@paradigma-inc/flywheel 0.1.51 → 0.1.53
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/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
buildGuidedSkillInstallPrompt,
|
|
40
40
|
runMcpModeCommand,
|
|
41
41
|
} from "./setup/modes/mcp-command.mjs";
|
|
42
|
+
import { findFlywheelMcpEntryNames } from "./setup/shared/prior-mode-detect.mjs";
|
|
42
43
|
import { renderSetupSummary } from "./setup/shared/summary.mjs";
|
|
43
44
|
|
|
44
45
|
export { buildGuidedSkillInstallPrompt };
|
|
@@ -532,16 +533,47 @@ async function resolveHostsWithRemainingFlywheelMcpEntries({ scope }) {
|
|
|
532
533
|
return remainingHosts;
|
|
533
534
|
}
|
|
534
535
|
|
|
535
|
-
async function
|
|
536
|
+
async function findFlywheelServerNamesOnHost(hostName, scope) {
|
|
537
|
+
// Mirror setup's prior-mode detector: walk every MCP entry on the host and
|
|
538
|
+
// keep those whose URL is Flywheel-identifying (hostname contains "flywheel"
|
|
539
|
+
// or path === /mcp-server with a matching target origin). Uninstall must
|
|
540
|
+
// catch renamed/drifted entries (e.g. `[mcp_servers.flywheel-staging]`) that
|
|
541
|
+
// setup already detects; otherwise a user whose host has a non-default entry
|
|
542
|
+
// name is stuck between setup ("already installed") and uninstall ("not
|
|
543
|
+
// configured").
|
|
544
|
+
return await findFlywheelMcpEntryNames({ hostName, scope }).catch(() => []);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
async function resolveUninstallServerNamesForHost(
|
|
548
|
+
hostName,
|
|
549
|
+
scope,
|
|
550
|
+
{ explicitServerName },
|
|
551
|
+
) {
|
|
552
|
+
if (explicitServerName) {
|
|
553
|
+
const configured = await isAlreadyConfigured(
|
|
554
|
+
hostName,
|
|
555
|
+
scope,
|
|
556
|
+
explicitServerName,
|
|
557
|
+
).catch(() => false);
|
|
558
|
+
return configured ? [explicitServerName] : [];
|
|
559
|
+
}
|
|
560
|
+
return await findFlywheelServerNamesOnHost(hostName, scope);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
async function isConfiguredForUninstallScope(
|
|
564
|
+
hostName,
|
|
565
|
+
scope,
|
|
566
|
+
{ explicitServerName },
|
|
567
|
+
) {
|
|
536
568
|
const scopes = scopesFromUninstallScope(scope);
|
|
537
569
|
for (const singleScope of scopes) {
|
|
538
570
|
// eslint-disable-next-line no-await-in-loop
|
|
539
|
-
const
|
|
571
|
+
const targets = await resolveUninstallServerNamesForHost(
|
|
540
572
|
hostName,
|
|
541
573
|
singleScope,
|
|
542
|
-
|
|
543
|
-
)
|
|
544
|
-
if (
|
|
574
|
+
{ explicitServerName },
|
|
575
|
+
);
|
|
576
|
+
if (targets.length > 0) return true;
|
|
545
577
|
}
|
|
546
578
|
return false;
|
|
547
579
|
}
|
|
@@ -563,14 +595,12 @@ async function promptUninstallScope(defaultScope) {
|
|
|
563
595
|
}
|
|
564
596
|
}
|
|
565
597
|
|
|
566
|
-
async function promptUninstallHosts(scope,
|
|
598
|
+
async function promptUninstallHosts(scope, { explicitServerName }) {
|
|
567
599
|
const choices = await Promise.all(
|
|
568
600
|
ALL_HOST_NAMES.map(async (hostName) => {
|
|
569
|
-
const configured = await isConfiguredForUninstallScope(
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
serverName,
|
|
573
|
-
);
|
|
601
|
+
const configured = await isConfiguredForUninstallScope(hostName, scope, {
|
|
602
|
+
explicitServerName,
|
|
603
|
+
});
|
|
574
604
|
return {
|
|
575
605
|
name: SETUP_HOST_NAMES[hostName],
|
|
576
606
|
value: hostName,
|
|
@@ -599,7 +629,7 @@ async function promptUninstallHosts(scope, serverName) {
|
|
|
599
629
|
}
|
|
600
630
|
}
|
|
601
631
|
|
|
602
|
-
async function resolveUninstallTargets(options,
|
|
632
|
+
async function resolveUninstallTargets(options, { explicitServerName }) {
|
|
603
633
|
const explicitHostsFromFlags = selectedHostsFromOptions(options);
|
|
604
634
|
const explicitHostsFromList =
|
|
605
635
|
explicitHostsFromFlags.length === 0 ? parseHostsList(options.hosts) : [];
|
|
@@ -628,7 +658,9 @@ async function resolveUninstallTargets(options, serverName) {
|
|
|
628
658
|
}
|
|
629
659
|
|
|
630
660
|
if (!hasExplicitHosts) {
|
|
631
|
-
const selectedHosts = await promptUninstallHosts(scope,
|
|
661
|
+
const selectedHosts = await promptUninstallHosts(scope, {
|
|
662
|
+
explicitServerName,
|
|
663
|
+
});
|
|
632
664
|
if (!selectedHosts) {
|
|
633
665
|
log.warn("Uninstall cancelled");
|
|
634
666
|
return null;
|
|
@@ -682,8 +714,13 @@ async function removeHostConfig(hostName, scope, serverName) {
|
|
|
682
714
|
}
|
|
683
715
|
|
|
684
716
|
async function runUninstallCommand(options) {
|
|
685
|
-
const
|
|
686
|
-
|
|
717
|
+
const explicitServerName =
|
|
718
|
+
typeof options.name === "string" && options.name.trim().length > 0
|
|
719
|
+
? normalizeServerName(options.name)
|
|
720
|
+
: null;
|
|
721
|
+
const resolved = await resolveUninstallTargets(options, {
|
|
722
|
+
explicitServerName,
|
|
723
|
+
});
|
|
687
724
|
if (!resolved) return;
|
|
688
725
|
const { scope, hosts } = resolved;
|
|
689
726
|
const scopes = scopesFromUninstallScope(scope);
|
|
@@ -693,8 +730,35 @@ async function runUninstallCommand(options) {
|
|
|
693
730
|
for (const singleScope of scopes) {
|
|
694
731
|
for (const host of hosts) {
|
|
695
732
|
mcpSpinner.text = `Removing from ${getHost(host).displayName} (${singleScope})...`;
|
|
733
|
+
// Resolve the concrete server name(s) to remove at the host/scope level.
|
|
734
|
+
// When --name was not given, this iterates every Flywheel-identifying
|
|
735
|
+
// entry (matching setup's prior-mode detector) so renamed or drifted
|
|
736
|
+
// entries (e.g. `[mcp_servers.flywheel-staging]`) are actually cleared.
|
|
696
737
|
// eslint-disable-next-line no-await-in-loop
|
|
697
|
-
|
|
738
|
+
const targetNames = await resolveUninstallServerNamesForHost(
|
|
739
|
+
host,
|
|
740
|
+
singleScope,
|
|
741
|
+
{ explicitServerName },
|
|
742
|
+
);
|
|
743
|
+
if (targetNames.length === 0) {
|
|
744
|
+
// eslint-disable-next-line no-await-in-loop
|
|
745
|
+
const hostForDisplay = getHost(host);
|
|
746
|
+
// eslint-disable-next-line no-await-in-loop
|
|
747
|
+
const filePath = await resolveMcpPath(
|
|
748
|
+
mcpCandidatesForScope(hostForDisplay, singleScope),
|
|
749
|
+
);
|
|
750
|
+
mcpResults.push({
|
|
751
|
+
host: hostForDisplay.displayName,
|
|
752
|
+
scope: singleScope,
|
|
753
|
+
filePath,
|
|
754
|
+
status: "not present",
|
|
755
|
+
});
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
for (const targetName of targetNames) {
|
|
759
|
+
// eslint-disable-next-line no-await-in-loop
|
|
760
|
+
mcpResults.push(await removeHostConfig(host, singleScope, targetName));
|
|
761
|
+
}
|
|
698
762
|
}
|
|
699
763
|
}
|
|
700
764
|
mcpSpinner.succeed("MCP uninstall complete");
|
|
@@ -172,15 +172,15 @@ async function findFlywheelTomlEntryNames(filePath, targetOrigin) {
|
|
|
172
172
|
return unique(matches);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
async function findFlywheelMcpEntryNames({
|
|
175
|
+
export async function findFlywheelMcpEntryNames({
|
|
176
176
|
hostName,
|
|
177
177
|
scope,
|
|
178
|
-
cwd,
|
|
179
|
-
targetOrigin,
|
|
180
|
-
getHost,
|
|
181
|
-
resolveMcpPath,
|
|
182
|
-
readJsonConfig,
|
|
183
|
-
readYamlConfig,
|
|
178
|
+
cwd = process.cwd(),
|
|
179
|
+
targetOrigin = null,
|
|
180
|
+
getHost = defaultGetHost,
|
|
181
|
+
resolveMcpPath = defaultResolveMcpPath,
|
|
182
|
+
readJsonConfig = defaultReadJsonConfig,
|
|
183
|
+
readYamlConfig = defaultReadYamlConfig,
|
|
184
184
|
}) {
|
|
185
185
|
try {
|
|
186
186
|
const host = getHost(hostName);
|
package/src/unified-cli.mjs
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
1
5
|
import { runCli as runSetupCli } from "./cli.mjs";
|
|
2
6
|
import { runRuntimeCli } from "./runtime/delegate.mjs";
|
|
3
7
|
import { RUNTIME_ALIASES } from "./runtime/vendor/flywheel-cli-dist/commands/aliases.js";
|
|
4
8
|
|
|
9
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const PACKAGE_JSON_PATH = path.resolve(__dirname, "..", "package.json");
|
|
11
|
+
|
|
5
12
|
const ALIAS_RESERVED_COMMANDS = new Set([
|
|
6
13
|
"setup",
|
|
7
14
|
"uninstall",
|
|
@@ -9,6 +16,7 @@ const ALIAS_RESERVED_COMMANDS = new Set([
|
|
|
9
16
|
"--help",
|
|
10
17
|
"-h",
|
|
11
18
|
]);
|
|
19
|
+
const VERSION_REQUEST_TOKENS = new Set(["--version", "-v", "version"]);
|
|
12
20
|
|
|
13
21
|
const HELP_EXTRAS = [
|
|
14
22
|
{
|
|
@@ -49,6 +57,30 @@ function stripFormatTokens(argv) {
|
|
|
49
57
|
return out;
|
|
50
58
|
}
|
|
51
59
|
|
|
60
|
+
let cachedPackageVersion = null;
|
|
61
|
+
|
|
62
|
+
async function loadPackageVersion() {
|
|
63
|
+
if (cachedPackageVersion !== null) {
|
|
64
|
+
return cachedPackageVersion;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const raw = await readFile(PACKAGE_JSON_PATH, "utf8");
|
|
68
|
+
const parsed = JSON.parse(raw);
|
|
69
|
+
if (typeof parsed.version === "string" && parsed.version.trim()) {
|
|
70
|
+
cachedPackageVersion = parsed.version.trim();
|
|
71
|
+
return cachedPackageVersion;
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
// Fall through to deterministic fallback.
|
|
75
|
+
}
|
|
76
|
+
cachedPackageVersion = "0.0.0";
|
|
77
|
+
return cachedPackageVersion;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function isVersionRequest(argv) {
|
|
81
|
+
return argv.length === 1 && VERSION_REQUEST_TOKENS.has(argv[0]);
|
|
82
|
+
}
|
|
83
|
+
|
|
52
84
|
/**
|
|
53
85
|
* Detect a top-level help invocation.
|
|
54
86
|
*
|
|
@@ -104,6 +136,12 @@ export async function runUnifiedCli(argv = process.argv.slice(2)) {
|
|
|
104
136
|
throw new Error("runUnifiedCli expects an argv array.");
|
|
105
137
|
}
|
|
106
138
|
|
|
139
|
+
if (isVersionRequest(argv)) {
|
|
140
|
+
process.stdout.write(`${await loadPackageVersion()}\n`);
|
|
141
|
+
process.exitCode = 0;
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
107
145
|
if (isCombinedHelpRequest(argv)) {
|
|
108
146
|
// Preserve any --format token verbatim so the runtime's format validator
|
|
109
147
|
// runs and rejects unsupported values (e.g. `--format=badvalue`) with the
|