quiver-cli 0.5.0 → 0.6.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/cli.js CHANGED
@@ -9,15 +9,23 @@ var __export = (target, all) => {
9
9
  };
10
10
 
11
11
  // src/ui/prompts.ts
12
- var clackPromise, loadClack, QUIVER_ART, TAGLINE, colorEnabled, palette, block, banner, outro, step, info, success, warn, error, password, selectGrouped, selectGroupedText;
12
+ var clackPromise, warnedClackUnavailable, loadClack, QUIVER_ART, TAGLINE, colorEnabled, palette, block, banner, outro, step, info, success, warn, error, password, selectGrouped, selectGroupedText;
13
13
  var init_prompts = __esm({
14
14
  "src/ui/prompts.ts"() {
15
15
  "use strict";
16
+ warnedClackUnavailable = false;
16
17
  loadClack = async () => {
17
18
  if (clackPromise === void 0) {
18
19
  clackPromise = import("@clack/prompts").catch(() => null);
19
20
  }
20
- return clackPromise;
21
+ const clack = await clackPromise;
22
+ if (!clack && !warnedClackUnavailable) {
23
+ warnedClackUnavailable = true;
24
+ console.warn(
25
+ " Interactive menu unavailable (could not load @clack/prompts). This usually means Node < 20.12 - upgrade Node for the full UI. Falling back to plain text input."
26
+ );
27
+ }
28
+ return clack;
21
29
  };
22
30
  QUIVER_ART = [
23
31
  " ___ _ ",
@@ -184,6 +192,46 @@ Enter numbers (comma-separated), 'all', or 'none' [${preselected || "none"}]: `,
184
192
  }
185
193
  });
186
194
 
195
+ // src/version/node-guard.ts
196
+ var node_guard_exports = {};
197
+ __export(node_guard_exports, {
198
+ INTERACTIVE_COMMANDS: () => INTERACTIVE_COMMANDS,
199
+ MIN_NODE: () => MIN_NODE,
200
+ checkNodeForCommand: () => checkNodeForCommand,
201
+ isBelow: () => isBelow
202
+ });
203
+ var MIN_NODE, INTERACTIVE_COMMANDS, parse, isBelow, checkNodeForCommand;
204
+ var init_node_guard = __esm({
205
+ "src/version/node-guard.ts"() {
206
+ "use strict";
207
+ MIN_NODE = "20.12.0";
208
+ INTERACTIVE_COMMANDS = /* @__PURE__ */ new Set(["init", "add", "remove", "rm"]);
209
+ parse = (v) => {
210
+ const [major = 0, minor = 0, patch = 0] = v.replace(/^v/, "").split(".").map((p) => Number.parseInt(p, 10) || 0);
211
+ return [major, minor, patch];
212
+ };
213
+ isBelow = (current, min) => {
214
+ const a = parse(current);
215
+ const b = parse(min);
216
+ for (let i = 0; i < 3; i += 1) {
217
+ if (a[i] < b[i]) return true;
218
+ if (a[i] > b[i]) return false;
219
+ }
220
+ return false;
221
+ };
222
+ checkNodeForCommand = (command, nodeVersion = process.versions.node) => {
223
+ if (!INTERACTIVE_COMMANDS.has(command)) return { ok: true };
224
+ if (!isBelow(nodeVersion, MIN_NODE)) return { ok: true };
225
+ return {
226
+ ok: false,
227
+ message: `quiver-cli "${command}" needs Node >= ${MIN_NODE} for its interactive menu, but you are on v${nodeVersion}.
228
+ Upgrade Node (e.g. \`nvm install 24 && nvm use 24\`), then retry.
229
+ Or run non-interactively with --all to keep everything without prompts.`
230
+ };
231
+ };
232
+ }
233
+ });
234
+
187
235
  // src/catalog/digest.ts
188
236
  import { createHash } from "crypto";
189
237
  import { readdirSync, readFileSync, statSync } from "fs";
@@ -1562,7 +1610,10 @@ var init_init = __esm({
1562
1610
  `Source of truth is gitignored: ${ignored.join(", ")}. Remove those .gitignore entries - a fresh clone would miss them.`
1563
1611
  );
1564
1612
  }
1565
- const envVars = collectEnvVars(catalog.config.mcpServers ?? {});
1613
+ const selectedServers = Object.fromEntries(
1614
+ catalog.mcp.filter((m) => selection.mcp.includes(m.name)).map((m) => [m.name, m.server])
1615
+ );
1616
+ const envVars = collectEnvVars(selectedServers);
1566
1617
  if (envVars.length) {
1567
1618
  await info(
1568
1619
  `MCP secrets needed: ${envVars.join(", ")} - fill them in .env.local (template: .env.local.example)`
@@ -3008,14 +3059,14 @@ var init_notifier = __esm({
3008
3059
  }
3009
3060
  };
3010
3061
  compareSemver = (a, b) => {
3011
- const parse2 = (v) => {
3062
+ const parse3 = (v) => {
3012
3063
  const [core = "", ...preParts] = v.replace(/^v/, "").split("-");
3013
3064
  const nums = core.split(".").map((n) => Number.parseInt(n, 10) || 0);
3014
3065
  while (nums.length < 3) nums.push(0);
3015
3066
  return { nums, pre: preParts.length > 0 };
3016
3067
  };
3017
- const pa = parse2(a);
3018
- const pb = parse2(b);
3068
+ const pa = parse3(a);
3069
+ const pb = parse3(b);
3019
3070
  for (let i = 0; i < 3; i += 1) {
3020
3071
  const da = pa.nums[i] ?? 0;
3021
3072
  const db = pb.nums[i] ?? 0;
@@ -3113,7 +3164,7 @@ Options:
3113
3164
  --introspect-stdio Allow introspecting stdio MCP servers (runs foreign code)
3114
3165
  -v, --version Show the quiver-cli version
3115
3166
  `;
3116
- var parse = (argv) => {
3167
+ var parse2 = (argv) => {
3117
3168
  const [command = "init", ...rest] = argv;
3118
3169
  const flags = new Set(rest.filter((a) => a.startsWith("-")));
3119
3170
  const positionals = rest.filter((a) => !a.startsWith("-"));
@@ -3136,7 +3187,16 @@ var parse = (argv) => {
3136
3187
  };
3137
3188
  };
3138
3189
  var run = async () => {
3139
- const { command, options } = parse(process4.argv.slice(2));
3190
+ const { command, options } = parse2(process4.argv.slice(2));
3191
+ if (process4.stdin.isTTY && !options.all) {
3192
+ const { checkNodeForCommand: checkNodeForCommand2 } = await Promise.resolve().then(() => (init_node_guard(), node_guard_exports));
3193
+ const guard = checkNodeForCommand2(command);
3194
+ if (!guard.ok) {
3195
+ await error(guard.message);
3196
+ process4.exitCode = 1;
3197
+ return;
3198
+ }
3199
+ }
3140
3200
  switch (command) {
3141
3201
  case "init": {
3142
3202
  const { init: init2 } = await Promise.resolve().then(() => (init_init(), init_exports));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quiver-cli",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Compose a selected subset of skills, commands & MCP servers from a central catalog into any repo as native configs for opencode, Claude Code and Codex - with lockfile-based drift awareness.",
5
5
  "type": "module",
6
6
  "bin": {