higherdata 0.3.0 → 0.3.1

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.
Files changed (3) hide show
  1. package/README.md +30 -3
  2. package/dist/index.js +196 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -213,9 +213,8 @@ Formats follow the current [Claude Code MCP](https://code.claude.com/docs/en/mcp
213
213
  ## Compatibility
214
214
 
215
215
  The CLI reads public `/api/v1/meta` once per day per API origin and caches the
216
- policy beside its config file. Updates are announced on stderr so JSON output
217
- stays machine-readable. Versions below the server's minimum refuse commands
218
- with `npm install --global higherdata@latest` as the upgrade command. `login`,
216
+ policy beside its config file. Update notices are written to stderr only during interactive invocations.
217
+ Versions below the server's minimum refuse commands and suggest `higherdata update`. `update`, `login`,
219
218
  `--help` and `--version` remain available without a compatibility check.
220
219
 
221
220
  The metadata request times out after three seconds. On network failure the CLI
@@ -224,3 +223,31 @@ checks are cached for a day too. A read-only cache directory allows commands but
224
223
  cannot persist the daily check, so subsequent invocations may check again.
225
224
 
226
225
  Download the loaded search page to a new file with `higherdata search companies --country-code CA --out results.csv`. Add `--all` to download up to 5,000 rows, or use a `.jsonl` destination for JSON Lines. The interactive results screen offers "This page" and "All results" when you press `d`. For larger sets, save the search to a list and export the list. Existing files are never overwritten.
226
+
227
+ ## Updates
228
+
229
+ Run `higherdata update` (alias `higherdata upgrade`) to check npm and install the
230
+ latest stable release. The CLI installs the exact version it checked and prints
231
+ the old and new versions. A permission failure prints npm's error summary and
232
+ the manual command. It never retries with sudo.
233
+
234
+ Interactive npm global installs check npm on every run with a 1.5-second timeout, then
235
+ automatically install a newer release and restart the same command with the
236
+ same arguments. Failed installs print a manual command and continue on the
237
+ current version. Timeouts and network failures continue silently. There is no
238
+ cache for this npm release check.
239
+
240
+ Automatic updates are skipped when either stdin or stdout is not a TTY, `CI`
241
+ is set, `--json` or `--jsonl` is used, for MCP or stdio protocols, and for `npx`
242
+ or non-global installs. To opt out for an invocation, set
243
+ `HIGHERDATA_NO_AUTO_UPDATE=1`. To persist the preference, run:
244
+
245
+ ```sh
246
+ higherdata config set auto-update false
247
+ # Re-enable automatic updates
248
+ higherdata config set auto-update true
249
+ ```
250
+
251
+ Explicit `higherdata update` remains available with an opt-out or a server
252
+ minimum-version refusal. Users on 0.3.0 must reinstall once to obtain the update
253
+ command: `npm install --global higherdata@latest`.
package/dist/index.js CHANGED
@@ -20573,6 +20573,7 @@ var init_config = __esm({
20573
20573
  space: external_exports.string().min(1).optional()
20574
20574
  });
20575
20575
  configSchema = external_exports.strictObject({
20576
+ autoUpdate: external_exports.boolean().optional(),
20576
20577
  activeProfile: external_exports.string().min(1),
20577
20578
  profiles: external_exports.record(external_exports.string().min(1), profileSchema)
20578
20579
  }).refine((config2) => Object.hasOwn(config2.profiles, config2.activeProfile), {
@@ -20587,6 +20588,16 @@ var init_config = __esm({
20587
20588
  }
20588
20589
  });
20589
20590
 
20591
+ // ../../src/lib/ai/messages.ts
20592
+ var OWN_KEY_REQUIRED, OWN_KEY_REJECTED;
20593
+ var init_messages = __esm({
20594
+ "../../src/lib/ai/messages.ts"() {
20595
+ "use strict";
20596
+ OWN_KEY_REQUIRED = "Add your OpenRouter key in Settings to use AI features.";
20597
+ OWN_KEY_REJECTED = "Your OpenRouter key was rejected. Update it in Settings.";
20598
+ }
20599
+ });
20600
+
20590
20601
  // ../sdk/src/generated.ts
20591
20602
  var TOOL_CATALOG;
20592
20603
  var init_generated = __esm({
@@ -28312,6 +28323,7 @@ function apiFailure(status, data) {
28312
28323
  if (code === "limit_exceeded" && message && /^This month's email verification allowance is reached\. Resets \d{4}-\d{2}-\d{2}\. Upgrade: (https:\/\/[^\s]+|\/docs\/plans-and-limits)$/.test(message)) return new CliError(message, EXIT_CODES.LIMIT);
28313
28324
  if (status === 429 || code === "limit_exceeded") return new CliError("A HigherData limit was reached. Wait until the limit resets.", EXIT_CODES.LIMIT);
28314
28325
  if (code === "suppressed" || code === "suppressed_only") return new CliError("All requested records are suppressed.", EXIT_CODES.SUPPRESSED_ONLY);
28326
+ if (code === "ai_key_required" || code === "ai_key_rejected") return new CliError(code === "ai_key_required" ? OWN_KEY_REQUIRED : OWN_KEY_REJECTED);
28315
28327
  if (code === "needs_approval") return new CliError("This operation needs approval.", EXIT_CODES.NEEDS_APPROVAL);
28316
28328
  if (code === "jobs_unavailable") return new CliError("Background jobs are not configured for this deployment.");
28317
28329
  if (code === "invalid_input") return new CliError("The API rejected the input. Check the command's filters and identifiers.");
@@ -28322,6 +28334,7 @@ var CliError, object2, ApiClient;
28322
28334
  var init_api2 = __esm({
28323
28335
  "src/api.ts"() {
28324
28336
  "use strict";
28337
+ init_messages();
28325
28338
  init_src();
28326
28339
  init_zod();
28327
28340
  init_exit_codes();
@@ -28481,7 +28494,7 @@ async function checkCliVersion(input2) {
28481
28494
  }
28482
28495
  }
28483
28496
  if (!policy) return;
28484
- const upgrade = "npm install --global higherdata@latest";
28497
+ const upgrade = "higherdata update";
28485
28498
  if (compareVersions(input2.version, policy.minCliVersion) < 0) throw new CliError(`HigherData CLI ${input2.version} is no longer supported; minimum is ${policy.minCliVersion}. Upgrade: ${upgrade}`);
28486
28499
  if (compareVersions(input2.version, policy.latestCliVersion) < 0) input2.warn(`HigherData CLI ${policy.latestCliVersion} is available. Upgrade: ${upgrade}
28487
28500
  `);
@@ -31926,7 +31939,7 @@ var init_package = __esm({
31926
31939
  "package.json"() {
31927
31940
  package_default = {
31928
31941
  name: "higherdata",
31929
- version: "0.3.0",
31942
+ version: "0.3.1",
31930
31943
  type: "module",
31931
31944
  bin: {
31932
31945
  higherdata: "dist/index.js"
@@ -36832,11 +36845,11 @@ function parseTree(text2, errors2 = [], options = ParseOptions.DEFAULT) {
36832
36845
  onValue({ type: getNodeType(value), offset, length, parent: currentParent, value });
36833
36846
  ensurePropertyComplete(offset + length);
36834
36847
  },
36835
- onSeparator: (sep, offset, length) => {
36848
+ onSeparator: (sep2, offset, length) => {
36836
36849
  if (currentParent.type === "property") {
36837
- if (sep === ":") {
36850
+ if (sep2 === ":") {
36838
36851
  currentParent.colonOffset = offset;
36839
- } else if (sep === ",") {
36852
+ } else if (sep2 === ",") {
36840
36853
  ensurePropertyComplete(offset);
36841
36854
  }
36842
36855
  }
@@ -38079,6 +38092,7 @@ function recordFields(value, prefix = "") {
38079
38092
  if (!value || typeof value !== "object") return [[prefix || "Value", shownValue(value)]];
38080
38093
  return Object.entries(value).flatMap(([key, child]) => {
38081
38094
  if (internalCostKey(key) || child === void 0 || child === null && !["before", "after"].includes(key) || ["nextCursor", "requestId", "releaseId", "rawId", "warehouseId"].includes(key)) return [];
38095
+ if (key === "aiMode") return [["AI key", { byok: "Own key", platform: "Platform", none: "Not configured" }[String(child)] ?? "Unavailable"]];
38082
38096
  const name = prefix ? `${prefix} / ${title(key)}` : title(key);
38083
38097
  if (Array.isArray(child) && child.some((item) => item && typeof item === "object")) return child.flatMap((item, i) => recordFields(item, `${name} ${i + 1}`));
38084
38098
  if (child && typeof child === "object" && !Array.isArray(child)) return recordFields(child, name);
@@ -39441,8 +39455,158 @@ function registerSuppressCommands(program2, helpers) {
39441
39455
 
39442
39456
  // src/commands.ts
39443
39457
  init_install();
39458
+
39459
+ // src/update.ts
39460
+ init_zod();
39461
+ init_api2();
39462
+ init_version_policy();
39463
+ import { execFile as execFile3, spawn } from "child_process";
39464
+ import { realpath } from "fs/promises";
39465
+ import { isAbsolute, join as join4, sep } from "path";
39466
+ import { promisify as promisify2 } from "util";
39467
+ var NpmUpdateError = class extends Error {
39468
+ };
39469
+ function npmSummary(error63) {
39470
+ const value = error63;
39471
+ const lines = typeof value?.stderr === "string" ? value.stderr.split(/\r?\n/u) : [];
39472
+ const line = lines.find((line2) => /^npm (?:error|ERR!) code [A-Z0-9_]+$/u.test(line2.trim())) ?? lines.find((line2) => /^npm (?:error|ERR!) (?:EACCES|EPERM|ENOENT|ETIMEDOUT)\b/u.test(line2.trim()));
39473
+ return line?.trim().slice(0, 200) ?? (typeof value?.code === "string" && /^[A-Z0-9_]+$/u.test(value.code) ? value.code : "npm install failed");
39474
+ }
39475
+ function updateRuntime() {
39476
+ return {
39477
+ stdinTTY: Boolean(process.stdin.isTTY),
39478
+ stdoutTTY: Boolean(process.stdout.isTTY),
39479
+ script: process.argv[1] ?? "",
39480
+ realpath,
39481
+ async npm(args, env) {
39482
+ try {
39483
+ return (await promisify2(execFile3)("npm", args, { env, timeout: args[0] === "install" ? 12e4 : 1500, maxBuffer: 64 * 1024 })).stdout;
39484
+ } catch (error63) {
39485
+ throw new NpmUpdateError(npmSummary(error63));
39486
+ }
39487
+ },
39488
+ rerun(script, args, env) {
39489
+ return new Promise((resolve2, reject) => {
39490
+ const child = spawn(process.execPath, [script, ...args], { env, stdio: "inherit" });
39491
+ child.once("error", reject);
39492
+ child.once("exit", (code, signal) => resolve2(code ?? (signal === "SIGINT" ? 130 : signal === "SIGTERM" ? 143 : 1)));
39493
+ });
39494
+ }
39495
+ };
39496
+ }
39497
+ async function npmLatest(fetchImpl, timeoutMs = 3e3) {
39498
+ try {
39499
+ const response = await fetchImpl("https://registry.npmjs.org/higherdata/latest", { headers: { accept: "application/json" }, redirect: "error", signal: AbortSignal.timeout(timeoutMs) });
39500
+ if (!response.ok || !response.body) {
39501
+ await response.body?.cancel();
39502
+ throw new Error();
39503
+ }
39504
+ const reader = response.body.getReader(), chunks = [];
39505
+ let size = 0;
39506
+ try {
39507
+ while (true) {
39508
+ const { done, value } = await reader.read();
39509
+ if (done) break;
39510
+ size += value.length;
39511
+ if (size > 16384) {
39512
+ await reader.cancel();
39513
+ throw new Error();
39514
+ }
39515
+ chunks.push(value);
39516
+ }
39517
+ } finally {
39518
+ reader.releaseLock();
39519
+ }
39520
+ return external_exports.object({ version: releaseVersion }).parse(JSON.parse(Buffer.concat(chunks).toString("utf8"))).version;
39521
+ } catch {
39522
+ throw new CliError("Could not check the npm release. Try higherdata update again.");
39523
+ }
39524
+ }
39525
+ var installArgs = (version2) => ["install", "--global", `higherdata@${releaseVersion.parse(version2)}`];
39526
+ var manual = (version2) => `npm install --global higherdata@${releaseVersion.parse(version2)}`;
39527
+ async function updateCli(input2) {
39528
+ const latest = await npmLatest(input2.fetchImpl);
39529
+ if (compareVersions(input2.version, latest) >= 0) {
39530
+ input2.out(`HigherData CLI ${input2.version} is up to date.
39531
+ `);
39532
+ return;
39533
+ }
39534
+ try {
39535
+ await input2.runtime.npm(installArgs(latest), input2.env);
39536
+ } catch (error63) {
39537
+ throw new CliError(`${error63 instanceof NpmUpdateError ? error63.message : "npm install failed"}. Run: ${manual(latest)}`);
39538
+ }
39539
+ input2.out(`Updated HigherData CLI ${input2.version} to ${latest}
39540
+ `);
39541
+ }
39542
+ function primaryCommand(args) {
39543
+ for (let index = 0; index < args.length; index++) {
39544
+ const arg = args[index];
39545
+ if (["--api-url", "--idempotency-key"].includes(arg)) {
39546
+ index++;
39547
+ continue;
39548
+ }
39549
+ if (arg === "--") return args[index + 1];
39550
+ if (!arg.startsWith("-")) return arg;
39551
+ }
39552
+ }
39553
+ function interactiveUpdateAllowed(args, env, runtime) {
39554
+ return runtime.stdinTTY && runtime.stdoutTTY && !Object.hasOwn(env, "CI") && !["mcp", "stdio"].includes(primaryCommand(args) ?? "") && !args.some((arg) => ["--json", "--jsonl", "--stdio", "--help", "-h", "--version", "-V"].includes(arg) || /^(--jsonl?|--stdio)=/u.test(arg));
39555
+ }
39556
+ async function possibleGlobalScript(runtime, env) {
39557
+ try {
39558
+ const script = await runtime.realpath(runtime.script);
39559
+ if (script.split(sep).includes("_npx") || env.npm_command === "exec" || env.npm_lifecycle_event === "npx") return null;
39560
+ return script.endsWith(`${sep}${join4("node_modules", "higherdata", "dist", "index.js")}`) ? script : null;
39561
+ } catch {
39562
+ return null;
39563
+ }
39564
+ }
39565
+ async function globalScript(runtime, env, script) {
39566
+ try {
39567
+ const prefix = (await runtime.npm(["prefix", "-g"], env)).trim();
39568
+ if (!isAbsolute(prefix)) return null;
39569
+ const root = await runtime.realpath(prefix);
39570
+ const expected = join4(root, process.platform === "win32" ? "node_modules" : "lib/node_modules", "higherdata", "dist/index.js");
39571
+ return script === expected ? script : null;
39572
+ } catch {
39573
+ return null;
39574
+ }
39575
+ }
39576
+ async function autoUpdate(input2) {
39577
+ if (!interactiveUpdateAllowed(input2.args, input2.env, input2.runtime) || input2.env.HIGHERDATA_NO_AUTO_UPDATE === "1" || input2.env.HIGHERDATA_UPDATE_RERUN === "1" || ["update", "upgrade", "config"].includes(primaryCommand(input2.args) ?? "")) return null;
39578
+ if ((await input2.readConfig()).autoUpdate === false) return null;
39579
+ const candidate = await possibleGlobalScript(input2.runtime, input2.env);
39580
+ if (!candidate) return null;
39581
+ let latest = null;
39582
+ try {
39583
+ latest = await npmLatest(input2.fetchImpl, 1500);
39584
+ } catch {
39585
+ return null;
39586
+ }
39587
+ if (!latest || compareVersions(input2.version, latest) >= 0) return null;
39588
+ const script = await globalScript(input2.runtime, input2.env, candidate);
39589
+ if (!script) return null;
39590
+ input2.warn(`Updating HigherData CLI to ${latest}...
39591
+ `);
39592
+ try {
39593
+ await input2.runtime.npm(installArgs(latest), input2.env);
39594
+ } catch {
39595
+ input2.warn(`Automatic update failed. Run: ${manual(latest)}
39596
+ `);
39597
+ return null;
39598
+ }
39599
+ try {
39600
+ return await input2.runtime.rerun(script, input2.args, { ...input2.env, HIGHERDATA_UPDATE_RERUN: "1" });
39601
+ } catch {
39602
+ input2.warn("Could not restart HigherData CLI. Run your command again.\n");
39603
+ return 2;
39604
+ }
39605
+ }
39606
+
39607
+ // src/commands.ts
39444
39608
  function cliRuntime(overrides = {}) {
39445
- return { installation: installRuntime(), versionCache: fileVersionCache(), write: overrides.write ?? (overrides.out ? async (text2) => {
39609
+ return { updater: updateRuntime(), installation: installRuntime(), versionCache: fileVersionCache(), write: overrides.write ?? (overrides.out ? async (text2) => {
39446
39610
  overrides.out(text2);
39447
39611
  } : (text2) => new Promise((resolve2, reject) => {
39448
39612
  process.stdout.write(text2, (error63) => error63 ? reject(error63) : resolve2());
@@ -39606,9 +39770,21 @@ function createProgram(overrides = {}) {
39606
39770
  } else program2.outputHelp();
39607
39771
  });
39608
39772
  program2.hook("preAction", async (_program, command) => {
39609
- if (command === program2 || command.name() === "login" || ["mcp", "skills"].includes(command.parent?.name() ?? "")) return;
39773
+ if (["login", "update", "upgrade"].includes(command.name()) || ["mcp", "skills", "config"].includes(command.parent?.name() ?? "")) return;
39774
+ if (command === program2 && (!runtime.updater.stdinTTY || !runtime.updater.stdoutTTY || Object.hasOwn(runtime.env, "CI") || program2.opts().json || program2.opts().jsonl)) return;
39610
39775
  const settings = resolveSettings(await runtime.readConfig(), command.optsWithGlobals(), runtime.env);
39611
- await checkCliVersion({ apiUrl: settings.apiUrl, version: package_default.version, cache: runtime.versionCache, fetchImpl: runtime.fetchImpl, now: runtime.now, warn: runtime.err });
39776
+ const interactive = runtime.updater.stdinTTY && runtime.updater.stdoutTTY && !Object.hasOwn(runtime.env, "CI") && !command.optsWithGlobals().json && !command.optsWithGlobals().jsonl;
39777
+ await checkCliVersion({ apiUrl: settings.apiUrl, version: package_default.version, cache: runtime.versionCache, fetchImpl: runtime.fetchImpl, now: runtime.now, warn: interactive ? runtime.err : () => {
39778
+ } });
39779
+ });
39780
+ program2.command("update").alias("upgrade").description("Install the latest HigherData CLI release").action(() => updateCli({ version: package_default.version, fetchImpl: runtime.fetchImpl, runtime: runtime.updater, env: runtime.env, out: runtime.out }));
39781
+ program2.command("config").description("Configure the CLI").command("set <key> <value>").action(async (key, value) => {
39782
+ if (key !== "auto-update" || !["true", "false"].includes(value)) throw new CliError("Use higherdata config set auto-update true or false.");
39783
+ const config2 = await runtime.readConfig();
39784
+ config2.autoUpdate = value === "true";
39785
+ await runtime.writeConfig(config2);
39786
+ runtime.out(`Automatic updates ${config2.autoUpdate ? "enabled" : "disabled"}.
39787
+ `);
39612
39788
  });
39613
39789
  registerCommands(program2, runtime);
39614
39790
  registerToolCommands(program2, runtime);
@@ -39619,6 +39795,18 @@ async function runCli(args = process.argv.slice(2), overrides = {}) {
39619
39795
  const runtime = cliRuntime(overrides);
39620
39796
  const program2 = createProgram(runtime);
39621
39797
  try {
39798
+ if (interactiveUpdateAllowed(args, runtime.env, runtime.updater)) {
39799
+ const restarted = await autoUpdate({
39800
+ args,
39801
+ version: package_default.version,
39802
+ env: runtime.env,
39803
+ runtime: runtime.updater,
39804
+ readConfig: runtime.readConfig,
39805
+ fetchImpl: runtime.fetchImpl,
39806
+ warn: runtime.err
39807
+ });
39808
+ if (restarted !== null) return restarted;
39809
+ }
39622
39810
  await program2.parseAsync(args, { from: "user" });
39623
39811
  return EXIT_CODES.OK;
39624
39812
  } catch (error63) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "higherdata",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "higherdata": "dist/index.js"