@nolto/cli 0.4.0 → 0.5.0
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/index.js +117 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { createRequire as createRequire2 } from "module";
|
|
5
5
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6
|
-
import
|
|
6
|
+
import path8 from "path";
|
|
7
7
|
import { CommanderError } from "commander";
|
|
8
8
|
|
|
9
9
|
// src/config.ts
|
|
@@ -503,11 +503,11 @@ function createHttpClient(opts) {
|
|
|
503
503
|
const { baseUrl, version, token } = opts;
|
|
504
504
|
const base = baseUrl.replace(/\/+$/, "");
|
|
505
505
|
return {
|
|
506
|
-
async post(
|
|
507
|
-
if (!
|
|
508
|
-
throw new CliError(`HTTP client path must start with /api/, got: ${
|
|
506
|
+
async post(path9, body) {
|
|
507
|
+
if (!path9.startsWith("/api/")) {
|
|
508
|
+
throw new CliError(`HTTP client path must start with /api/, got: ${path9}`, 2);
|
|
509
509
|
}
|
|
510
|
-
const url = `${base}${
|
|
510
|
+
const url = `${base}${path9}`;
|
|
511
511
|
const headers = {
|
|
512
512
|
"Content-Type": "application/json",
|
|
513
513
|
"User-Agent": `${CLI_USER_AGENT_NAME}/${version}`
|
|
@@ -709,10 +709,7 @@ async function injectClaude(opts) {
|
|
|
709
709
|
nolto: {
|
|
710
710
|
url: mcpUrl,
|
|
711
711
|
headers: {
|
|
712
|
-
Authorization:
|
|
713
|
-
},
|
|
714
|
-
env: {
|
|
715
|
-
NOLTO_MCP_TOKEN: opts.token
|
|
712
|
+
Authorization: "Bearer ${NOLTO_MCP_TOKEN}"
|
|
716
713
|
}
|
|
717
714
|
}
|
|
718
715
|
};
|
|
@@ -721,7 +718,14 @@ async function injectClaude(opts) {
|
|
|
721
718
|
mcpServers: updatedServers
|
|
722
719
|
};
|
|
723
720
|
await atomicWrite(configPath, JSON.stringify(newConfig, null, 2) + "\n", 384);
|
|
724
|
-
|
|
721
|
+
const tokensUrl = `${opts.baseUrl.replace(/\/+$/, "")}/settings/tokens`;
|
|
722
|
+
process.stdout.write(
|
|
723
|
+
`Updated ${configPath} (claude project .mcp.json) \u2014 uses the NOLTO_MCP_TOKEN env var; no token is stored in the file, so it is safe to commit.
|
|
724
|
+
`
|
|
725
|
+
);
|
|
726
|
+
process.stdout.write("Set NOLTO_MCP_TOKEN in your environment before launching Claude Code, e.g.:\n");
|
|
727
|
+
process.stdout.write(" export NOLTO_MCP_TOKEN=<your token>\n");
|
|
728
|
+
process.stdout.write(`Your token is saved in your nolto config (from this login); or create one at ${tokensUrl}
|
|
725
729
|
`);
|
|
726
730
|
}
|
|
727
731
|
async function injectCodex(opts) {
|
|
@@ -1998,10 +2002,10 @@ async function handleShow(deps, projectBindingPath, mode2) {
|
|
|
1998
2002
|
}
|
|
1999
2003
|
}
|
|
2000
2004
|
async function handleUnlink(projectBindingPath, mode2) {
|
|
2001
|
-
const { readFile:
|
|
2005
|
+
const { readFile: readFile6, writeFile: writeFile5, chmod } = await import("fs/promises");
|
|
2002
2006
|
let existing = {};
|
|
2003
2007
|
try {
|
|
2004
|
-
const raw = await
|
|
2008
|
+
const raw = await readFile6(projectBindingPath, "utf8");
|
|
2005
2009
|
const parsed = JSON.parse(raw);
|
|
2006
2010
|
if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2007
2011
|
throw new CliError(
|
|
@@ -2016,7 +2020,7 @@ async function handleUnlink(projectBindingPath, mode2) {
|
|
|
2016
2020
|
}
|
|
2017
2021
|
const { projectId: _removed, ...rest } = existing;
|
|
2018
2022
|
void _removed;
|
|
2019
|
-
await
|
|
2023
|
+
await writeFile5(projectBindingPath, JSON.stringify(rest, null, 2) + "\n", { mode: 420 });
|
|
2020
2024
|
await chmod(projectBindingPath, 420);
|
|
2021
2025
|
if (mode2 === "json") {
|
|
2022
2026
|
printResult({ unlinked: true, projectBindingPath }, mode2);
|
|
@@ -2119,12 +2123,109 @@ function buildProgram(deps) {
|
|
|
2119
2123
|
return program;
|
|
2120
2124
|
}
|
|
2121
2125
|
|
|
2126
|
+
// src/update-notifier.ts
|
|
2127
|
+
import { readFile as readFile5, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
|
|
2128
|
+
import https from "https";
|
|
2129
|
+
import path7 from "path";
|
|
2130
|
+
var PACKAGE = "@nolto/cli";
|
|
2131
|
+
var CACHE_FILE = "update-check.json";
|
|
2132
|
+
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2133
|
+
var REQUEST_TIMEOUT_MS = 2e3;
|
|
2134
|
+
function isNewerVersion(latest, current) {
|
|
2135
|
+
const parts = (v) => v.split("-")[0].split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
2136
|
+
const a = parts(latest);
|
|
2137
|
+
const b = parts(current);
|
|
2138
|
+
for (let i = 0; i < 3; i++) {
|
|
2139
|
+
const x = a[i] ?? 0;
|
|
2140
|
+
const y = b[i] ?? 0;
|
|
2141
|
+
if (x !== y) return x > y;
|
|
2142
|
+
}
|
|
2143
|
+
return false;
|
|
2144
|
+
}
|
|
2145
|
+
function formatUpdateNotice(latest, current) {
|
|
2146
|
+
return `
|
|
2147
|
+
Update available: ${current} \u2192 ${latest} \xB7 npm i -g @nolto/cli@latest
|
|
2148
|
+
`;
|
|
2149
|
+
}
|
|
2150
|
+
function isDisabled(env) {
|
|
2151
|
+
return env["NO_UPDATE_NOTIFIER"] === "1" || env["NODE_ENV"] === "test" || Boolean(env["CI"]);
|
|
2152
|
+
}
|
|
2153
|
+
function fetchLatestFromRegistry() {
|
|
2154
|
+
return new Promise((resolve) => {
|
|
2155
|
+
const req = https.get(
|
|
2156
|
+
`https://registry.npmjs.org/${PACKAGE}/latest`,
|
|
2157
|
+
{ timeout: REQUEST_TIMEOUT_MS, headers: { accept: "application/json" } },
|
|
2158
|
+
(res) => {
|
|
2159
|
+
if (res.statusCode !== 200) {
|
|
2160
|
+
res.resume();
|
|
2161
|
+
resolve(null);
|
|
2162
|
+
return;
|
|
2163
|
+
}
|
|
2164
|
+
let data = "";
|
|
2165
|
+
res.on("data", (chunk) => data += chunk);
|
|
2166
|
+
res.on("end", () => {
|
|
2167
|
+
try {
|
|
2168
|
+
const v = JSON.parse(data).version;
|
|
2169
|
+
resolve(typeof v === "string" ? v : null);
|
|
2170
|
+
} catch {
|
|
2171
|
+
resolve(null);
|
|
2172
|
+
}
|
|
2173
|
+
});
|
|
2174
|
+
}
|
|
2175
|
+
);
|
|
2176
|
+
req.on("socket", (s) => s.unref());
|
|
2177
|
+
req.on("timeout", () => {
|
|
2178
|
+
req.destroy();
|
|
2179
|
+
resolve(null);
|
|
2180
|
+
});
|
|
2181
|
+
req.on("error", () => resolve(null));
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2184
|
+
async function refreshCache(cachePath, now, fetchLatest) {
|
|
2185
|
+
const latest = await fetchLatest();
|
|
2186
|
+
if (!latest) return;
|
|
2187
|
+
await mkdir4(path7.dirname(cachePath), { recursive: true }).catch(() => void 0);
|
|
2188
|
+
const payload = { checkedAt: now, latest };
|
|
2189
|
+
await writeFile4(cachePath, JSON.stringify(payload), { mode: 384 }).catch(() => void 0);
|
|
2190
|
+
}
|
|
2191
|
+
async function checkForUpdate(opts) {
|
|
2192
|
+
if (isDisabled(opts.env)) return null;
|
|
2193
|
+
const cachePath = path7.join(opts.configDir, CACHE_FILE);
|
|
2194
|
+
let cache = {};
|
|
2195
|
+
try {
|
|
2196
|
+
cache = JSON.parse(await readFile5(cachePath, "utf8"));
|
|
2197
|
+
} catch {
|
|
2198
|
+
}
|
|
2199
|
+
if (typeof cache.checkedAt !== "number" || opts.now - cache.checkedAt > CACHE_TTL_MS) {
|
|
2200
|
+
void refreshCache(cachePath, opts.now, opts.fetchLatest ?? fetchLatestFromRegistry).catch(
|
|
2201
|
+
() => void 0
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
if (typeof cache.latest === "string" && isNewerVersion(cache.latest, opts.current)) {
|
|
2205
|
+
return cache.latest;
|
|
2206
|
+
}
|
|
2207
|
+
return null;
|
|
2208
|
+
}
|
|
2209
|
+
async function notifyUpdate(opts) {
|
|
2210
|
+
try {
|
|
2211
|
+
if (opts.isJson || !process.stderr.isTTY) return;
|
|
2212
|
+
const latest = await checkForUpdate({
|
|
2213
|
+
current: opts.current,
|
|
2214
|
+
configDir: getConfigDir(opts.env),
|
|
2215
|
+
env: opts.env,
|
|
2216
|
+
now: opts.now
|
|
2217
|
+
});
|
|
2218
|
+
if (latest) process.stderr.write(formatUpdateNotice(latest, opts.current));
|
|
2219
|
+
} catch {
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2122
2223
|
// src/index.ts
|
|
2123
|
-
var __dirname2 =
|
|
2224
|
+
var __dirname2 = path8.dirname(fileURLToPath2(import.meta.url));
|
|
2124
2225
|
var require2 = createRequire2(import.meta.url);
|
|
2125
2226
|
function getVersion() {
|
|
2126
2227
|
try {
|
|
2127
|
-
const pkgPath =
|
|
2228
|
+
const pkgPath = path8.resolve(__dirname2, "../package.json");
|
|
2128
2229
|
const pkg = require2(pkgPath);
|
|
2129
2230
|
return pkg.version ?? "0.0.0";
|
|
2130
2231
|
} catch {
|
|
@@ -2183,6 +2284,7 @@ async function main() {
|
|
|
2183
2284
|
};
|
|
2184
2285
|
const program = buildProgram({ caller, settings, output: { mode }, version, configPath, projectBindingPath });
|
|
2185
2286
|
await program.parseAsync(process.argv);
|
|
2287
|
+
await notifyUpdate({ current: version, env: process.env, isJson: mode === "json", now: Date.now() });
|
|
2186
2288
|
}
|
|
2187
2289
|
function extractFlag(argv, name) {
|
|
2188
2290
|
const idx = argv.indexOf(name);
|