lazy-gravity 0.9.2 → 0.11.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/bin/commands/doctor.js +45 -7
- package/dist/bot/index.js +401 -41
- package/dist/bot/telegramMessageHandler.js +1 -0
- package/dist/commands/chatCommandHandler.js +43 -3
- package/dist/commands/registerSlashCommands.js +13 -1
- package/dist/events/interactionCreateHandler.js +456 -27
- package/dist/events/messageCreateHandler.js +66 -7
- package/dist/handlers/__tests__/fileChangeButtonAction.test.js +85 -0
- package/dist/handlers/approvalButtonAction.js +2 -1
- package/dist/handlers/errorPopupButtonAction.js +2 -1
- package/dist/handlers/fileChangeButtonAction.js +57 -0
- package/dist/handlers/genericActionButtonAction.js +72 -0
- package/dist/handlers/planningButtonAction.js +126 -23
- package/dist/handlers/planningModalSubmitAction.js +38 -0
- package/dist/handlers/questionSelectAction.js +70 -0
- package/dist/handlers/questionSkipAction.js +68 -0
- package/dist/handlers/runCommandButtonAction.js +2 -1
- package/dist/platform/discord/discordResponseRenderer.js +164 -0
- package/dist/platform/discord/wrappers.js +76 -0
- package/dist/services/approvalDetector.js +110 -35
- package/dist/services/artifactService.js +103 -37
- package/dist/services/assistantDomExtractor.js +194 -3
- package/dist/services/cdpBridgeManager.js +149 -8
- package/dist/services/cdpConnectionPool.js +22 -2
- package/dist/services/cdpService.js +134 -15
- package/dist/services/chatSessionService.js +147 -40
- package/dist/services/errorPopupDetector.js +23 -11
- package/dist/services/notificationSender.js +80 -3
- package/dist/services/planningDetector.js +69 -25
- package/dist/services/promptDispatcher.js +27 -1
- package/dist/services/questionDetector.js +428 -0
- package/dist/services/responseMonitor.js +45 -3
- package/dist/services/runCommandDetector.js +14 -7
- package/dist/ui/artifactsUi.js +4 -3
- package/dist/utils/consecutiveEmptyPollGate.js +21 -0
- package/dist/utils/fileOpenCache.js +29 -0
- package/dist/utils/htmlToDiscordMarkdown.js +5 -2
- package/dist/utils/pathUtils.js +12 -0
- package/dist/utils/projectResolver.js +10 -0
- package/dist/utils/questionActionUtils.js +47 -0
- package/package.json +1 -1
package/dist/bot/index.js
CHANGED
|
@@ -46,6 +46,9 @@ const logger_1 = require("../utils/logger");
|
|
|
46
46
|
const logBuffer_1 = require("../utils/logBuffer");
|
|
47
47
|
const discord_js_1 = require("discord.js");
|
|
48
48
|
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
49
|
+
const fs_1 = __importDefault(require("fs"));
|
|
50
|
+
const child_process_1 = require("child_process");
|
|
51
|
+
const path_1 = __importDefault(require("path"));
|
|
49
52
|
const wrappers_1 = require("../platform/discord/wrappers");
|
|
50
53
|
const config_1 = require("../utils/config");
|
|
51
54
|
const slashCommandHandler_1 = require("../commands/slashCommandHandler");
|
|
@@ -72,10 +75,12 @@ const chatSessionService_1 = require("../services/chatSessionService");
|
|
|
72
75
|
const responseMonitor_1 = require("../services/responseMonitor");
|
|
73
76
|
const antigravityLauncher_1 = require("../services/antigravityLauncher");
|
|
74
77
|
const pathUtils_1 = require("../utils/pathUtils");
|
|
78
|
+
const fileOpenCache_1 = require("../utils/fileOpenCache");
|
|
75
79
|
const promptDispatcher_1 = require("../services/promptDispatcher");
|
|
76
80
|
const cdpBridgeManager_1 = require("../services/cdpBridgeManager");
|
|
77
81
|
const streamMessageFormatter_1 = require("../utils/streamMessageFormatter");
|
|
78
82
|
const discordFormatter_1 = require("../utils/discordFormatter");
|
|
83
|
+
const discordResponseRenderer_1 = require("../platform/discord/discordResponseRenderer");
|
|
79
84
|
const processLogBuffer_1 = require("../utils/processLogBuffer");
|
|
80
85
|
const imageHandler_1 = require("../utils/imageHandler");
|
|
81
86
|
const modeUi_1 = require("../ui/modeUi");
|
|
@@ -106,8 +111,11 @@ const planningButtonAction_1 = require("../handlers/planningButtonAction");
|
|
|
106
111
|
const errorPopupButtonAction_1 = require("../handlers/errorPopupButtonAction");
|
|
107
112
|
const runCommandButtonAction_1 = require("../handlers/runCommandButtonAction");
|
|
108
113
|
const modelButtonAction_1 = require("../handlers/modelButtonAction");
|
|
109
|
-
const
|
|
114
|
+
const questionSelectAction_1 = require("../handlers/questionSelectAction");
|
|
110
115
|
const templateButtonAction_1 = require("../handlers/templateButtonAction");
|
|
116
|
+
const fileChangeButtonAction_1 = require("../handlers/fileChangeButtonAction");
|
|
117
|
+
const autoAcceptButtonAction_1 = require("../handlers/autoAcceptButtonAction");
|
|
118
|
+
const genericActionButtonAction_1 = require("../handlers/genericActionButtonAction");
|
|
111
119
|
const modeSelectAction_1 = require("../handlers/modeSelectAction");
|
|
112
120
|
const accountSelectAction_1 = require("../handlers/accountSelectAction");
|
|
113
121
|
const telegramStartupTarget_1 = require("./telegramStartupTarget");
|
|
@@ -172,8 +180,9 @@ function createSerialTaskQueueForTest(queueName, traceId) {
|
|
|
172
180
|
return queue;
|
|
173
181
|
};
|
|
174
182
|
}
|
|
183
|
+
// Shared fileOpenCache is imported from utils/fileOpenCache
|
|
175
184
|
/**
|
|
176
|
-
* Send a
|
|
185
|
+
* Send a user's prompt to Antigravity and monitor generation.
|
|
177
186
|
*
|
|
178
187
|
* Message strategy:
|
|
179
188
|
* - Send new messages per phase instead of editing, to preserve history
|
|
@@ -182,11 +191,15 @@ function createSerialTaskQueueForTest(queueName, traceId) {
|
|
|
182
191
|
async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService, modelService, inboundImages = [], options) {
|
|
183
192
|
// Completion signal — called exactly once when the entire prompt lifecycle ends
|
|
184
193
|
let completionSignaled = false;
|
|
194
|
+
let onApprovalRef = null;
|
|
185
195
|
const signalCompletion = (exitPath) => {
|
|
186
196
|
if (completionSignaled)
|
|
187
197
|
return;
|
|
188
198
|
completionSignaled = true;
|
|
189
199
|
logger_1.logger.debug(`[sendPrompt:${message.channelId}] signalCompletion via ${exitPath}`);
|
|
200
|
+
if (onApprovalRef) {
|
|
201
|
+
cdp.off('approval_required', onApprovalRef);
|
|
202
|
+
}
|
|
190
203
|
options?.onFullCompletion?.();
|
|
191
204
|
};
|
|
192
205
|
// Resolve output format once at the start (no mid-response switches)
|
|
@@ -408,16 +421,20 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
408
421
|
return;
|
|
409
422
|
lastLiveResponseKey = renderKey;
|
|
410
423
|
for (let i = 0; i < plainChunks.length; i++) {
|
|
424
|
+
const messageOpts = { content: plainChunks[i] };
|
|
425
|
+
if (i === plainChunks.length - 1 && opts?.components?.length) {
|
|
426
|
+
messageOpts.components = opts.components;
|
|
427
|
+
}
|
|
411
428
|
if (!liveResponseMessages[i]) {
|
|
412
|
-
liveResponseMessages[i] = await channel.send(
|
|
429
|
+
liveResponseMessages[i] = await channel.send(messageOpts).catch((error) => {
|
|
413
430
|
logDeliveryError('liveResponse/plain/send', error);
|
|
414
431
|
return null;
|
|
415
432
|
});
|
|
416
433
|
continue;
|
|
417
434
|
}
|
|
418
|
-
await liveResponseMessages[i].edit(
|
|
435
|
+
await liveResponseMessages[i].edit(messageOpts).catch(async (error) => {
|
|
419
436
|
logDeliveryError('liveResponse/plain/edit', error);
|
|
420
|
-
liveResponseMessages[i] = await channel.send(
|
|
437
|
+
liveResponseMessages[i] = await channel.send(messageOpts).catch((sendError) => {
|
|
421
438
|
logDeliveryError('liveResponse/plain/resend', sendError);
|
|
422
439
|
return null;
|
|
423
440
|
});
|
|
@@ -445,15 +462,23 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
445
462
|
.setFooter({ text: footerText })
|
|
446
463
|
.setTimestamp();
|
|
447
464
|
if (!liveResponseMessages[i]) {
|
|
448
|
-
|
|
465
|
+
const messageOpts = { embeds: [embed] };
|
|
466
|
+
if (i === descriptions.length - 1 && opts?.components?.length) {
|
|
467
|
+
messageOpts.components = opts.components;
|
|
468
|
+
}
|
|
469
|
+
liveResponseMessages[i] = await channel.send(messageOpts).catch((error) => {
|
|
449
470
|
logDeliveryError('liveResponse/embed/send', error);
|
|
450
471
|
return null;
|
|
451
472
|
});
|
|
452
473
|
continue;
|
|
453
474
|
}
|
|
454
|
-
|
|
475
|
+
const messageOpts = { embeds: [embed] };
|
|
476
|
+
if (i === descriptions.length - 1 && opts?.components?.length) {
|
|
477
|
+
messageOpts.components = opts.components;
|
|
478
|
+
}
|
|
479
|
+
await liveResponseMessages[i].edit(messageOpts).catch(async (error) => {
|
|
455
480
|
logDeliveryError('liveResponse/embed/edit', error);
|
|
456
|
-
liveResponseMessages[i] = await channel.send(
|
|
481
|
+
liveResponseMessages[i] = await channel.send(messageOpts).catch((sendError) => {
|
|
457
482
|
logDeliveryError('liveResponse/embed/resend', sendError);
|
|
458
483
|
return null;
|
|
459
484
|
});
|
|
@@ -544,16 +569,18 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
544
569
|
try {
|
|
545
570
|
const baseline = await (0, responseMonitor_1.captureResponseMonitorBaseline)(cdp);
|
|
546
571
|
logger_1.logger.prompt(prompt);
|
|
547
|
-
let injectResult;
|
|
548
|
-
if (
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
572
|
+
let injectResult = { ok: true };
|
|
573
|
+
if (!options?.resumeOnly) {
|
|
574
|
+
if (inboundImages.length > 0) {
|
|
575
|
+
injectResult = await cdp.injectMessageWithImageFiles(prompt, inboundImages.map((image) => image.localPath));
|
|
576
|
+
if (!injectResult.ok) {
|
|
577
|
+
await sendEmbed((0, i18n_1.t)('🖼️ Attached image fallback'), (0, i18n_1.t)('Failed to attach image directly, resending via URL reference.'), PHASE_COLORS.thinking);
|
|
578
|
+
injectResult = await cdp.injectMessage((0, imageHandler_1.buildPromptWithAttachmentUrls)(prompt, inboundImages));
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
injectResult = await cdp.injectMessage(prompt);
|
|
553
583
|
}
|
|
554
|
-
}
|
|
555
|
-
else {
|
|
556
|
-
injectResult = await cdp.injectMessage(prompt);
|
|
557
584
|
}
|
|
558
585
|
if (!injectResult.ok) {
|
|
559
586
|
isFinalized = true;
|
|
@@ -564,6 +591,8 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
564
591
|
return;
|
|
565
592
|
}
|
|
566
593
|
const startTime = Date.now();
|
|
594
|
+
let earlyConvIdResolved = false;
|
|
595
|
+
let earlyConvIdInFlight = false;
|
|
567
596
|
await upsertLiveActivityEmbeds(`${PHASE_ICONS.thinking} Process Log`, '', PHASE_COLORS.thinking, (0, i18n_1.t)('⏱️ Elapsed: 0s | Process log'), { source: 'initial' });
|
|
568
597
|
const monitor = new responseMonitor_1.ResponseMonitor({
|
|
569
598
|
cdpService: cdp,
|
|
@@ -590,6 +619,30 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
590
619
|
expectedVersion: activityVersion,
|
|
591
620
|
skipWhenFinalized: true,
|
|
592
621
|
}).catch(() => { });
|
|
622
|
+
// Try to resolve conversation_id early if not already bound
|
|
623
|
+
const { artifactService, chatSessionRepo, chatSessionService } = options || {};
|
|
624
|
+
if (!earlyConvIdResolved && !earlyConvIdInFlight && artifactService && chatSessionRepo && chatSessionService) {
|
|
625
|
+
earlyConvIdInFlight = true;
|
|
626
|
+
chatSessionService.getCurrentSessionInfo(cdp)
|
|
627
|
+
.then((sessionInfo) => {
|
|
628
|
+
if (sessionInfo && sessionInfo.title && sessionInfo.title !== (0, i18n_1.t)('(Untitled)')) {
|
|
629
|
+
const session = chatSessionRepo.findByChannelId(message.channelId);
|
|
630
|
+
const workspaceDirName = (session
|
|
631
|
+
? bridge.pool.extractProjectName(session.workspacePath)
|
|
632
|
+
: cdp.getCurrentWorkspaceName()) ?? undefined;
|
|
633
|
+
const convId = artifactService.findConversationByTitle(sessionInfo.title, workspaceDirName);
|
|
634
|
+
if (convId) {
|
|
635
|
+
chatSessionRepo.setConversationId(message.channelId, convId);
|
|
636
|
+
earlyConvIdResolved = true;
|
|
637
|
+
logger_1.logger.debug(`[EarlyBinding] Saved conversation_id: "${convId}" for channel: ${message.channelId}`);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
})
|
|
641
|
+
.catch(() => { })
|
|
642
|
+
.finally(() => {
|
|
643
|
+
earlyConvIdInFlight = false;
|
|
644
|
+
});
|
|
645
|
+
}
|
|
593
646
|
},
|
|
594
647
|
onProgress: (text) => {
|
|
595
648
|
if (isFinalized)
|
|
@@ -600,7 +653,7 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
600
653
|
lastProgressText = separated.output;
|
|
601
654
|
}
|
|
602
655
|
},
|
|
603
|
-
onComplete: async (finalText) => {
|
|
656
|
+
onComplete: async (finalText, citedFiles, fileChanges) => {
|
|
604
657
|
isFinalized = true;
|
|
605
658
|
try {
|
|
606
659
|
// If the user explicitly pressed /stop, skip output display entirely
|
|
@@ -680,18 +733,15 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
680
733
|
});
|
|
681
734
|
liveResponseUpdateVersion += 1;
|
|
682
735
|
const responseVersion = liveResponseUpdateVersion;
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
await upsertLiveResponseEmbeds(`${PHASE_ICONS.complete} Complete`, (0, i18n_1.t)('Failed to extract response. Use `/screenshot` to verify.'), PHASE_COLORS.complete, (0, i18n_1.t)(`⏱️ Time: ${elapsed}s | Complete`), {
|
|
691
|
-
source: 'complete',
|
|
692
|
-
expectedVersion: responseVersion,
|
|
693
|
-
});
|
|
736
|
+
const components = [];
|
|
737
|
+
if (!citedFiles)
|
|
738
|
+
citedFiles = [];
|
|
739
|
+
// Only pause when newly created conversation folders and files need to flush to disk
|
|
740
|
+
const existingConvId = options?.chatSessionRepo?.findByChannelId(message.channelId)?.conversationId;
|
|
741
|
+
if (!existingConvId) {
|
|
742
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
694
743
|
}
|
|
744
|
+
let activeConversationId = undefined;
|
|
695
745
|
if (options && message.guild) {
|
|
696
746
|
try {
|
|
697
747
|
const sessionInfo = await options.chatSessionService.getCurrentSessionInfo(cdp);
|
|
@@ -711,9 +761,15 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
711
761
|
}
|
|
712
762
|
// Persist conversation_id for artifact picker resolution
|
|
713
763
|
if (options.artifactService) {
|
|
714
|
-
const
|
|
764
|
+
const session = options.chatSessionRepo.findByChannelId(message.channelId);
|
|
765
|
+
let workspaceDirName;
|
|
766
|
+
if (session && session.workspacePath) {
|
|
767
|
+
workspaceDirName = bridge.pool.extractProjectName(session.workspacePath);
|
|
768
|
+
}
|
|
769
|
+
const convId = options.artifactService.findConversationByTitle(sessionInfo.title, workspaceDirName);
|
|
715
770
|
if (convId) {
|
|
716
771
|
options.chatSessionRepo.setConversationId(message.channelId, convId);
|
|
772
|
+
activeConversationId = convId;
|
|
717
773
|
}
|
|
718
774
|
}
|
|
719
775
|
}
|
|
@@ -722,6 +778,201 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
722
778
|
logger_1.logger.error('[Rename] Failed to get title from Antigravity and rename:', e);
|
|
723
779
|
}
|
|
724
780
|
}
|
|
781
|
+
const classifiedForFiles = monitor.getLastClassified();
|
|
782
|
+
if (classifiedForFiles?.fileChanges && classifiedForFiles.fileChanges.length > 0) {
|
|
783
|
+
for (const fc of classifiedForFiles.fileChanges) {
|
|
784
|
+
if (!citedFiles.includes(fc.path)) {
|
|
785
|
+
citedFiles.push(fc.path);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
if (!activeConversationId && options?.chatSessionRepo) {
|
|
790
|
+
activeConversationId = options.chatSessionRepo.findByChannelId(message.channelId)?.conversationId ?? undefined;
|
|
791
|
+
}
|
|
792
|
+
if (activeConversationId && options?.artifactService) {
|
|
793
|
+
const artifacts = options.artifactService.listArtifacts(activeConversationId);
|
|
794
|
+
const planArt = artifacts.find(art => art.artifactType === 'ARTIFACT_TYPE_IMPLEMENTATION_PLAN' ||
|
|
795
|
+
art.filename.toLowerCase() === 'implementation_plan.md');
|
|
796
|
+
let planTime = 0;
|
|
797
|
+
if (planArt) {
|
|
798
|
+
try {
|
|
799
|
+
planTime = fs_1.default.statSync(planArt.absolutePath).mtimeMs;
|
|
800
|
+
}
|
|
801
|
+
catch { /* ignore */ }
|
|
802
|
+
}
|
|
803
|
+
for (const art of artifacts) {
|
|
804
|
+
const nameWithExt = art.filename;
|
|
805
|
+
const nameWithoutExt = art.filename.replace(/\.[^/.]+$/, "");
|
|
806
|
+
const regex = new RegExp(`\\b${nameWithoutExt.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')}\\b`, 'i');
|
|
807
|
+
const mentionsArtifact = finalOutputText.includes(nameWithExt) || finalOutputText.includes(`\`${nameWithoutExt}\``) || regex.test(finalOutputText);
|
|
808
|
+
const isTask = art.artifactType === 'ARTIFACT_TYPE_TASK' || nameWithExt.toLowerCase() === 'task.md';
|
|
809
|
+
const isWalkthrough = art.artifactType === 'ARTIFACT_TYPE_WALKTHROUGH' || nameWithExt.toLowerCase() === 'walkthrough.md';
|
|
810
|
+
let isSpecialArtifact = false;
|
|
811
|
+
if (isTask || isWalkthrough) {
|
|
812
|
+
let artTime = 0;
|
|
813
|
+
try {
|
|
814
|
+
artTime = fs_1.default.statSync(art.absolutePath).mtimeMs;
|
|
815
|
+
}
|
|
816
|
+
catch { /* ignore */ }
|
|
817
|
+
if (artTime > planTime) {
|
|
818
|
+
isSpecialArtifact = true;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
if ((mentionsArtifact || isSpecialArtifact) && !citedFiles.includes(nameWithExt)) {
|
|
822
|
+
citedFiles.push(nameWithExt);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
if (citedFiles && citedFiles.length > 0) {
|
|
827
|
+
// Strip trailing punctuation and deduplicate
|
|
828
|
+
let uniqueFiles = Array.from(new Set(citedFiles.map(f => {
|
|
829
|
+
let clean = f.trim();
|
|
830
|
+
while (clean.match(/[.,;:!?]$/)) {
|
|
831
|
+
clean = clean.slice(0, -1);
|
|
832
|
+
}
|
|
833
|
+
return clean;
|
|
834
|
+
})));
|
|
835
|
+
// Filter out obviously bad paths
|
|
836
|
+
uniqueFiles = uniqueFiles.filter(f => f.length > 0 && f !== 'unknown');
|
|
837
|
+
const row = new discord_js_1.ActionRowBuilder();
|
|
838
|
+
// Max 5 buttons per row in Discord
|
|
839
|
+
for (let i = 0; i < Math.min(uniqueFiles.length, 5); i++) {
|
|
840
|
+
let fileUrl = uniqueFiles[i];
|
|
841
|
+
let isArtifactMatch = false;
|
|
842
|
+
let artifactDisplayName = fileUrl;
|
|
843
|
+
if (activeConversationId && options?.artifactService) {
|
|
844
|
+
const artifacts = options.artifactService.listArtifacts(activeConversationId);
|
|
845
|
+
const rawName = fileUrl.replace(/^file:\/\/\//, '');
|
|
846
|
+
const matched = artifacts.find(a => a.filename.toLowerCase() === fileUrl.toLowerCase() ||
|
|
847
|
+
a.filename.toLowerCase() === rawName.toLowerCase());
|
|
848
|
+
if (matched) {
|
|
849
|
+
isArtifactMatch = true;
|
|
850
|
+
fileUrl = `file:///${matched.absolutePath.replace(/\\/g, '/')}`;
|
|
851
|
+
artifactDisplayName = matched.filename;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
const wsPath = cdp.getCurrentWorkspacePath();
|
|
855
|
+
if (!wsPath) {
|
|
856
|
+
continue;
|
|
857
|
+
}
|
|
858
|
+
if (!isArtifactMatch) {
|
|
859
|
+
if (!fileUrl.startsWith('file:///') && !path_1.default.isAbsolute(fileUrl)) {
|
|
860
|
+
fileUrl = `file:///${path_1.default.resolve(wsPath, fileUrl).replace(/\\/g, '/')}`;
|
|
861
|
+
}
|
|
862
|
+
let fsPath = fileUrl.replace(/^file:\/\/\//, '');
|
|
863
|
+
if (path_1.default.sep === '/' && !fsPath.startsWith('/')) {
|
|
864
|
+
fsPath = '/' + fsPath;
|
|
865
|
+
}
|
|
866
|
+
else if (process.platform === 'win32' && fsPath.startsWith('/')) {
|
|
867
|
+
fsPath = fsPath.substring(1);
|
|
868
|
+
}
|
|
869
|
+
const relative = path_1.default.relative(wsPath, fsPath);
|
|
870
|
+
const isArtifact = fsPath.includes('.gemini') && fsPath.includes('antigravity') && fsPath.includes('brain');
|
|
871
|
+
if (!isArtifact && (relative.startsWith('..') || path_1.default.isAbsolute(relative))) {
|
|
872
|
+
continue;
|
|
873
|
+
}
|
|
874
|
+
if (!fs_1.default.existsSync(fsPath)) {
|
|
875
|
+
continue;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
let displayName = fileUrl;
|
|
879
|
+
if (isArtifactMatch) {
|
|
880
|
+
displayName = artifactDisplayName;
|
|
881
|
+
}
|
|
882
|
+
else if (displayName.startsWith('file:///')) {
|
|
883
|
+
const parts = displayName.split('/');
|
|
884
|
+
displayName = parts[parts.length - 1];
|
|
885
|
+
}
|
|
886
|
+
const hashId = Math.random().toString(36).substring(2, 10);
|
|
887
|
+
fileOpenCache_1.fileOpenCache.set(hashId, fileUrl);
|
|
888
|
+
let customId = `file_open:cache:${hashId}`;
|
|
889
|
+
if (isArtifactMatch && activeConversationId && displayName) {
|
|
890
|
+
const artId = `file_open:art:${activeConversationId}:${displayName}`;
|
|
891
|
+
if (artId.length < 100) {
|
|
892
|
+
customId = artId;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
else if (wsPath) {
|
|
896
|
+
let fsPath = fileUrl.replace(/^file:\/\/\//, '');
|
|
897
|
+
if (path_1.default.sep === '/' && !fsPath.startsWith('/')) {
|
|
898
|
+
fsPath = '/' + fsPath;
|
|
899
|
+
}
|
|
900
|
+
else if (process.platform === 'win32' && fsPath.startsWith('/')) {
|
|
901
|
+
fsPath = fsPath.substring(1);
|
|
902
|
+
}
|
|
903
|
+
const resolvedFsPath = path_1.default.resolve(fsPath);
|
|
904
|
+
const relative = path_1.default.relative(wsPath, resolvedFsPath);
|
|
905
|
+
if (!relative.startsWith('..') && !path_1.default.isAbsolute(relative)) {
|
|
906
|
+
const relSlash = relative.replace(/\\/g, '/');
|
|
907
|
+
const relId = `file_open:rel:${relSlash}`;
|
|
908
|
+
if (relId.length < 100) {
|
|
909
|
+
customId = relId;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
row.addComponents(new discord_js_1.ButtonBuilder()
|
|
914
|
+
.setCustomId(customId)
|
|
915
|
+
.setLabel(isArtifactMatch ? `Review ${displayName.substring(0, 15)}` : `Open ${displayName.substring(0, 20)}`)
|
|
916
|
+
.setStyle(isArtifactMatch ? discord_js_1.ButtonStyle.Success : discord_js_1.ButtonStyle.Primary));
|
|
917
|
+
}
|
|
918
|
+
if (row.components.length > 0) {
|
|
919
|
+
components.push(row);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
if (fileChanges && fileChanges.length > 0) {
|
|
923
|
+
// The extracted text is the toolbar title, e.g. "1 File With Changes"
|
|
924
|
+
const widgetTitle = fileChanges[fileChanges.length - 1] || 'Files With Changes';
|
|
925
|
+
const fileChangesRow = new discord_js_1.ActionRowBuilder().addComponents(new discord_js_1.ButtonBuilder()
|
|
926
|
+
.setCustomId((0, cdpBridgeManager_1.buildFileChangeCustomId)('reject', cdp.getCurrentWorkspaceName() || 'unknown', message.channelId))
|
|
927
|
+
.setLabel(`Reject all (${widgetTitle})`)
|
|
928
|
+
.setStyle(discord_js_1.ButtonStyle.Danger), new discord_js_1.ButtonBuilder()
|
|
929
|
+
.setCustomId((0, cdpBridgeManager_1.buildFileChangeCustomId)('accept', cdp.getCurrentWorkspaceName() || 'unknown', message.channelId))
|
|
930
|
+
.setLabel('Accept all')
|
|
931
|
+
.setStyle(discord_js_1.ButtonStyle.Success));
|
|
932
|
+
components.push(fileChangesRow);
|
|
933
|
+
}
|
|
934
|
+
const classified = monitor.getLastClassified();
|
|
935
|
+
if (options?.extractionMode === 'structured' && classified && outputFormat !== 'plain') {
|
|
936
|
+
const messageOptions = (0, discordResponseRenderer_1.renderDiscordResponse)(classified, {
|
|
937
|
+
projectName: cdp.getCurrentWorkspaceName() || 'unknown',
|
|
938
|
+
channelId: message.channelId
|
|
939
|
+
});
|
|
940
|
+
for (const msg of liveResponseMessages) {
|
|
941
|
+
if (msg)
|
|
942
|
+
await msg.delete().catch(() => { });
|
|
943
|
+
}
|
|
944
|
+
liveResponseMessages.length = 0;
|
|
945
|
+
if (components.length > 0) {
|
|
946
|
+
if (!messageOptions.components)
|
|
947
|
+
messageOptions.components = [];
|
|
948
|
+
messageOptions.components = [...(messageOptions.components || []), ...components];
|
|
949
|
+
}
|
|
950
|
+
if (messageOptions.embeds && messageOptions.embeds.length > 0) {
|
|
951
|
+
const lastEmbed = messageOptions.embeds[messageOptions.embeds.length - 1];
|
|
952
|
+
if (lastEmbed && typeof lastEmbed.setFooter === 'function') {
|
|
953
|
+
lastEmbed.setFooter({ text: (0, i18n_1.t)(`⏱️ Time: ${elapsed}s | Complete`) });
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
if (channel) {
|
|
957
|
+
await channel.send(messageOptions).catch((error) => {
|
|
958
|
+
logDeliveryError('renderDiscordResponse/send', error);
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
else if (finalOutputText && finalOutputText.trim().length > 0) {
|
|
963
|
+
await upsertLiveResponseEmbeds(`${PHASE_ICONS.complete} Final Output`, finalOutputText, PHASE_COLORS.complete, (0, i18n_1.t)(`⏱️ Time: ${elapsed}s | Complete`), {
|
|
964
|
+
source: 'complete',
|
|
965
|
+
expectedVersion: responseVersion,
|
|
966
|
+
components: components.length > 0 ? components : undefined,
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
else {
|
|
970
|
+
await upsertLiveResponseEmbeds(`${PHASE_ICONS.complete} Complete`, (0, i18n_1.t)('Failed to extract response. Use `/screenshot` to verify.'), PHASE_COLORS.complete, (0, i18n_1.t)(`⏱️ Time: ${elapsed}s | Complete`), {
|
|
971
|
+
source: 'complete',
|
|
972
|
+
expectedVersion: responseVersion,
|
|
973
|
+
components: components.length > 0 ? components : undefined,
|
|
974
|
+
});
|
|
975
|
+
}
|
|
725
976
|
await sendGeneratedImages(finalOutputText || '');
|
|
726
977
|
await clearWatchingReaction();
|
|
727
978
|
await message.react(finalOutputText && finalOutputText.trim().length > 0 ? '✅' : '⚠️').catch(() => { });
|
|
@@ -770,6 +1021,32 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
770
1021
|
}
|
|
771
1022
|
},
|
|
772
1023
|
});
|
|
1024
|
+
onApprovalRef = async () => {
|
|
1025
|
+
if (isFinalized)
|
|
1026
|
+
return;
|
|
1027
|
+
const textToUse = lastProgressText || monitor.getLastText() || '';
|
|
1028
|
+
const separated = (0, discordFormatter_1.splitOutputAndLogs)(textToUse);
|
|
1029
|
+
const outputText = separated.output || textToUse;
|
|
1030
|
+
if (outputText && outputText.trim().length > 0) {
|
|
1031
|
+
liveResponseUpdateVersion += 1;
|
|
1032
|
+
const responseVersion = liveResponseUpdateVersion;
|
|
1033
|
+
const elapsed = Math.round((Date.now() - startTime) / 1000);
|
|
1034
|
+
await upsertLiveResponseEmbeds((0, i18n_1.t)('Response'), outputText, PHASE_COLORS.thinking, (0, i18n_1.t)(`⏱️ Time: ${elapsed}s | Awaiting Approval`), {
|
|
1035
|
+
source: 'approval-pause',
|
|
1036
|
+
expectedVersion: responseVersion,
|
|
1037
|
+
skipWhenFinalized: true,
|
|
1038
|
+
}).catch(() => { });
|
|
1039
|
+
}
|
|
1040
|
+
};
|
|
1041
|
+
cdp.on('approval_required', onApprovalRef);
|
|
1042
|
+
if (options?.onMonitorCreated) {
|
|
1043
|
+
options.onMonitorCreated({
|
|
1044
|
+
stop: async () => {
|
|
1045
|
+
isFinalized = true;
|
|
1046
|
+
await monitor.stop();
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
773
1050
|
await monitor.start();
|
|
774
1051
|
// 1-second elapsed timer — updates footer independently of process log events
|
|
775
1052
|
const elapsedTimer = setInterval(() => {
|
|
@@ -834,6 +1111,8 @@ const startBot = async (cliLogLevel) => {
|
|
|
834
1111
|
.filter((account) => typeof account.userDataDir === 'string' && account.userDataDir.trim().length > 0)
|
|
835
1112
|
.map((account) => [account.name, account.userDataDir.trim()]));
|
|
836
1113
|
const bridge = (0, cdpBridgeManager_1.initCdpBridge)(config.autoApproveFileEdits, accountPorts, accountUserDataDirs);
|
|
1114
|
+
bridge.chatSessionRepo = chatSessionRepo;
|
|
1115
|
+
bridge.artifactService = artifactService;
|
|
837
1116
|
// Initialize CDP-dependent services (constructor CDP dependency removed)
|
|
838
1117
|
const chatSessionService = new chatSessionService_1.ChatSessionService();
|
|
839
1118
|
const titleGenerator = new titleGeneratorService_1.TitleGeneratorService();
|
|
@@ -884,7 +1163,20 @@ const startBot = async (cliLogLevel) => {
|
|
|
884
1163
|
accountPrefRepo,
|
|
885
1164
|
accounts: config.antigravityAccounts,
|
|
886
1165
|
});
|
|
887
|
-
await (0, antigravityLauncher_1.startAntigravity)(accountPorts[accountName] ?? 9222);
|
|
1166
|
+
const status = await (0, antigravityLauncher_1.startAntigravity)(accountPorts[accountName] ?? 9222);
|
|
1167
|
+
if (status === 'started') {
|
|
1168
|
+
const cdp = new cdpService_1.CdpService({ portsToScan: [accountPorts[accountName] ?? 9222] });
|
|
1169
|
+
try {
|
|
1170
|
+
await cdp.connect();
|
|
1171
|
+
await cdp.openChatPanel();
|
|
1172
|
+
}
|
|
1173
|
+
catch (e) {
|
|
1174
|
+
// ignore
|
|
1175
|
+
}
|
|
1176
|
+
finally {
|
|
1177
|
+
await cdp.disconnect().catch(() => { });
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
888
1180
|
});
|
|
889
1181
|
const chatHandler = new chatCommandHandler_1.ChatCommandHandler(chatSessionService, chatSessionRepo, workspaceBindingRepo, channelManager, workspaceService, bridge.pool, (channelId, userId) => (0, accountUtils_1.resolveScopedAccountName)({
|
|
890
1182
|
channelId,
|
|
@@ -977,6 +1269,7 @@ const startBot = async (cliLogLevel) => {
|
|
|
977
1269
|
wsHandler,
|
|
978
1270
|
chatHandler,
|
|
979
1271
|
client,
|
|
1272
|
+
promptDispatcher,
|
|
980
1273
|
sendModeUI: modeUi_1.sendModeUI,
|
|
981
1274
|
sendModelsUI: modelsUi_1.sendModelsUI,
|
|
982
1275
|
sendAutoAcceptUI: autoAcceptUi_1.sendAutoAcceptUI,
|
|
@@ -984,6 +1277,7 @@ const startBot = async (cliLogLevel) => {
|
|
|
984
1277
|
parseApprovalCustomId: cdpBridgeManager_1.parseApprovalCustomId,
|
|
985
1278
|
parseErrorPopupCustomId: cdpBridgeManager_1.parseErrorPopupCustomId,
|
|
986
1279
|
parsePlanningCustomId: cdpBridgeManager_1.parsePlanningCustomId,
|
|
1280
|
+
parseFileChangeCustomId: cdpBridgeManager_1.parseFileChangeCustomId,
|
|
987
1281
|
parseRunCommandCustomId: cdpBridgeManager_1.parseRunCommandCustomId,
|
|
988
1282
|
joinHandler,
|
|
989
1283
|
userPrefRepo,
|
|
@@ -993,8 +1287,10 @@ const startBot = async (cliLogLevel) => {
|
|
|
993
1287
|
chatSessionService,
|
|
994
1288
|
artifactThreadRepo,
|
|
995
1289
|
artifactService,
|
|
1290
|
+
channelManager,
|
|
1291
|
+
titleGenerator,
|
|
996
1292
|
antigravityAccounts: config.antigravityAccounts,
|
|
997
|
-
handleSlashInteraction: async (interaction, handler, bridgeArg, wsHandlerArg, chatHandlerArg, cleanupHandlerArg, modeServiceArg, modelServiceArg, autoAcceptServiceArg, clientArg, accountPrefRepoArg, channelPrefRepoArg, antigravityAccountsArg) => handleSlashInteraction(interaction, handler, bridgeArg, wsHandlerArg, chatHandlerArg, cleanupHandlerArg, chatSessionService, modeServiceArg, modelServiceArg, autoAcceptServiceArg, clientArg, promptDispatcher, templateRepo, joinHandler, userPrefRepo, accountPrefRepoArg, channelPrefRepoArg, antigravityAccountsArg,
|
|
1293
|
+
handleSlashInteraction: async (interaction, handler, bridgeArg, wsHandlerArg, chatHandlerArg, cleanupHandlerArg, modeServiceArg, modelServiceArg, autoAcceptServiceArg, clientArg, accountPrefRepoArg, channelPrefRepoArg, antigravityAccountsArg, chatSessionRepoArg, scheduleServiceArg) => handleSlashInteraction(interaction, handler, bridgeArg, wsHandlerArg, chatHandlerArg, cleanupHandlerArg, chatSessionService, modeServiceArg, modelServiceArg, autoAcceptServiceArg, clientArg, promptDispatcher, templateRepo, joinHandler, userPrefRepo, accountPrefRepoArg, channelPrefRepoArg, antigravityAccountsArg, chatSessionRepoArg, artifactService, scheduleServiceArg),
|
|
998
1294
|
handleTemplateUse: async (interaction, templateId) => {
|
|
999
1295
|
const template = templateRepo.findById(templateId);
|
|
1000
1296
|
if (!template) {
|
|
@@ -1035,6 +1331,7 @@ const startBot = async (cliLogLevel) => {
|
|
|
1035
1331
|
(0, cdpBridgeManager_1.ensureErrorPopupDetector)(bridge, cdp, projectName, selectedAccount);
|
|
1036
1332
|
(0, cdpBridgeManager_1.ensurePlanningDetector)(bridge, cdp, projectName, selectedAccount);
|
|
1037
1333
|
(0, cdpBridgeManager_1.ensureRunCommandDetector)(bridge, cdp, projectName, selectedAccount);
|
|
1334
|
+
(0, cdpBridgeManager_1.ensureQuestionDetector)(bridge, cdp, projectName, selectedAccount);
|
|
1038
1335
|
}
|
|
1039
1336
|
catch (e) {
|
|
1040
1337
|
await interaction.followUp({
|
|
@@ -1184,10 +1481,12 @@ const startBot = async (cliLogLevel) => {
|
|
|
1184
1481
|
: binding.workspacePath;
|
|
1185
1482
|
},
|
|
1186
1483
|
});
|
|
1484
|
+
const questionSelectAction = (0, questionSelectAction_1.createQuestionSelectAction)({ bridge, wsHandler });
|
|
1187
1485
|
const telegramSelectHandler = (0, selectHandler_1.createPlatformSelectHandler)({
|
|
1188
1486
|
actions: [
|
|
1189
1487
|
modeSelectAction,
|
|
1190
1488
|
accountSelectAction,
|
|
1489
|
+
questionSelectAction,
|
|
1191
1490
|
],
|
|
1192
1491
|
});
|
|
1193
1492
|
// Composite handler that routes to the right handler
|
|
@@ -1206,7 +1505,9 @@ const startBot = async (cliLogLevel) => {
|
|
|
1206
1505
|
}, interaction);
|
|
1207
1506
|
return;
|
|
1208
1507
|
}
|
|
1209
|
-
if (interaction.customId === 'mode_select' ||
|
|
1508
|
+
if (interaction.customId === 'mode_select' ||
|
|
1509
|
+
interaction.customId === 'account_select' ||
|
|
1510
|
+
interaction.customId.startsWith('question_select_action')) {
|
|
1210
1511
|
await telegramSelectHandler(interaction);
|
|
1211
1512
|
return;
|
|
1212
1513
|
}
|
|
@@ -1221,10 +1522,10 @@ const startBot = async (cliLogLevel) => {
|
|
|
1221
1522
|
}
|
|
1222
1523
|
const telegramButtonHandler = (0, buttonHandler_1.createPlatformButtonHandler)({
|
|
1223
1524
|
actions: [
|
|
1224
|
-
(0, approvalButtonAction_1.createApprovalButtonAction)({ bridge }),
|
|
1225
|
-
(0, planningButtonAction_1.createPlanningButtonAction)({ bridge }),
|
|
1226
|
-
(0, errorPopupButtonAction_1.createErrorPopupButtonAction)({ bridge }),
|
|
1227
|
-
(0, runCommandButtonAction_1.createRunCommandButtonAction)({ bridge }),
|
|
1525
|
+
(0, approvalButtonAction_1.createApprovalButtonAction)({ bridge, wsHandler }),
|
|
1526
|
+
(0, planningButtonAction_1.createPlanningButtonAction)({ bridge, wsHandler }),
|
|
1527
|
+
(0, errorPopupButtonAction_1.createErrorPopupButtonAction)({ bridge, wsHandler }),
|
|
1528
|
+
(0, runCommandButtonAction_1.createRunCommandButtonAction)({ bridge, wsHandler }),
|
|
1228
1529
|
(0, modelButtonAction_1.createModelButtonAction)({
|
|
1229
1530
|
bridge,
|
|
1230
1531
|
fetchQuota: () => bridge.quota.fetchQuota(),
|
|
@@ -1262,6 +1563,8 @@ const startBot = async (cliLogLevel) => {
|
|
|
1262
1563
|
}),
|
|
1263
1564
|
(0, autoAcceptButtonAction_1.createAutoAcceptButtonAction)({ autoAcceptService: bridge.autoAccept }),
|
|
1264
1565
|
(0, templateButtonAction_1.createTemplateButtonAction)({ bridge, templateRepo }),
|
|
1566
|
+
(0, fileChangeButtonAction_1.createFileChangeButtonAction)({ bridge, wsHandler }),
|
|
1567
|
+
(0, genericActionButtonAction_1.createGenericActionButtonAction)({ bridge, wsHandler }),
|
|
1265
1568
|
],
|
|
1266
1569
|
});
|
|
1267
1570
|
const eventRouter = new eventRouter_1.EventRouter({ allowedUsers }, {
|
|
@@ -1382,7 +1685,7 @@ async function autoRenameChannel(message, chatSessionRepo, titleGenerator, chann
|
|
|
1382
1685
|
/**
|
|
1383
1686
|
* Handle Discord Interactions API slash commands
|
|
1384
1687
|
*/
|
|
1385
|
-
async function handleSlashInteraction(interaction, handler, bridge, wsHandler, chatHandler, cleanupHandler, chatSessionService, modeService, modelService, autoAcceptService, _client, promptDispatcher, templateRepo, joinHandler, userPrefRepo, accountPrefRepo, channelPrefRepo, antigravityAccounts = [{ name: 'default', cdpPort: 9222 }], chatSessionRepo, artifactService) {
|
|
1688
|
+
async function handleSlashInteraction(interaction, handler, bridge, wsHandler, chatHandler, cleanupHandler, chatSessionService, modeService, modelService, autoAcceptService, _client, promptDispatcher, templateRepo, joinHandler, userPrefRepo, accountPrefRepo, channelPrefRepo, antigravityAccounts = [{ name: 'default', cdpPort: 9222 }], chatSessionRepo, artifactService, scheduleService) {
|
|
1386
1689
|
const commandName = interaction.commandName;
|
|
1387
1690
|
const getAccountPort = (accountName) => {
|
|
1388
1691
|
const match = antigravityAccounts.find((account) => account.name === accountName);
|
|
@@ -1407,9 +1710,7 @@ async function handleSlashInteraction(interaction, handler, bridge, wsHandler, c
|
|
|
1407
1710
|
const projectName = bridge.pool.extractProjectName(workspacePath);
|
|
1408
1711
|
return bridge.pool.getConnected(projectName, resolveSelectedAccount());
|
|
1409
1712
|
}
|
|
1410
|
-
return
|
|
1411
|
-
? bridge.pool.getConnected(bridge.lastActiveWorkspace, resolveSelectedAccount())
|
|
1412
|
-
: null;
|
|
1713
|
+
return null;
|
|
1413
1714
|
})();
|
|
1414
1715
|
const ensureChannelCdp = async () => {
|
|
1415
1716
|
const existing = getChannelCdp();
|
|
@@ -1880,6 +2181,65 @@ async function handleSlashInteraction(interaction, handler, bridge, wsHandler, c
|
|
|
1880
2181
|
await interaction.editReply({ content: codeBlock });
|
|
1881
2182
|
break;
|
|
1882
2183
|
}
|
|
2184
|
+
case 'open': {
|
|
2185
|
+
const filepath = interaction.options.getString('filepath', true);
|
|
2186
|
+
let resolvedPath = null;
|
|
2187
|
+
// 1. Try to resolve as an artifact
|
|
2188
|
+
if (chatSessionRepo && artifactService) {
|
|
2189
|
+
const session = chatSessionRepo.findByChannelId(interaction.channelId);
|
|
2190
|
+
if (session && session.conversationId) {
|
|
2191
|
+
const possibleArtifact = artifactService.getArtifactPath(session.conversationId, filepath);
|
|
2192
|
+
if (fs_1.default.existsSync(possibleArtifact)) {
|
|
2193
|
+
resolvedPath = possibleArtifact;
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
// 2. Try to resolve against the workspace
|
|
2198
|
+
if (!resolvedPath) {
|
|
2199
|
+
const cdp = await ensureChannelCdp();
|
|
2200
|
+
if (cdp) {
|
|
2201
|
+
const wsPath = cdp.getCurrentWorkspacePath();
|
|
2202
|
+
if (wsPath) {
|
|
2203
|
+
let rawPath = filepath;
|
|
2204
|
+
if (filepath.startsWith('file:///')) {
|
|
2205
|
+
rawPath = filepath.replace('file:///', '');
|
|
2206
|
+
if (process.platform === 'win32' && rawPath.startsWith('/')) {
|
|
2207
|
+
rawPath = rawPath.substring(1);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
const candidatePath = path_1.default.isAbsolute(rawPath) ? rawPath : path_1.default.join(wsPath, rawPath);
|
|
2211
|
+
const relative = path_1.default.relative(wsPath, candidatePath);
|
|
2212
|
+
if (!relative.startsWith('..') && !path_1.default.isAbsolute(relative)) {
|
|
2213
|
+
if (fs_1.default.existsSync(candidatePath)) {
|
|
2214
|
+
resolvedPath = candidatePath;
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
if (!resolvedPath) {
|
|
2221
|
+
await interaction.editReply({
|
|
2222
|
+
content: '❌ Error: Cannot resolve file path. Ensure the file exists as an artifact or within the current workspace.'
|
|
2223
|
+
});
|
|
2224
|
+
break;
|
|
2225
|
+
}
|
|
2226
|
+
try {
|
|
2227
|
+
(0, child_process_1.execFile)((0, pathUtils_1.getAntigravityCliPath)(), [resolvedPath], (error) => {
|
|
2228
|
+
if (error) {
|
|
2229
|
+
logger_1.logger.error(`Failed to open file via CLI: ${error.message}`);
|
|
2230
|
+
interaction.editReply({ content: `❌ Error opening file via CLI.` }).catch(() => { });
|
|
2231
|
+
}
|
|
2232
|
+
else {
|
|
2233
|
+
interaction.editReply({ content: `✅ Opened file: **${path_1.default.basename(resolvedPath)}**` }).catch(() => { });
|
|
2234
|
+
}
|
|
2235
|
+
});
|
|
2236
|
+
}
|
|
2237
|
+
catch (e) {
|
|
2238
|
+
logger_1.logger.error(`Failed to open file: ${e.message}`);
|
|
2239
|
+
await interaction.editReply({ content: `❌ Error opening file.` });
|
|
2240
|
+
}
|
|
2241
|
+
break;
|
|
2242
|
+
}
|
|
1883
2243
|
case 'artifacts': {
|
|
1884
2244
|
await (0, artifactsUi_1.sendArtifactPickerUI)(interaction, {
|
|
1885
2245
|
userPrefRepo,
|