camstack 0.5.1 → 0.5.3
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/cli.js +125 -15
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { createRequire } from "module";
|
|
|
8
8
|
import { fileURLToPath } from "url";
|
|
9
9
|
import { dirname, resolve as resolve2 } from "path";
|
|
10
10
|
import * as os4 from "os";
|
|
11
|
-
import { parseArgs as
|
|
11
|
+
import { parseArgs as parseArgs5 } from "util";
|
|
12
12
|
|
|
13
13
|
// src/commands/serve.ts
|
|
14
14
|
import { parseArgs } from "util";
|
|
@@ -444,29 +444,29 @@ function isUnknown(_value) {
|
|
|
444
444
|
async function resolveServerInteractive(presetNamespace) {
|
|
445
445
|
const { discoverNodes, resolveHubFromDiscovered } = await import("./discover-NPUMWBRW.js");
|
|
446
446
|
if (presetNamespace) {
|
|
447
|
-
const
|
|
448
|
-
|
|
447
|
+
const spinner4 = clack.spinner();
|
|
448
|
+
spinner4.start(`Discovering hub on LAN (namespace "${presetNamespace}")`);
|
|
449
449
|
const filtered = await discoverNodes({ namespace: presetNamespace });
|
|
450
450
|
if (filtered.length === 0) {
|
|
451
|
-
|
|
451
|
+
spinner4.stop(`No nodes responded for namespace "${presetNamespace}".`);
|
|
452
452
|
throw new Error(`Hub running? Same LAN?`);
|
|
453
453
|
}
|
|
454
454
|
const hub = await resolveHubFromDiscovered(filtered);
|
|
455
455
|
if (!hub) {
|
|
456
|
-
|
|
456
|
+
spinner4.stop(`Found ${filtered.length} node(s) but none responded on HTTPS :4443.`);
|
|
457
457
|
throw new Error("Pass --server explicitly if the hub uses a non-default port.");
|
|
458
458
|
}
|
|
459
|
-
|
|
459
|
+
spinner4.stop(`Hub: ${hub.nodeID} @ https://${hub.address}:${hub.port}`);
|
|
460
460
|
return `https://${hub.address}:${hub.port}`;
|
|
461
461
|
}
|
|
462
|
-
const
|
|
463
|
-
|
|
462
|
+
const spinner3 = clack.spinner();
|
|
463
|
+
spinner3.start("Scanning LAN for camstack nodes (UDP multicast)");
|
|
464
464
|
const all = await discoverNodes({});
|
|
465
465
|
if (all.length === 0) {
|
|
466
|
-
|
|
466
|
+
spinner3.stop("No camstack nodes responded on LAN.");
|
|
467
467
|
throw new Error("Either pass --server or verify the hub is running on the same network.");
|
|
468
468
|
}
|
|
469
|
-
|
|
469
|
+
spinner3.stop(`Found ${all.length} node(s).`);
|
|
470
470
|
const chosen = await askSelect(
|
|
471
471
|
"Select a hub to log into",
|
|
472
472
|
all.map((n) => ({
|
|
@@ -571,8 +571,8 @@ async function logoutCommand(opts) {
|
|
|
571
571
|
return;
|
|
572
572
|
}
|
|
573
573
|
clack.intro("camstack logout");
|
|
574
|
-
const
|
|
575
|
-
|
|
574
|
+
const spinner3 = clack.spinner();
|
|
575
|
+
spinner3.start(`Revoking token on ${session.server}`);
|
|
576
576
|
try {
|
|
577
577
|
await callTrpcMutation(
|
|
578
578
|
`${session.server}/trpc/userManagement.revokeScopedToken?batch=1`,
|
|
@@ -580,9 +580,9 @@ async function logoutCommand(opts) {
|
|
|
580
580
|
{ id: session.tokenId },
|
|
581
581
|
isUnknown
|
|
582
582
|
);
|
|
583
|
-
|
|
583
|
+
spinner3.stop("Token revoked server-side.");
|
|
584
584
|
} catch (err) {
|
|
585
|
-
|
|
585
|
+
spinner3.stop(`Server-side revoke failed (${err instanceof Error ? err.message : String(err)}). Removing local cache anyway.`);
|
|
586
586
|
}
|
|
587
587
|
clearSession(session.server);
|
|
588
588
|
clack.outro(`\u2713 Logged out of ${session.server}`);
|
|
@@ -601,6 +601,11 @@ function whoamiCommand(opts) {
|
|
|
601
601
|
console.log(` createdAt: ${new Date(session.createdAt).toISOString()}`);
|
|
602
602
|
}
|
|
603
603
|
|
|
604
|
+
// src/commands/update.ts
|
|
605
|
+
import { parseArgs as parseArgs4 } from "util";
|
|
606
|
+
import { spawn } from "child_process";
|
|
607
|
+
import * as clack2 from "@clack/prompts";
|
|
608
|
+
|
|
604
609
|
// src/update-notifier.ts
|
|
605
610
|
import * as fs4 from "fs";
|
|
606
611
|
import * as path4 from "path";
|
|
@@ -700,6 +705,91 @@ function printBanner(pkgName, current, latest) {
|
|
|
700
705
|
process.stderr.write(lines.join("\n"));
|
|
701
706
|
}
|
|
702
707
|
|
|
708
|
+
// src/commands/update.ts
|
|
709
|
+
function isRunningViaNpx() {
|
|
710
|
+
const entry = process.argv[1] ?? "";
|
|
711
|
+
return entry.includes("/_npx/") || entry.includes("\\_npx\\");
|
|
712
|
+
}
|
|
713
|
+
function runNpmInstall(spec) {
|
|
714
|
+
return new Promise((resolve3, reject) => {
|
|
715
|
+
const proc = spawn("npm", ["install", "-g", spec], { stdio: "inherit" });
|
|
716
|
+
proc.on("exit", (code) => {
|
|
717
|
+
if (code === 0) resolve3();
|
|
718
|
+
else reject(new Error(`npm install -g ${spec} exited with code ${code}`));
|
|
719
|
+
});
|
|
720
|
+
proc.on("error", reject);
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
async function runUpdate(args) {
|
|
724
|
+
const { values } = parseArgs4({
|
|
725
|
+
args: [...args],
|
|
726
|
+
options: {
|
|
727
|
+
version: { type: "string", short: "V" },
|
|
728
|
+
yes: { type: "boolean", short: "y" }
|
|
729
|
+
},
|
|
730
|
+
strict: true,
|
|
731
|
+
allowPositionals: false
|
|
732
|
+
});
|
|
733
|
+
const pinnedVersion = typeof values.version === "string" ? values.version : void 0;
|
|
734
|
+
const skipConfirm = values.yes === true;
|
|
735
|
+
if (isRunningViaNpx()) {
|
|
736
|
+
console.log("You are running via npx \u2014 versions are fetched per-invocation.");
|
|
737
|
+
console.log("Just call `npx camstack@latest <cmd>` for the freshest release.");
|
|
738
|
+
console.log("To install globally: `npm install -g camstack@latest`");
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
clack2.intro("camstack update");
|
|
742
|
+
let target;
|
|
743
|
+
if (pinnedVersion) {
|
|
744
|
+
target = pinnedVersion;
|
|
745
|
+
} else {
|
|
746
|
+
const spinner3 = clack2.spinner();
|
|
747
|
+
spinner3.start("Checking npm registry");
|
|
748
|
+
const latest = await fetchLatestVersion("camstack");
|
|
749
|
+
if (!latest) {
|
|
750
|
+
spinner3.stop("Could not reach the npm registry.");
|
|
751
|
+
throw new Error("Network error \u2014 try again or pass --version <x.y.z>");
|
|
752
|
+
}
|
|
753
|
+
spinner3.stop(`Latest published: ${latest}`);
|
|
754
|
+
target = latest;
|
|
755
|
+
}
|
|
756
|
+
const { createRequire: createRequire2 } = await import("module");
|
|
757
|
+
const { fileURLToPath: fileURLToPath2 } = await import("url");
|
|
758
|
+
const { dirname: dirname2, resolve: resolve3 } = await import("path");
|
|
759
|
+
const require3 = createRequire2(import.meta.url);
|
|
760
|
+
const here = dirname2(fileURLToPath2(import.meta.url));
|
|
761
|
+
let current = "0.0.0";
|
|
762
|
+
try {
|
|
763
|
+
const pkg = require3(resolve3(here, "..", "package.json"));
|
|
764
|
+
current = pkg.version;
|
|
765
|
+
} catch {
|
|
766
|
+
}
|
|
767
|
+
if (current === target && !pinnedVersion) {
|
|
768
|
+
clack2.outro(`Already at ${current} \u2014 no update needed.`);
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
clack2.log.info(`Current: ${current} \u2192 Target: ${target}`);
|
|
772
|
+
if (!skipConfirm) {
|
|
773
|
+
const ok = await clack2.confirm({
|
|
774
|
+
message: `Install camstack@${target} globally with npm?`,
|
|
775
|
+
initialValue: true
|
|
776
|
+
});
|
|
777
|
+
if (clack2.isCancel(ok) || ok === false) {
|
|
778
|
+
clack2.cancel("Cancelled.");
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
console.log("");
|
|
783
|
+
try {
|
|
784
|
+
await runNpmInstall(`camstack@${target}`);
|
|
785
|
+
} catch (err) {
|
|
786
|
+
clack2.log.error(err instanceof Error ? err.message : String(err));
|
|
787
|
+
clack2.log.warn("If you see EACCES, your global npm prefix may need sudo or a different prefix. See https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally");
|
|
788
|
+
throw err;
|
|
789
|
+
}
|
|
790
|
+
clack2.outro(`\u2713 Installed camstack@${target}. Verify with: camstack --version`);
|
|
791
|
+
}
|
|
792
|
+
|
|
703
793
|
// src/cli.ts
|
|
704
794
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
705
795
|
var require2 = createRequire(import.meta.url);
|
|
@@ -852,6 +942,23 @@ function buildCommands() {
|
|
|
852
942
|
" -c, --cluster Push to hub + every online agent (requires admin token)"
|
|
853
943
|
].join("\n")
|
|
854
944
|
},
|
|
945
|
+
{
|
|
946
|
+
name: "update",
|
|
947
|
+
aliases: ["upgrade"],
|
|
948
|
+
summary: "Self-upgrade \u2014 runs `npm install -g camstack@latest`",
|
|
949
|
+
run: runUpdate,
|
|
950
|
+
help: () => [
|
|
951
|
+
"Usage: camstack update [options]",
|
|
952
|
+
" camstack upgrade [options] (alias)",
|
|
953
|
+
"",
|
|
954
|
+
"With no flags: fetches the latest version from npm, confirms,",
|
|
955
|
+
" then runs `npm install -g camstack@<latest>`.",
|
|
956
|
+
"",
|
|
957
|
+
"Options:",
|
|
958
|
+
" -V, --version <x.y.z> Install a specific version (pin/downgrade)",
|
|
959
|
+
" -y, --yes Skip confirmation (useful for scripts)"
|
|
960
|
+
].join("\n")
|
|
961
|
+
},
|
|
855
962
|
{
|
|
856
963
|
name: "info",
|
|
857
964
|
summary: "Print detailed version and platform info",
|
|
@@ -868,7 +975,7 @@ function buildCommands() {
|
|
|
868
975
|
}
|
|
869
976
|
function parseSubcommandArgs(args, options, allowPositionals) {
|
|
870
977
|
if (args.some((a) => HELP_FLAGS.has(a))) return null;
|
|
871
|
-
const parsed =
|
|
978
|
+
const parsed = parseArgs5({
|
|
872
979
|
args: [...args],
|
|
873
980
|
options,
|
|
874
981
|
allowPositionals,
|
|
@@ -972,6 +1079,9 @@ function optionalString(values, key, outKey) {
|
|
|
972
1079
|
return { [outKey ?? key]: v };
|
|
973
1080
|
}
|
|
974
1081
|
async function main() {
|
|
1082
|
+
if (!process.env.CAMSTACK_STRICT_TLS) {
|
|
1083
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
1084
|
+
}
|
|
975
1085
|
maybeNotifyUpdate("camstack", pkgVersion);
|
|
976
1086
|
const argv = process.argv.slice(2);
|
|
977
1087
|
const commands = buildCommands();
|