@novastorm-ai/cli 0.0.4 → 0.0.6
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/nova.js
CHANGED
|
@@ -105,16 +105,42 @@ var TeamDetector = class {
|
|
|
105
105
|
}
|
|
106
106
|
};
|
|
107
107
|
var FREE_DEV_LIMIT = 3;
|
|
108
|
-
var
|
|
108
|
+
var NOVA_KEY_PATTERN = /^NOVA-([A-Z0-9]+)-([a-f0-9]{4})$/;
|
|
109
|
+
var NA_KEY_PATTERN = /^NA-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}$/;
|
|
110
|
+
var VALIDATE_ENDPOINT = "https://cli-api.novastorm.ai/v1/license/validate";
|
|
111
|
+
var TIMEOUT_MS = 5e3;
|
|
109
112
|
function computeChecksum(base32Body) {
|
|
110
113
|
return createHash("sha256").update(base32Body).digest("hex").slice(0, 4);
|
|
111
114
|
}
|
|
112
|
-
function
|
|
113
|
-
|
|
115
|
+
function validateKeyFormat(key) {
|
|
116
|
+
if (NA_KEY_PATTERN.test(key)) return true;
|
|
117
|
+
const match = NOVA_KEY_PATTERN.exec(key);
|
|
114
118
|
if (!match) return false;
|
|
115
119
|
const [, body, checksum] = match;
|
|
116
120
|
return computeChecksum(body) === checksum;
|
|
117
121
|
}
|
|
122
|
+
async function validateKeyOnline(key, devCount) {
|
|
123
|
+
try {
|
|
124
|
+
const controller = new AbortController();
|
|
125
|
+
const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
126
|
+
try {
|
|
127
|
+
const response = await fetch(VALIDATE_ENDPOINT, {
|
|
128
|
+
method: "POST",
|
|
129
|
+
headers: { "Content-Type": "application/json" },
|
|
130
|
+
body: JSON.stringify({ licenseKey: key, gitAuthors90d: devCount }),
|
|
131
|
+
signal: controller.signal
|
|
132
|
+
});
|
|
133
|
+
if (response.ok) {
|
|
134
|
+
return await response.json();
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
} finally {
|
|
138
|
+
clearTimeout(timeout);
|
|
139
|
+
}
|
|
140
|
+
} catch {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
118
144
|
var LicenseChecker = class {
|
|
119
145
|
teamDetector = new TeamDetector();
|
|
120
146
|
async check(projectPath, _config) {
|
|
@@ -129,27 +155,46 @@ var LicenseChecker = class {
|
|
|
129
155
|
valid: false,
|
|
130
156
|
tier: "company",
|
|
131
157
|
devCount,
|
|
132
|
-
message: "Company license required: this project has more than 3 contributors. Set NOVA_LICENSE_KEY
|
|
158
|
+
message: "Company license required: this project has more than 3 contributors. Set NOVA_LICENSE_KEY or run: nova license activate <key>"
|
|
133
159
|
};
|
|
134
160
|
}
|
|
135
|
-
if (!
|
|
161
|
+
if (!validateKeyFormat(key)) {
|
|
136
162
|
return {
|
|
137
163
|
valid: false,
|
|
138
164
|
tier: "company",
|
|
139
165
|
devCount,
|
|
140
|
-
message: "Invalid license key format.
|
|
166
|
+
message: "Invalid license key format. Get a valid key at https://cli.novastorm.ai/#pricing"
|
|
141
167
|
};
|
|
142
168
|
}
|
|
169
|
+
const onlineResult = await validateKeyOnline(key, devCount);
|
|
170
|
+
if (onlineResult) {
|
|
171
|
+
if (!onlineResult.valid) {
|
|
172
|
+
return {
|
|
173
|
+
valid: false,
|
|
174
|
+
tier: "company",
|
|
175
|
+
devCount,
|
|
176
|
+
message: "License key is invalid or expired. Visit https://cli.novastorm.ai/#pricing"
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
if (onlineResult.maxDevs && devCount > onlineResult.maxDevs) {
|
|
180
|
+
return {
|
|
181
|
+
valid: false,
|
|
182
|
+
tier: "company",
|
|
183
|
+
devCount,
|
|
184
|
+
message: `Your license covers ${onlineResult.maxDevs} developers but your team has ${devCount}. Upgrade at https://cli.novastorm.ai/#pricing`
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
143
188
|
return { valid: true, tier: "company", devCount };
|
|
144
189
|
}
|
|
145
190
|
};
|
|
146
|
-
var TELEMETRY_ENDPOINT = "https://api.
|
|
147
|
-
var
|
|
191
|
+
var TELEMETRY_ENDPOINT = "https://cli-api.novastorm.ai/v1/telemetry";
|
|
192
|
+
var TIMEOUT_MS2 = 3e3;
|
|
148
193
|
var Telemetry = class {
|
|
149
194
|
async send(payload) {
|
|
150
195
|
try {
|
|
151
196
|
const controller = new AbortController();
|
|
152
|
-
const timeout = setTimeout(() => controller.abort(),
|
|
197
|
+
const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS2);
|
|
153
198
|
try {
|
|
154
199
|
const response = await fetch(TELEMETRY_ENDPOINT, {
|
|
155
200
|
method: "POST",
|
|
@@ -176,16 +221,16 @@ var NudgeRenderer = class {
|
|
|
176
221
|
case 0:
|
|
177
222
|
return null;
|
|
178
223
|
case 1:
|
|
179
|
-
return "Nova Architect is free for teams of 3 or fewer. Learn more: https://
|
|
224
|
+
return "Nova Architect is free for teams of 3 or fewer. Learn more: https://cli.novastorm.ai/#pricing";
|
|
180
225
|
case 2:
|
|
181
|
-
return `Your team has ${context.devCount} developers. A license is recommended. Visit https://
|
|
226
|
+
return `Your team has ${context.devCount} developers. A license is recommended. Visit https://cli.novastorm.ai/#pricing`;
|
|
182
227
|
case 3:
|
|
183
228
|
return [
|
|
184
229
|
"+-------------------------------------------------+",
|
|
185
230
|
"| License Required |",
|
|
186
231
|
`| Your team of ${String(context.devCount).padEnd(3)} developers needs a |`,
|
|
187
232
|
"| commercial license. |",
|
|
188
|
-
"| -> https://
|
|
233
|
+
"| -> https://cli.novastorm.ai/#pricing |",
|
|
189
234
|
"+-------------------------------------------------+"
|
|
190
235
|
].join("\n");
|
|
191
236
|
default:
|
|
@@ -882,13 +927,13 @@ async function startCommand() {
|
|
|
882
927
|
if (config.telemetry.enabled && process.env["NOVA_TELEMETRY"] !== "false") {
|
|
883
928
|
const { createHash: createHash2 } = await import("crypto");
|
|
884
929
|
const os = await import("os");
|
|
885
|
-
const { execFile:
|
|
930
|
+
const { execFile: execFile3 } = await import("child_process");
|
|
886
931
|
const mac = Object.values(os.networkInterfaces()).flat().find((i) => !i?.internal && i?.mac !== "00:00:00:00:00:00")?.mac ?? "";
|
|
887
932
|
const machineId = createHash2("sha256").update(os.hostname() + os.userInfo().username + mac).digest("hex");
|
|
888
933
|
let projectHash;
|
|
889
934
|
try {
|
|
890
935
|
const remoteUrl = await new Promise((resolve4, reject) => {
|
|
891
|
-
|
|
936
|
+
execFile3("git", ["remote", "get-url", "origin"], { cwd }, (err, stdout3) => {
|
|
892
937
|
if (err) reject(err);
|
|
893
938
|
else resolve4(stdout3.trim());
|
|
894
939
|
});
|
|
@@ -898,7 +943,7 @@ async function startCommand() {
|
|
|
898
943
|
projectHash = createHash2("sha256").update(cwd).digest("hex");
|
|
899
944
|
}
|
|
900
945
|
const telemetry = new Telemetry();
|
|
901
|
-
const cliPkg = await import("./package-
|
|
946
|
+
const cliPkg = await import("./package-6R6RECMI.js").catch(
|
|
902
947
|
() => ({ default: { version: "0.0.1" } })
|
|
903
948
|
);
|
|
904
949
|
telemetry.send({
|
|
@@ -1573,9 +1618,9 @@ async function watchCommand() {
|
|
|
1573
1618
|
|
|
1574
1619
|
// src/commands/license.ts
|
|
1575
1620
|
import chalk7 from "chalk";
|
|
1576
|
-
var
|
|
1577
|
-
var
|
|
1578
|
-
var
|
|
1621
|
+
var KEY_PATTERN = /^NOVA-([A-Z2-7]+)-([a-f0-9]{4})$/;
|
|
1622
|
+
var VALIDATE_ENDPOINT2 = "https://cli-api.novastorm.ai/v1/license/validate";
|
|
1623
|
+
var TIMEOUT_MS3 = 5e3;
|
|
1579
1624
|
async function licenseCommand(subcommand, key) {
|
|
1580
1625
|
const cwd = process.cwd();
|
|
1581
1626
|
const configReader = new ConfigReader();
|
|
@@ -1621,7 +1666,7 @@ async function showStatus(cwd, config) {
|
|
|
1621
1666
|
console.log("");
|
|
1622
1667
|
}
|
|
1623
1668
|
async function activateKey(cwd, configReader, key) {
|
|
1624
|
-
if (!
|
|
1669
|
+
if (!KEY_PATTERN.test(key)) {
|
|
1625
1670
|
console.error(chalk7.red("Invalid key format. Expected: NOVA-{BASE32}-{CHECKSUM}"));
|
|
1626
1671
|
process.exit(1);
|
|
1627
1672
|
}
|
|
@@ -1629,9 +1674,9 @@ async function activateKey(cwd, configReader, key) {
|
|
|
1629
1674
|
let serverValid = true;
|
|
1630
1675
|
try {
|
|
1631
1676
|
const controller = new AbortController();
|
|
1632
|
-
const timeout = setTimeout(() => controller.abort(),
|
|
1677
|
+
const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS3);
|
|
1633
1678
|
try {
|
|
1634
|
-
const response = await fetch(
|
|
1679
|
+
const response = await fetch(VALIDATE_ENDPOINT2, {
|
|
1635
1680
|
method: "POST",
|
|
1636
1681
|
headers: { "Content-Type": "application/json" },
|
|
1637
1682
|
body: JSON.stringify({ key }),
|
|
@@ -1968,6 +2013,88 @@ async function bibleCommand(subcommand) {
|
|
|
1968
2013
|
}
|
|
1969
2014
|
}
|
|
1970
2015
|
|
|
2016
|
+
// src/commands/update.ts
|
|
2017
|
+
import { execFile as execFile2 } from "child_process";
|
|
2018
|
+
import chalk10 from "chalk";
|
|
2019
|
+
import ora3 from "ora";
|
|
2020
|
+
var PKG_NAME = "@novastorm-ai/cli";
|
|
2021
|
+
async function getLatestVersion() {
|
|
2022
|
+
try {
|
|
2023
|
+
const controller = new AbortController();
|
|
2024
|
+
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
2025
|
+
try {
|
|
2026
|
+
const res = await fetch(`https://registry.npmjs.org/${PKG_NAME}/latest`, {
|
|
2027
|
+
signal: controller.signal
|
|
2028
|
+
});
|
|
2029
|
+
if (res.ok) {
|
|
2030
|
+
const data = await res.json();
|
|
2031
|
+
return data.version;
|
|
2032
|
+
}
|
|
2033
|
+
return null;
|
|
2034
|
+
} finally {
|
|
2035
|
+
clearTimeout(timeout);
|
|
2036
|
+
}
|
|
2037
|
+
} catch {
|
|
2038
|
+
return null;
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
function runNpmInstall() {
|
|
2042
|
+
return new Promise((resolve4) => {
|
|
2043
|
+
execFile2("npm", ["install", "-g", `${PKG_NAME}@latest`], { timeout: 6e4 }, (error, stdout3, stderr) => {
|
|
2044
|
+
if (error) {
|
|
2045
|
+
resolve4({ ok: false, output: stderr || error.message });
|
|
2046
|
+
} else {
|
|
2047
|
+
resolve4({ ok: true, output: stdout3 });
|
|
2048
|
+
}
|
|
2049
|
+
});
|
|
2050
|
+
});
|
|
2051
|
+
}
|
|
2052
|
+
async function updateCommand() {
|
|
2053
|
+
const spinner = ora3("Checking for updates...").start();
|
|
2054
|
+
const latest = await getLatestVersion();
|
|
2055
|
+
if (!latest) {
|
|
2056
|
+
spinner.fail("Could not reach npm registry. Check your internet connection.");
|
|
2057
|
+
return;
|
|
2058
|
+
}
|
|
2059
|
+
const { readFileSync: readFileSync2 } = await import("fs");
|
|
2060
|
+
const { dirname: dirname2, resolve: resolve4 } = await import("path");
|
|
2061
|
+
const { fileURLToPath: fileURLToPath2 } = await import("url");
|
|
2062
|
+
const __dirname2 = dirname2(fileURLToPath2(import.meta.url));
|
|
2063
|
+
let currentVersion = "0.0.0";
|
|
2064
|
+
try {
|
|
2065
|
+
const pkg2 = JSON.parse(readFileSync2(resolve4(__dirname2, "..", "package.json"), "utf-8"));
|
|
2066
|
+
currentVersion = pkg2.version;
|
|
2067
|
+
} catch {
|
|
2068
|
+
}
|
|
2069
|
+
if (currentVersion === latest) {
|
|
2070
|
+
spinner.succeed(`Already on the latest version ${chalk10.green(latest)}`);
|
|
2071
|
+
return;
|
|
2072
|
+
}
|
|
2073
|
+
spinner.text = `Updating ${chalk10.gray(currentVersion)} \u2192 ${chalk10.green(latest)}...`;
|
|
2074
|
+
const result = await runNpmInstall();
|
|
2075
|
+
if (result.ok) {
|
|
2076
|
+
spinner.succeed(`Updated to ${chalk10.green(latest)}`);
|
|
2077
|
+
} else {
|
|
2078
|
+
spinner.fail("Update failed. Try manually:");
|
|
2079
|
+
console.log(chalk10.cyan(` npm install -g ${PKG_NAME}@latest`));
|
|
2080
|
+
if (result.output) {
|
|
2081
|
+
console.log(chalk10.gray(result.output.trim()));
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
async function checkForUpdates(currentVersion) {
|
|
2086
|
+
try {
|
|
2087
|
+
const latest = await getLatestVersion();
|
|
2088
|
+
if (latest && latest !== currentVersion) {
|
|
2089
|
+
console.log(
|
|
2090
|
+
chalk10.yellow(` Update available: ${chalk10.gray(currentVersion)} \u2192 ${chalk10.green(latest)}`) + chalk10.gray(` Run ${chalk10.cyan("nova update")} to install
|
|
2091
|
+
`)
|
|
2092
|
+
);
|
|
2093
|
+
}
|
|
2094
|
+
} catch {
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
|
|
1971
2098
|
// src/index.ts
|
|
1972
2099
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
1973
2100
|
var pkg = JSON.parse(
|
|
@@ -2028,6 +2155,9 @@ function createCli() {
|
|
|
2028
2155
|
program.command("bible [subcommand]").description("Read the Ambient Development manifesto: nova bible [--read]").action(async (subcommand) => {
|
|
2029
2156
|
await bibleCommand(subcommand);
|
|
2030
2157
|
});
|
|
2158
|
+
program.command("update").description("Update Novastorm CLI to the latest version").action(async () => {
|
|
2159
|
+
await updateCommand();
|
|
2160
|
+
});
|
|
2031
2161
|
return program;
|
|
2032
2162
|
}
|
|
2033
2163
|
var BANNER = `\x1B[96m
|
|
@@ -2040,12 +2170,15 @@ var BANNER = `\x1B[96m
|
|
|
2040
2170
|
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
2041
2171
|
\u2551 A M B I E N T D E V E L O P M E N T T O O L \u2551
|
|
2042
2172
|
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
2043
|
-
\x1B[0m
|
|
2173
|
+
\x1B[0m\x1B[90m https://cli.novastorm.ai\x1B[0m
|
|
2174
|
+
`;
|
|
2044
2175
|
async function run(argv = process.argv) {
|
|
2045
2176
|
const args = argv.slice(2);
|
|
2046
2177
|
const suppressBanner = args.includes("--version") || args.includes("-V") || args.includes("--help") || args.includes("-h");
|
|
2047
2178
|
if (!suppressBanner) {
|
|
2048
2179
|
console.log(BANNER);
|
|
2180
|
+
checkForUpdates(pkg.version).catch(() => {
|
|
2181
|
+
});
|
|
2049
2182
|
}
|
|
2050
2183
|
const program = createCli();
|
|
2051
2184
|
await program.parseAsync(argv);
|
package/dist/index.js
CHANGED