premanmcp 0.16.0 → 0.16.2
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/bin/integrations.js +110 -38
- package/package.json +1 -1
package/bin/integrations.js
CHANGED
|
@@ -273,8 +273,12 @@ export async function githubCommand(args) {
|
|
|
273
273
|
|
|
274
274
|
const url = started.install_url || started.url;
|
|
275
275
|
if (!url) throw new Error("Backend returned no GitHub install URL.");
|
|
276
|
-
|
|
277
|
-
|
|
276
|
+
// Installing the App is our plumbing and choosing repositories is the
|
|
277
|
+
// decision, so the decision leads. Naming the save matters more than either:
|
|
278
|
+
// GitHub's picker reads as a confirmation screen, so people recognise their
|
|
279
|
+
// repository on it and close the tab without ever granting anything.
|
|
280
|
+
present(url, "choose the repositories PreMan may read");
|
|
281
|
+
process.stdout.write("Save the selection on GitHub — that is what connects them.\n");
|
|
278
282
|
|
|
279
283
|
// The refresh answer is the diagnosis. A 409 means GitHub never called back;
|
|
280
284
|
// a success carrying no repositories means the App is installed and sharing
|
|
@@ -366,14 +370,6 @@ export async function slackCommand(args) {
|
|
|
366
370
|
// The guided run
|
|
367
371
|
// ---------------------------------------------------------------------------
|
|
368
372
|
|
|
369
|
-
/**
|
|
370
|
-
* "yes" | "no" | "back" -- back only offered once there is somewhere to go.
|
|
371
|
-
*
|
|
372
|
-
* `--yes` takes each step's own default rather than answering yes to all of
|
|
373
|
-
* them, so a step that should not ride in on a keypress can say so. Every step
|
|
374
|
-
* that asks defaults to yes today; the desktop app, which used to be the
|
|
375
|
-
* exception, no longer asks at all.
|
|
376
|
-
*/
|
|
377
373
|
/**
|
|
378
374
|
* Ask, once, before PreMan writes into an SDK repository or a docs site.
|
|
379
375
|
*
|
|
@@ -387,8 +383,14 @@ export async function slackCommand(args) {
|
|
|
387
383
|
* which is the whole reason this moved out of the delivery run.
|
|
388
384
|
*/
|
|
389
385
|
async function offerReleaseTargets(args, checkout, { assumeYes }) {
|
|
386
|
+
// SILENT is a step that did not happen rather than one that was skipped: no
|
|
387
|
+
// heading, and no line in the summary either. A repository with no SDK and no
|
|
388
|
+
// docs site has nothing to decide here, and saying so is worse than saying
|
|
389
|
+
// nothing.
|
|
390
|
+
const SILENT = { state: "skipped", silent: true };
|
|
391
|
+
|
|
390
392
|
const integrationId = checkout?.match?.integration_id;
|
|
391
|
-
if (!integrationId) return
|
|
393
|
+
if (!integrationId) return SILENT;
|
|
392
394
|
|
|
393
395
|
const token = resolveApiKey(args);
|
|
394
396
|
const path = `/sdk/integrations/${integrationId}/distribution`;
|
|
@@ -399,18 +401,19 @@ async function offerReleaseTargets(args, checkout, { assumeYes }) {
|
|
|
399
401
|
// Detection costs one root listing per repository in the installation. It
|
|
400
402
|
// is the least important thing in this walk and never worth failing setup
|
|
401
403
|
// over.
|
|
402
|
-
return
|
|
404
|
+
return SILENT;
|
|
403
405
|
}
|
|
404
406
|
|
|
407
|
+
const sdkRepo = detected?.sdk_repo || "";
|
|
408
|
+
const docsRepo = detected?.docs_repo || "";
|
|
409
|
+
if (!sdkRepo && !docsRepo) return SILENT;
|
|
410
|
+
|
|
411
|
+
banner("Releases");
|
|
405
412
|
if (detected?.confirmed) {
|
|
406
413
|
process.stdout.write(`${MARK.ok()} Release targets already answered.\n`);
|
|
407
414
|
return;
|
|
408
415
|
}
|
|
409
416
|
|
|
410
|
-
const sdkRepo = detected?.sdk_repo || "";
|
|
411
|
-
const docsRepo = detected?.docs_repo || "";
|
|
412
|
-
if (!sdkRepo && !docsRepo) return { state: "skipped" };
|
|
413
|
-
|
|
414
417
|
const body = {};
|
|
415
418
|
const decided = [];
|
|
416
419
|
for (const [repo, field, flag, question] of [
|
|
@@ -474,6 +477,46 @@ async function askRelease(question, assumeYes) {
|
|
|
474
477
|
return answer === "y" || answer === "yes";
|
|
475
478
|
}
|
|
476
479
|
|
|
480
|
+
/**
|
|
481
|
+
* Put PreMan on screen, signed in as the account this walk just used.
|
|
482
|
+
*
|
|
483
|
+
* Returns whether the app is actually up, because that is what decides the last
|
|
484
|
+
* line of the walk and nothing downstream can work it out.
|
|
485
|
+
*/
|
|
486
|
+
async function showDesktopSignedIn(openDesktopSignedIn, args, creds, stopOpening) {
|
|
487
|
+
// The same --dest the install honoured, or the launch would look for the app
|
|
488
|
+
// somewhere it was never copied to.
|
|
489
|
+
const destination = args.value("--dest", "/Applications");
|
|
490
|
+
const opened = await openDesktopSignedIn(creds, { destination });
|
|
491
|
+
stopOpening?.();
|
|
492
|
+
if (opened.state === "opened-signed-in") {
|
|
493
|
+
process.stdout.write("Opened PreMan, signed in as this account.\n");
|
|
494
|
+
} else if (opened.state === "not-installed") {
|
|
495
|
+
process.stdout.write(
|
|
496
|
+
`PreMan is not in ${destination} yet \u2014 open it once installed and sign in.\n`
|
|
497
|
+
);
|
|
498
|
+
} else {
|
|
499
|
+
// Either the session could not be handed over or this app is too old to take
|
|
500
|
+
// it up. Say so rather than let the customer wonder why they are looking at
|
|
501
|
+
// a login screen.
|
|
502
|
+
process.stdout.write("Opened PreMan \u2014 sign in with the account you just used.\n");
|
|
503
|
+
}
|
|
504
|
+
return opened.state !== "not-installed";
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/** One step heading, in the one format the whole walk uses. */
|
|
508
|
+
function banner(name) {
|
|
509
|
+
process.stdout.write(`\n── ${name} ──\n`);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* "yes" | "no" | "back" -- back only offered once there is somewhere to go.
|
|
514
|
+
*
|
|
515
|
+
* `--yes` takes each step's own default rather than answering yes to all of
|
|
516
|
+
* them, so a step that should not ride in on a keypress can say so. Every step
|
|
517
|
+
* that asks defaults to yes today; the desktop app, which used to be the
|
|
518
|
+
* exception, no longer asks at all.
|
|
519
|
+
*/
|
|
477
520
|
async function askStep(question, { assumeYes, canGoBack, defaultYes = true }) {
|
|
478
521
|
const fallback = defaultYes ? "yes" : "no";
|
|
479
522
|
if (assumeYes) return fallback;
|
|
@@ -599,6 +642,22 @@ export async function onboardCommand(
|
|
|
599
642
|
process.stdout.write(
|
|
600
643
|
`${checkout.slug} is still not shared. Add it at ${INSTALLATIONS_URL}.\n`
|
|
601
644
|
);
|
|
645
|
+
// Nothing was connected, so this step did not finish. Returning nothing
|
|
646
|
+
// marks it done, which is how the walk came to print a tick directly
|
|
647
|
+
// under a line saying the repository is not shared — and why somebody
|
|
648
|
+
// would then open the app expecting to find GitHub set up and find
|
|
649
|
+
// "Continue with GitHub" instead. The sibling branch below already
|
|
650
|
+
// reports this correctly; this one simply never did.
|
|
651
|
+
return { state: "skipped" };
|
|
652
|
+
},
|
|
653
|
+
onSkip: () => {
|
|
654
|
+
// The one question in this walk that decides whether a fix from this
|
|
655
|
+
// code can ever land anywhere. Declining it in silence is how the gap
|
|
656
|
+
// stays invisible until a fix task finishes and produces nothing.
|
|
657
|
+
process.stdout.write(
|
|
658
|
+
`${MARK.skip()} ${checkout.slug} stays disconnected — fixes here cannot open pull requests.\n`
|
|
659
|
+
);
|
|
660
|
+
process.stdout.write(` Run '${cliInvocation()} github' here to change that.\n`);
|
|
602
661
|
},
|
|
603
662
|
});
|
|
604
663
|
} else {
|
|
@@ -631,6 +690,10 @@ export async function onboardCommand(
|
|
|
631
690
|
// inside a delivery run, on a screen most people never opened.
|
|
632
691
|
steps.push({
|
|
633
692
|
name: "Releases",
|
|
693
|
+
// Prints its own heading, and only once it knows there is a question. A
|
|
694
|
+
// walk that draws an empty section has told the customer something is
|
|
695
|
+
// missing when nothing is.
|
|
696
|
+
ownBanner: true,
|
|
634
697
|
run: () => offerReleaseTargets(args, checkout, { assumeYes }),
|
|
635
698
|
});
|
|
636
699
|
|
|
@@ -678,8 +741,21 @@ export async function onboardCommand(
|
|
|
678
741
|
if (desktop?.state === "installed") {
|
|
679
742
|
steps.push({
|
|
680
743
|
name: "Desktop app",
|
|
681
|
-
|
|
744
|
+
// Nothing to download, which is the point of this branch. It is not a
|
|
745
|
+
// reason to stop at the sentence: the step exists to leave the customer
|
|
746
|
+
// looking at PreMan, so the one run with nothing to install was also the
|
|
747
|
+
// only run that opened nothing, and it closed by sending someone to a
|
|
748
|
+
// website instead of the app already sitting on their machine.
|
|
749
|
+
run: async () => {
|
|
682
750
|
process.stdout.write(`${MARK.ok()} PreMan desktop app already installed.\n`);
|
|
751
|
+
const stopOpening = showOpeningDesktop();
|
|
752
|
+
try {
|
|
753
|
+
return {
|
|
754
|
+
appOpened: await showDesktopSignedIn(openDesktopSignedIn, args, creds, stopOpening),
|
|
755
|
+
};
|
|
756
|
+
} finally {
|
|
757
|
+
stopOpening();
|
|
758
|
+
}
|
|
683
759
|
},
|
|
684
760
|
});
|
|
685
761
|
} else if (!desktop) {
|
|
@@ -707,26 +783,15 @@ export async function onboardCommand(
|
|
|
707
783
|
return installed;
|
|
708
784
|
}
|
|
709
785
|
stopOpening ??= showOpeningDesktop();
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
`PreMan is not in ${destination} yet \u2014 open it once installed and sign in.\n`
|
|
720
|
-
);
|
|
721
|
-
} else {
|
|
722
|
-
// Either the session could not be handed over or this app is too
|
|
723
|
-
// old to take it up. Say so rather than let the customer wonder
|
|
724
|
-
// why they are looking at a login screen.
|
|
725
|
-
process.stdout.write("Opened PreMan \u2014 sign in with the account you just used.\n");
|
|
726
|
-
}
|
|
727
|
-
// Whether the app is on screen decides what the last line of the walk
|
|
728
|
-
// should say, and only this closure knows.
|
|
729
|
-
return { ...installed, appOpened: opened.state !== "not-installed" };
|
|
786
|
+
return {
|
|
787
|
+
...installed,
|
|
788
|
+
appOpened: await showDesktopSignedIn(
|
|
789
|
+
openDesktopSignedIn,
|
|
790
|
+
args,
|
|
791
|
+
creds,
|
|
792
|
+
stopOpening
|
|
793
|
+
),
|
|
794
|
+
};
|
|
730
795
|
} finally {
|
|
731
796
|
stopOpening?.();
|
|
732
797
|
}
|
|
@@ -745,7 +810,7 @@ export async function onboardCommand(
|
|
|
745
810
|
let i = 0;
|
|
746
811
|
while (i < steps.length) {
|
|
747
812
|
const step = steps[i];
|
|
748
|
-
|
|
813
|
+
if (!step.ownBanner) banner(step.name);
|
|
749
814
|
|
|
750
815
|
if (step.question) {
|
|
751
816
|
// "back" goes to the last step that asked something, not simply to the
|
|
@@ -784,6 +849,13 @@ export async function onboardCommand(
|
|
|
784
849
|
// at the end of a successful install: the install reports state "installed",
|
|
785
850
|
// which is none of the three, so it printed as a failure with no detail.
|
|
786
851
|
const reported = await step.run();
|
|
852
|
+
// A step that never announced itself does not belong in the summary
|
|
853
|
+
// either: a line reading "(skipped)" for work nobody was offered reads as
|
|
854
|
+
// something having gone wrong.
|
|
855
|
+
if (reported?.silent) {
|
|
856
|
+
i += 1;
|
|
857
|
+
continue;
|
|
858
|
+
}
|
|
787
859
|
const state =
|
|
788
860
|
{ failed: "failed", skipped: "skipped", unsupported: "skipped" }[reported?.state] ||
|
|
789
861
|
"done";
|