maistro 1.2.20 → 1.2.24
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/app.d.ts +12 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +182 -1
- package/dist/app.js.map +1 -1
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +35 -0
- package/dist/config.js.map +1 -1
- package/dist/notifications.d.ts +22 -0
- package/dist/notifications.d.ts.map +1 -0
- package/dist/notifications.js +155 -0
- package/dist/notifications.js.map +1 -0
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +6 -9
- package/dist/ui.js.map +1 -1
- package/package.json +1 -1
package/dist/app.d.ts
CHANGED
|
@@ -185,6 +185,14 @@ export declare class MaistroApp {
|
|
|
185
185
|
* Handle settings command - show settings menu
|
|
186
186
|
*/
|
|
187
187
|
private handleSettings;
|
|
188
|
+
/**
|
|
189
|
+
* Handle webhook URL configuration in settings
|
|
190
|
+
*/
|
|
191
|
+
private handleWebhookSettings;
|
|
192
|
+
/**
|
|
193
|
+
* Prompt user to enter a webhook URL using InputBox
|
|
194
|
+
*/
|
|
195
|
+
private promptWebhookUrl;
|
|
188
196
|
/**
|
|
189
197
|
* Show manual Cmd+V configuration instructions
|
|
190
198
|
*/
|
|
@@ -233,5 +241,9 @@ export declare class MaistroApp {
|
|
|
233
241
|
private renderExecutionSection;
|
|
234
242
|
private handleRun;
|
|
235
243
|
private executeWithUnifiedView;
|
|
244
|
+
/**
|
|
245
|
+
* Get a display name for the project (folder name, or "projectName (folder)" if they differ)
|
|
246
|
+
*/
|
|
247
|
+
private getProjectDisplayName;
|
|
236
248
|
}
|
|
237
249
|
//# sourceMappingURL=app.d.ts.map
|
package/dist/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAwOA,qBAAa,UAAU;IACrB,OAAO,CAAC,EAAE,CAAgB;IAC1B,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAS;IAG9B,OAAO,CAAC,cAAc,CAA+B;gBAEzC,WAAW,GAAE,MAAY;IAsBrC,OAAO,CAAC,eAAe;IASvB;;;OAGG;YACW,qBAAqB;IA+CnC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkH5B;;;OAGG;YACW,iBAAiB;IAiE/B;;OAEG;IACH,OAAO,CAAC,eAAe;IAUvB;;;OAGG;IACG,YAAY,CAAC,SAAS,UAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAqFtD;;;OAGG;YACW,iBAAiB;IAwD/B;;OAEG;YACW,sBAAsB;IAsCpC;;;OAGG;YACW,iBAAiB;IAoB/B;;;OAGG;YACW,oBAAoB;IAkClC;;OAEG;YACW,qBAAqB;IA4BnC;;OAEG;YACW,gBAAgB;IAoB9B;;;OAGG;YACW,qBAAqB;IAoEnC;;;OAGG;YACW,eAAe;IAiJ7B;;;OAGG;YACW,gBAAgB;IAiD9B;;;OAGG;YACW,uBAAuB;IAyErC;;OAEG;YACW,4BAA4B;IAkE1C;;OAEG;YACW,oBAAoB;IAiElC;;OAEG;IACH,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,UAAU;IAQlB;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;IA2J7B,OAAO,CAAC,iBAAiB,CAAM;IAC/B,OAAO,CAAC,gBAAgB,CAAK;IAE7B;;;OAGG;YACW,YAAY;IAyT1B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA2CxB;;OAEG;YACW,aAAa;IAsmB3B;;;OAGG;YACW,iBAAiB;IAgI/B;;OAEG;YACW,cAAc;IAwU5B,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,aAAa,CAAS;IAE9B;;OAEG;YACW,gBAAgB;IAkB9B;;OAEG;YACW,gBAAgB;IAe9B;;;OAGG;YACW,WAAW;IAsEzB;;;OAGG;YACW,mBAAmB;IA8BjC;;;OAGG;YACW,cAAc;IAkB5B;;;;OAIG;YACW,6BAA6B;IAqI3C;;;OAGG;YACW,aAAa;IA+B3B;;;;OAIG;YACW,sBAAsB;IA6NpC;;;;OAIG;YACW,sBAAsB;YAmHtB,UAAU;IAsIxB,OAAO,CAAC,YAAY;IAmFpB;;;OAGG;YACW,eAAe;IAqD7B;;OAEG;YACW,cAAc;IAgQ5B;;OAEG;YACW,qBAAqB;IA0CnC;;OAEG;YACW,gBAAgB;IA4C9B;;OAEG;YACW,oBAAoB;IAwBlC;;OAEG;YACW,eAAe;IAU7B;;OAEG;YACW,wBAAwB;YAsBxB,gBAAgB;IA4B9B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsD;IAEpF;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAqB3B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAO1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAS1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAKzB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAqB5B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAQ/B;;OAEG;IACH,OAAO,CAAC,eAAe;IASvB;;OAEG;IACH,OAAO,CAAC,sBAAsB;YAoEhB,SAAS;YAiIT,sBAAsB;IA8dpC;;OAEG;IACH,OAAO,CAAC,qBAAqB;CAc9B"}
|
package/dist/app.js
CHANGED
|
@@ -15,7 +15,8 @@ import { buildHeaderWithLogo } from './logo.js';
|
|
|
15
15
|
import { addImageFromFile, addImageFromUrl, addImageFromPaste, getImages, deleteImage, looksLikeImagePath, looksLikeImageUrl, formatImageSize, sanitizeImageId, generatePasteImageId, extractImageUrls, processDescriptionImageUrls, } from './imageManager.js';
|
|
16
16
|
import { InputBox, getDisplayWidth, charIndexAtDisplayColumn } from './inputBox.js';
|
|
17
17
|
import { startCaffeinate, stopCaffeinate, isCaffeinateAvailable, isCaffeinateRunning } from './caffeinate.js';
|
|
18
|
-
import {
|
|
18
|
+
import { sendNotification, testWebhook } from './notifications.js';
|
|
19
|
+
import { getPreventSleep, setPreventSleep, getConfigPath, detectTerminal, getShiftEnterEnabled, setShiftEnterEnabled, configureTerminalShiftEnter, removeTerminalShiftEnter, getNewlineHint, getCmdVPasteEnabled, setCmdVPasteEnabled, configureTerminalCmdVPaste, removeTerminalCmdVPaste, getCmdVPasteInstructions, validateTerminalConfig, getSoundNotifications, setSoundNotifications, getWebhookUrl, setWebhookUrl, } from './config.js';
|
|
19
20
|
import { hasClipboardImage, saveClipboardImage, cleanupTempImage } from './clipboard.js';
|
|
20
21
|
import { isGitRepo } from './git.js';
|
|
21
22
|
import { UI, TipsManager } from './constants.js';
|
|
@@ -742,6 +743,13 @@ export class MaistroApp {
|
|
|
742
743
|
questions: result.questions.map(q => ({ id: q.id, question: q.question, options: q.options })),
|
|
743
744
|
assumptions: result.assumptions,
|
|
744
745
|
});
|
|
746
|
+
// Notify user that input is needed
|
|
747
|
+
await sendNotification({
|
|
748
|
+
event: 'attention',
|
|
749
|
+
title: 'Discovery: input needed',
|
|
750
|
+
detail: `${result.questions.length} question${result.questions.length > 1 ? 's' : ''} to answer`,
|
|
751
|
+
project: this.getProjectDisplayName(),
|
|
752
|
+
});
|
|
745
753
|
// Ask each question one at a time (full-screen for each)
|
|
746
754
|
const answers = {};
|
|
747
755
|
for (let i = 0; i < result.questions.length; i++) {
|
|
@@ -3076,6 +3084,13 @@ ${detection.projectContext}`;
|
|
|
3076
3084
|
}
|
|
3077
3085
|
console.log(`\n\x1b[32m✓ Plan created with ${tasksWithImages.length} tasks\x1b[0m\n`);
|
|
3078
3086
|
getLogger()?.info('Plan created and finalized', { taskCount: tasksWithImages.length });
|
|
3087
|
+
// Notify user that plan is ready for review
|
|
3088
|
+
await sendNotification({
|
|
3089
|
+
event: 'attention',
|
|
3090
|
+
title: 'Plan ready for review',
|
|
3091
|
+
detail: `${tasksWithImages.length} tasks created`,
|
|
3092
|
+
project: this.getProjectDisplayName(),
|
|
3093
|
+
});
|
|
3079
3094
|
}
|
|
3080
3095
|
catch (err) {
|
|
3081
3096
|
// Re-throw ExitRequestedError to propagate exit signal
|
|
@@ -3184,6 +3199,13 @@ ${detection.projectContext}`;
|
|
|
3184
3199
|
}
|
|
3185
3200
|
console.log(`\n\x1b[32m✓ Project initialized with ${tasksWithImages.length} tasks\x1b[0m\n`);
|
|
3186
3201
|
getLogger()?.info('Plan created and finalized', { taskCount: tasksWithImages.length });
|
|
3202
|
+
// Notify user that plan is ready for review
|
|
3203
|
+
await sendNotification({
|
|
3204
|
+
event: 'attention',
|
|
3205
|
+
title: 'Plan ready for review',
|
|
3206
|
+
detail: `${tasksWithImages.length} tasks created`,
|
|
3207
|
+
project: this.getProjectDisplayName(),
|
|
3208
|
+
});
|
|
3187
3209
|
}
|
|
3188
3210
|
catch (err) {
|
|
3189
3211
|
// Re-throw ExitRequestedError to propagate exit signal
|
|
@@ -3393,6 +3415,20 @@ ${detection.projectContext}`;
|
|
|
3393
3415
|
description: `${terminalInfo.name} - use /paste command instead`,
|
|
3394
3416
|
});
|
|
3395
3417
|
}
|
|
3418
|
+
// Sound notification toggle
|
|
3419
|
+
const soundEnabled = getSoundNotifications();
|
|
3420
|
+
menuItems.push({
|
|
3421
|
+
key: 'sound',
|
|
3422
|
+
label: `Sound notifications: ${soundEnabled ? '\x1b[32mON\x1b[0m' : '\x1b[90mOFF\x1b[0m'}`,
|
|
3423
|
+
description: 'Play a chime when execution completes or needs attention',
|
|
3424
|
+
});
|
|
3425
|
+
// Webhook notification
|
|
3426
|
+
const webhookUrl = getWebhookUrl();
|
|
3427
|
+
menuItems.push({
|
|
3428
|
+
key: 'webhook',
|
|
3429
|
+
label: `Webhook notifications: ${webhookUrl ? '\x1b[32mConfigured\x1b[0m' : '\x1b[90mOFF\x1b[0m'}`,
|
|
3430
|
+
description: webhookUrl ? 'Update or remove webhook URL' : 'Configure a webhook URL for notifications',
|
|
3431
|
+
});
|
|
3396
3432
|
menuItems.push({
|
|
3397
3433
|
key: 'back',
|
|
3398
3434
|
label: 'Back',
|
|
@@ -3529,8 +3565,107 @@ ${detection.projectContext}`;
|
|
|
3529
3565
|
// Show manual instructions for Cmd+V
|
|
3530
3566
|
await this.showCmdVInstructions();
|
|
3531
3567
|
}
|
|
3568
|
+
if (choice === 'sound') {
|
|
3569
|
+
const newValue = !soundEnabled;
|
|
3570
|
+
setSoundNotifications(newValue);
|
|
3571
|
+
// Loop redraws with updated value
|
|
3572
|
+
}
|
|
3573
|
+
if (choice === 'webhook') {
|
|
3574
|
+
await this.handleWebhookSettings();
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
/**
|
|
3579
|
+
* Handle webhook URL configuration in settings
|
|
3580
|
+
*/
|
|
3581
|
+
async handleWebhookSettings() {
|
|
3582
|
+
const currentUrl = getWebhookUrl();
|
|
3583
|
+
if (currentUrl) {
|
|
3584
|
+
// Already configured — show sub-menu
|
|
3585
|
+
this.ui.clear();
|
|
3586
|
+
this.showHeader();
|
|
3587
|
+
console.log('\x1b[1m── Settings: Webhook Notifications ──\x1b[0m\n');
|
|
3588
|
+
console.log(`\x1b[90mCurrent URL: ${currentUrl}\x1b[0m\n`);
|
|
3589
|
+
const subMenuItems = [
|
|
3590
|
+
{ key: 'update', label: 'Update URL', description: 'Enter a new webhook URL' },
|
|
3591
|
+
{ key: 'test', label: 'Test notification', description: 'Send a test message to the webhook' },
|
|
3592
|
+
{ key: 'remove', label: 'Remove', description: 'Disable webhook notifications' },
|
|
3593
|
+
{ key: 'cancel', label: 'Cancel', description: 'Return to settings' },
|
|
3594
|
+
];
|
|
3595
|
+
const subChoice = await this.ui.quickPick(subMenuItems, 'Webhook options:', undefined, { showInput: false });
|
|
3596
|
+
if (subChoice === 'update') {
|
|
3597
|
+
await this.promptWebhookUrl();
|
|
3598
|
+
}
|
|
3599
|
+
else if (subChoice === 'test') {
|
|
3600
|
+
this.ui.clear();
|
|
3601
|
+
this.showHeader();
|
|
3602
|
+
console.log('\x1b[1m── Settings: Test Webhook ──\x1b[0m\n');
|
|
3603
|
+
console.log('Sending test notification...\n');
|
|
3604
|
+
const result = await testWebhook(currentUrl);
|
|
3605
|
+
if (result.success) {
|
|
3606
|
+
console.log('\x1b[32m✓ Test notification sent successfully!\x1b[0m');
|
|
3607
|
+
}
|
|
3608
|
+
else {
|
|
3609
|
+
console.log(`\x1b[31m✗ Failed: ${result.error}\x1b[0m`);
|
|
3610
|
+
}
|
|
3611
|
+
console.log('\n\x1b[90mPress any key to continue...\x1b[0m');
|
|
3612
|
+
await this.waitForKeypress();
|
|
3613
|
+
}
|
|
3614
|
+
else if (subChoice === 'remove') {
|
|
3615
|
+
setWebhookUrl(undefined);
|
|
3616
|
+
}
|
|
3617
|
+
}
|
|
3618
|
+
else {
|
|
3619
|
+
// Not configured — prompt for URL
|
|
3620
|
+
await this.promptWebhookUrl();
|
|
3532
3621
|
}
|
|
3533
3622
|
}
|
|
3623
|
+
/**
|
|
3624
|
+
* Prompt user to enter a webhook URL using InputBox
|
|
3625
|
+
*/
|
|
3626
|
+
async promptWebhookUrl() {
|
|
3627
|
+
return new Promise((resolve) => {
|
|
3628
|
+
const inputBox = new InputBox({
|
|
3629
|
+
placeholder: 'https://hooks.slack.com/services/...',
|
|
3630
|
+
hint: 'Enter to save · Esc to cancel',
|
|
3631
|
+
onRedraw: () => {
|
|
3632
|
+
this.ui.clear();
|
|
3633
|
+
this.showHeader();
|
|
3634
|
+
console.log('\x1b[1m── Settings: Webhook URL ──\x1b[0m\n');
|
|
3635
|
+
console.log('Enter your webhook URL for notifications.');
|
|
3636
|
+
console.log('Works with Slack, Discord, or any endpoint that accepts JSON POST.\n');
|
|
3637
|
+
console.log('\x1b[90mSlack: Workspace Settings → Manage Apps → Custom Integrations → Incoming WebHooks\x1b[0m\n');
|
|
3638
|
+
},
|
|
3639
|
+
onSubmit: (value) => {
|
|
3640
|
+
const url = value.trim();
|
|
3641
|
+
if (!url) {
|
|
3642
|
+
resolve();
|
|
3643
|
+
return;
|
|
3644
|
+
}
|
|
3645
|
+
if (!url.startsWith('https://')) {
|
|
3646
|
+
this.ui.clear();
|
|
3647
|
+
this.showHeader();
|
|
3648
|
+
console.log('\x1b[1m── Settings: Webhook URL ──\x1b[0m\n');
|
|
3649
|
+
console.log('\x1b[31m✗ URL must start with https://\x1b[0m');
|
|
3650
|
+
console.log('\n\x1b[90mPress any key to continue...\x1b[0m');
|
|
3651
|
+
this.waitForKeypress().then(() => resolve());
|
|
3652
|
+
return;
|
|
3653
|
+
}
|
|
3654
|
+
setWebhookUrl(url);
|
|
3655
|
+
this.ui.clear();
|
|
3656
|
+
this.showHeader();
|
|
3657
|
+
console.log('\x1b[1m── Settings ──\x1b[0m\n');
|
|
3658
|
+
console.log('\x1b[32m✓ Webhook URL saved!\x1b[0m');
|
|
3659
|
+
console.log('\n\x1b[90mPress any key to continue...\x1b[0m');
|
|
3660
|
+
this.waitForKeypress().then(() => resolve());
|
|
3661
|
+
},
|
|
3662
|
+
onCancel: () => {
|
|
3663
|
+
resolve();
|
|
3664
|
+
},
|
|
3665
|
+
});
|
|
3666
|
+
inputBox.start();
|
|
3667
|
+
});
|
|
3668
|
+
}
|
|
3534
3669
|
/**
|
|
3535
3670
|
* Show manual Cmd+V configuration instructions
|
|
3536
3671
|
*/
|
|
@@ -4292,8 +4427,54 @@ ${detection.projectContext}`;
|
|
|
4292
4427
|
getLogger()?.error('Execution failed with full error', { error: result.error });
|
|
4293
4428
|
}
|
|
4294
4429
|
}
|
|
4430
|
+
// Send notifications (sound + webhook)
|
|
4431
|
+
// Skip notification if no tasks were actually executed this run (all were already done)
|
|
4432
|
+
const tasksExecutedThisRun = result.completedTasks - alreadyCompleted;
|
|
4433
|
+
const project = this.getProjectDisplayName();
|
|
4434
|
+
if (result.success && tasksExecutedThisRun > 0) {
|
|
4435
|
+
await sendNotification({
|
|
4436
|
+
event: 'completed',
|
|
4437
|
+
title: 'All tasks completed',
|
|
4438
|
+
detail: `${result.completedTasks}/${result.totalTasks} tasks completed successfully`,
|
|
4439
|
+
project,
|
|
4440
|
+
});
|
|
4441
|
+
}
|
|
4442
|
+
else if (result.blockedTask) {
|
|
4443
|
+
await sendNotification({
|
|
4444
|
+
event: 'attention',
|
|
4445
|
+
title: `Task failed: ${result.blockedTask.title}`,
|
|
4446
|
+
detail: result.error ? truncateError(result.error) : undefined,
|
|
4447
|
+
project,
|
|
4448
|
+
});
|
|
4449
|
+
}
|
|
4450
|
+
else if (!this.shouldStop) {
|
|
4451
|
+
// User-initiated pause doesn't need a notification
|
|
4452
|
+
await sendNotification({
|
|
4453
|
+
event: 'attention',
|
|
4454
|
+
title: 'Execution failed',
|
|
4455
|
+
detail: result.error ? truncateError(result.error) : undefined,
|
|
4456
|
+
project,
|
|
4457
|
+
});
|
|
4458
|
+
}
|
|
4295
4459
|
// Clear cached orchestrator
|
|
4296
4460
|
this.orchestrator = null;
|
|
4297
4461
|
}
|
|
4462
|
+
/**
|
|
4463
|
+
* Get a display name for the project (folder name, or "projectName (folder)" if they differ)
|
|
4464
|
+
*/
|
|
4465
|
+
getProjectDisplayName() {
|
|
4466
|
+
const folderName = basename(this.projectPath);
|
|
4467
|
+
try {
|
|
4468
|
+
const orchestrator = this.getOrchestrator();
|
|
4469
|
+
const projectName = orchestrator.getProjectName();
|
|
4470
|
+
if (projectName && projectName !== folderName) {
|
|
4471
|
+
return `${projectName} (${folderName})`;
|
|
4472
|
+
}
|
|
4473
|
+
}
|
|
4474
|
+
catch {
|
|
4475
|
+
// Orchestrator may not be loaded yet
|
|
4476
|
+
}
|
|
4477
|
+
return folderName;
|
|
4478
|
+
}
|
|
4298
4479
|
}
|
|
4299
4480
|
//# sourceMappingURL=app.js.map
|