higherdata 0.2.2 → 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.
- package/README.md +32 -3
- package/dist/index.js +544 -89
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -213,12 +213,41 @@ 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.
|
|
217
|
-
|
|
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
|
|
222
221
|
uses its last known policy; with no cached policy it allows the command. Failed
|
|
223
222
|
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.
|
|
224
|
+
|
|
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({
|
|
@@ -28133,6 +28144,10 @@ function retryAfter(response, data, now) {
|
|
|
28133
28144
|
const date5 = Date.parse(value);
|
|
28134
28145
|
if (Number.isFinite(date5)) return Math.max(0, (date5 - now) / 1e3);
|
|
28135
28146
|
}
|
|
28147
|
+
if (response.status === 429) {
|
|
28148
|
+
const reset = response.headers.get("ratelimit-reset");
|
|
28149
|
+
if (reset !== null && /^\d+(?:\.\d+)?$/.test(reset.trim())) return Number(reset);
|
|
28150
|
+
}
|
|
28136
28151
|
const parsed = failure2.safeParse(data);
|
|
28137
28152
|
return parsed.success && typeof parsed.data.error !== "string" ? parsed.data.error.retry_after : void 0;
|
|
28138
28153
|
}
|
|
@@ -28308,6 +28323,7 @@ function apiFailure(status, data) {
|
|
|
28308
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);
|
|
28309
28324
|
if (status === 429 || code === "limit_exceeded") return new CliError("A HigherData limit was reached. Wait until the limit resets.", EXIT_CODES.LIMIT);
|
|
28310
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);
|
|
28311
28327
|
if (code === "needs_approval") return new CliError("This operation needs approval.", EXIT_CODES.NEEDS_APPROVAL);
|
|
28312
28328
|
if (code === "jobs_unavailable") return new CliError("Background jobs are not configured for this deployment.");
|
|
28313
28329
|
if (code === "invalid_input") return new CliError("The API rejected the input. Check the command's filters and identifiers.");
|
|
@@ -28318,6 +28334,7 @@ var CliError, object2, ApiClient;
|
|
|
28318
28334
|
var init_api2 = __esm({
|
|
28319
28335
|
"src/api.ts"() {
|
|
28320
28336
|
"use strict";
|
|
28337
|
+
init_messages();
|
|
28321
28338
|
init_src();
|
|
28322
28339
|
init_zod();
|
|
28323
28340
|
init_exit_codes();
|
|
@@ -28340,8 +28357,16 @@ var init_api2 = __esm({
|
|
|
28340
28357
|
async request(path2, input2, options = {}) {
|
|
28341
28358
|
if (options.authenticated && !this.settings.apiKey) throw new CliError("Run higherdata login or set HIGHERDATA_API_KEY.", EXIT_CODES.AUTH);
|
|
28342
28359
|
try {
|
|
28343
|
-
|
|
28344
|
-
|
|
28360
|
+
for (let attempt = 0; ; attempt++) {
|
|
28361
|
+
try {
|
|
28362
|
+
return await this.transport.request(path2, input2, { ...options, idempotencyKey: this.settings.idempotencyKey });
|
|
28363
|
+
} catch (error63) {
|
|
28364
|
+
if (!(error63 instanceof HigherDataError) || error63.status !== 429 || !options.rateLimitRecovery || attempt >= 5) throw error63;
|
|
28365
|
+
const wait = (error63.retryAfter ?? 1) * 1e3;
|
|
28366
|
+
if (!Number.isFinite(wait) || wait > 3e5) throw error63;
|
|
28367
|
+
await options.rateLimitRecovery.sleep(Math.max(100, wait));
|
|
28368
|
+
}
|
|
28369
|
+
}
|
|
28345
28370
|
} catch (error63) {
|
|
28346
28371
|
if (error63 instanceof HigherDataError) {
|
|
28347
28372
|
if (error63.status) throw apiFailure(error63.status, { error: { code: error63.code, message: error63.message } });
|
|
@@ -28469,7 +28494,7 @@ async function checkCliVersion(input2) {
|
|
|
28469
28494
|
}
|
|
28470
28495
|
}
|
|
28471
28496
|
if (!policy) return;
|
|
28472
|
-
const upgrade = "
|
|
28497
|
+
const upgrade = "higherdata update";
|
|
28473
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}`);
|
|
28474
28499
|
if (compareVersions(input2.version, policy.latestCliVersion) < 0) input2.warn(`HigherData CLI ${policy.latestCliVersion} is available. Upgrade: ${upgrade}
|
|
28475
28500
|
`);
|
|
@@ -31914,7 +31939,7 @@ var init_package = __esm({
|
|
|
31914
31939
|
"package.json"() {
|
|
31915
31940
|
package_default = {
|
|
31916
31941
|
name: "higherdata",
|
|
31917
|
-
version: "0.
|
|
31942
|
+
version: "0.3.1",
|
|
31918
31943
|
type: "module",
|
|
31919
31944
|
bin: {
|
|
31920
31945
|
higherdata: "dist/index.js"
|
|
@@ -34894,6 +34919,9 @@ function cell(value) {
|
|
|
34894
34919
|
const text2 = value == null ? "" : typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
34895
34920
|
return text2.replace(/[\u0000-\u001f\u007f-\u009f]/gu, " ");
|
|
34896
34921
|
}
|
|
34922
|
+
function lookupMatchColumns(row) {
|
|
34923
|
+
return { kind: cell(row.kind), name: cell(row.label), details: cell(row.detail) };
|
|
34924
|
+
}
|
|
34897
34925
|
function customerOutput(value) {
|
|
34898
34926
|
if (Array.isArray(value)) return value.map(customerOutput);
|
|
34899
34927
|
if (!value || typeof value !== "object") return value;
|
|
@@ -34903,10 +34931,10 @@ function renderOutput(value, mode) {
|
|
|
34903
34931
|
value = customerOutput(value);
|
|
34904
34932
|
if (mode === "json") return `${JSON.stringify(value)}
|
|
34905
34933
|
`;
|
|
34906
|
-
const records = Array.isArray(value.items) ? value.items : Array.isArray(value.candidates) ? value.candidates : [value];
|
|
34934
|
+
const records = Array.isArray(value.items) ? value.items : Array.isArray(value.candidates) ? value.candidates : Array.isArray(value.matches) ? value.matches : [value];
|
|
34907
34935
|
if (mode === "jsonl") return records.map((record2) => JSON.stringify(record2)).join("\n") + (records.length ? "\n" : "");
|
|
34908
34936
|
if (!records.length) return "No results.\n";
|
|
34909
|
-
const rows = records.map((record2) => record2);
|
|
34937
|
+
const rows = records.map((record2) => Array.isArray(value.matches) ? lookupMatchColumns(record2) : record2);
|
|
34910
34938
|
const columns = rows.some((row) => "companyName" in row) ? rows.some((row) => "fullName" in row) ? ["id", "fullName", "jobTitle", "companyName", "emailAddress"] : ["id", "companyName", "normalizedDomain", "headquartersCountryCode"] : Object.keys(rows[0]);
|
|
34911
34939
|
const headings = columns.map((column) => column.replace(/([a-z])([A-Z])/gu, "$1 $2").toUpperCase());
|
|
34912
34940
|
const widths = columns.map((column, index) => rows.reduce((width, row) => Math.min(64, Math.max(width, cell(row[column]).length)), headings[index].length));
|
|
@@ -34922,6 +34950,105 @@ var init_output = __esm({
|
|
|
34922
34950
|
}
|
|
34923
34951
|
});
|
|
34924
34952
|
|
|
34953
|
+
// ../../src/lib/csv/search-download.ts
|
|
34954
|
+
function csvCell(value) {
|
|
34955
|
+
let text2 = value === null || value === void 0 ? "" : String(value);
|
|
34956
|
+
if (/^[\s\u0000-\u001f]*[=+\-@]/.test(text2)) text2 = `'${text2}`;
|
|
34957
|
+
return `"${text2.replaceAll('"', '""')}"`;
|
|
34958
|
+
}
|
|
34959
|
+
function pageCsv(headers, rows) {
|
|
34960
|
+
const lines = [headers.map(csvCell).join(","), ...rows.map((row) => row.map(csvCell).join(","))];
|
|
34961
|
+
return `${lines.join("\r\n")}\r
|
|
34962
|
+
`;
|
|
34963
|
+
}
|
|
34964
|
+
function companyPageCsv(items) {
|
|
34965
|
+
return pageCsv(
|
|
34966
|
+
[...COMPANY_DOWNLOAD_FIELDS],
|
|
34967
|
+
items.map((item) => COMPANY_DOWNLOAD_FIELDS.map((field) => item[field]))
|
|
34968
|
+
);
|
|
34969
|
+
}
|
|
34970
|
+
function peoplePageCsv(items) {
|
|
34971
|
+
return pageCsv(
|
|
34972
|
+
[...PEOPLE_DOWNLOAD_FIELDS],
|
|
34973
|
+
items.map((item) => PEOPLE_DOWNLOAD_FIELDS.map((field) => item[field]))
|
|
34974
|
+
);
|
|
34975
|
+
}
|
|
34976
|
+
function searchPageJsonl(kind, items) {
|
|
34977
|
+
const fields = kind === "companies" ? COMPANY_DOWNLOAD_FIELDS : PEOPLE_DOWNLOAD_FIELDS;
|
|
34978
|
+
return items.map((item) => JSON.stringify(Object.fromEntries(fields.map((field) => [field, item[field] ?? null]))) + "\n").join("");
|
|
34979
|
+
}
|
|
34980
|
+
var COMPANY_DOWNLOAD_FIELDS, PEOPLE_DOWNLOAD_FIELDS;
|
|
34981
|
+
var init_search_download = __esm({
|
|
34982
|
+
"../../src/lib/csv/search-download.ts"() {
|
|
34983
|
+
"use strict";
|
|
34984
|
+
COMPANY_DOWNLOAD_FIELDS = ["id", "companyName", "normalizedDomain", "headquartersCountryCode", "industryLinkedin", "employeeCountEstimate"];
|
|
34985
|
+
PEOPLE_DOWNLOAD_FIELDS = ["id", "fullName", "jobTitle", "companyName", "emailAddress", "countryCode"];
|
|
34986
|
+
}
|
|
34987
|
+
});
|
|
34988
|
+
|
|
34989
|
+
// src/search-download.ts
|
|
34990
|
+
import { open as open5 } from "fs/promises";
|
|
34991
|
+
function searchDownloadFormat(path2) {
|
|
34992
|
+
if (!/\.(csv|jsonl)$/.test(path2)) throw new CliError("Choose a new .csv or .jsonl destination.");
|
|
34993
|
+
return path2.endsWith(".jsonl") ? "jsonl" : "csv";
|
|
34994
|
+
}
|
|
34995
|
+
async function downloadSearch(api, name, input2, path2, options) {
|
|
34996
|
+
const format2 = searchDownloadFormat(path2);
|
|
34997
|
+
if (options.all && api.settings.idempotencyKey) throw new CliError("An idempotency key applies to one page. Omit --all.");
|
|
34998
|
+
const file2 = await open5(path2, "wx", 384);
|
|
34999
|
+
let count = 0, first = true, cursor = input2.cursor, loaded = options.loadedPage;
|
|
35000
|
+
const seen = /* @__PURE__ */ new Set();
|
|
35001
|
+
if (typeof cursor === "string") seen.add(cursor);
|
|
35002
|
+
try {
|
|
35003
|
+
while (true) {
|
|
35004
|
+
let raw, headers;
|
|
35005
|
+
if (loaded) {
|
|
35006
|
+
raw = loaded;
|
|
35007
|
+
loaded = void 0;
|
|
35008
|
+
} else {
|
|
35009
|
+
const response = await api.request(`/api/v1/tools/${name}`, { ...input2, ...cursor === void 0 ? {} : { cursor } }, { authenticated: true, rateLimitRecovery: options });
|
|
35010
|
+
raw = response.data;
|
|
35011
|
+
headers = response.headers;
|
|
35012
|
+
}
|
|
35013
|
+
const page = pageSchema2.safeParse(raw);
|
|
35014
|
+
if (!page.success || page.data.items.some((item) => typeof item.id !== "string" || !(name === "search.companies" ? /^hdo_[a-f0-9]{32}$/ : /^hdp_[a-f0-9]{32}$/).test(item.id))) throw new CliError("The API returned an invalid search page.");
|
|
35015
|
+
const items = page.data.items.slice(0, SEARCH_DOWNLOAD_CAP - count);
|
|
35016
|
+
if (format2 === "jsonl") await file2.writeFile(searchPageJsonl(name === "search.companies" ? "companies" : "people", items));
|
|
35017
|
+
else {
|
|
35018
|
+
const csv = (name === "search.companies" ? companyPageCsv : peoplePageCsv)(items);
|
|
35019
|
+
await file2.writeFile(first ? csv : csv.slice(csv.indexOf("\r\n") + 2));
|
|
35020
|
+
}
|
|
35021
|
+
first = false;
|
|
35022
|
+
count += items.length;
|
|
35023
|
+
options.progress?.(`Downloaded ${count.toLocaleString("en-US")} of 5,000`);
|
|
35024
|
+
const next = page.data.nextCursor;
|
|
35025
|
+
if (!options.all || !next || count === SEARCH_DOWNLOAD_CAP) return { rows: count, capped: !!options.all && count === SEARCH_DOWNLOAD_CAP && (!!next || items.length < page.data.items.length) };
|
|
35026
|
+
if (seen.has(next)) throw new CliError("The API repeated a cursor. Pagination stopped.");
|
|
35027
|
+
seen.add(next);
|
|
35028
|
+
cursor = next;
|
|
35029
|
+
if (headers?.get("ratelimit-remaining") === "0") {
|
|
35030
|
+
const reset = headers.get("ratelimit-reset");
|
|
35031
|
+
if (reset !== null && /^\d+(?:\.\d+)?$/.test(reset.trim())) await options.sleep(Number(reset) * 1e3);
|
|
35032
|
+
}
|
|
35033
|
+
}
|
|
35034
|
+
} finally {
|
|
35035
|
+
await file2.close();
|
|
35036
|
+
}
|
|
35037
|
+
}
|
|
35038
|
+
var SEARCH_DOWNLOAD_CAP, SEARCH_DOWNLOAD_CAP_NOTICE, isSearchResults, pageSchema2;
|
|
35039
|
+
var init_search_download2 = __esm({
|
|
35040
|
+
"src/search-download.ts"() {
|
|
35041
|
+
"use strict";
|
|
35042
|
+
init_zod();
|
|
35043
|
+
init_search_download();
|
|
35044
|
+
init_api2();
|
|
35045
|
+
SEARCH_DOWNLOAD_CAP = 5e3;
|
|
35046
|
+
SEARCH_DOWNLOAD_CAP_NOTICE = "Download stopped at 5,000 rows. Save the search to a list and export the list for larger sets.";
|
|
35047
|
+
isSearchResults = (name) => name === "search.companies" || name === "search.people";
|
|
35048
|
+
pageSchema2 = external_exports.object({ items: external_exports.array(external_exports.record(external_exports.string(), external_exports.unknown())).max(50), nextCursor: external_exports.string().min(1).max(2048).nullable() });
|
|
35049
|
+
}
|
|
35050
|
+
});
|
|
35051
|
+
|
|
34925
35052
|
// ../../node_modules/smol-toml/dist/error.js
|
|
34926
35053
|
function getLineColFromPtr(string4, ptr) {
|
|
34927
35054
|
let lines = string4.slice(0, ptr).split(/\r?\n/);
|
|
@@ -36718,11 +36845,11 @@ function parseTree(text2, errors2 = [], options = ParseOptions.DEFAULT) {
|
|
|
36718
36845
|
onValue({ type: getNodeType(value), offset, length, parent: currentParent, value });
|
|
36719
36846
|
ensurePropertyComplete(offset + length);
|
|
36720
36847
|
},
|
|
36721
|
-
onSeparator: (
|
|
36848
|
+
onSeparator: (sep2, offset, length) => {
|
|
36722
36849
|
if (currentParent.type === "property") {
|
|
36723
|
-
if (
|
|
36850
|
+
if (sep2 === ":") {
|
|
36724
36851
|
currentParent.colonOffset = offset;
|
|
36725
|
-
} else if (
|
|
36852
|
+
} else if (sep2 === ",") {
|
|
36726
36853
|
ensurePropertyComplete(offset);
|
|
36727
36854
|
}
|
|
36728
36855
|
}
|
|
@@ -37342,7 +37469,7 @@ var init_main = __esm({
|
|
|
37342
37469
|
|
|
37343
37470
|
// src/install.ts
|
|
37344
37471
|
import { constants } from "fs";
|
|
37345
|
-
import { access, chmod as chmod2, lstat, mkdir as mkdir3, open as
|
|
37472
|
+
import { access, chmod as chmod2, lstat, mkdir as mkdir3, open as open6, readFile as readFile3, readdir, rename as rename3, unlink as unlink3 } from "fs/promises";
|
|
37346
37473
|
import { execFile as execFile2 } from "child_process";
|
|
37347
37474
|
import { promisify, isDeepStrictEqual } from "util";
|
|
37348
37475
|
import { homedir as homedir2 } from "os";
|
|
@@ -37416,7 +37543,7 @@ async function safeParents(path2) {
|
|
|
37416
37543
|
await mkdir3(dirname3(path2), { recursive: true, mode: 448 });
|
|
37417
37544
|
}
|
|
37418
37545
|
async function privateFile(path2, text2) {
|
|
37419
|
-
const file2 = await
|
|
37546
|
+
const file2 = await open6(path2, "wx", 384);
|
|
37420
37547
|
try {
|
|
37421
37548
|
await file2.writeFile(text2, "utf8");
|
|
37422
37549
|
} finally {
|
|
@@ -37965,6 +38092,7 @@ function recordFields(value, prefix = "") {
|
|
|
37965
38092
|
if (!value || typeof value !== "object") return [[prefix || "Value", shownValue(value)]];
|
|
37966
38093
|
return Object.entries(value).flatMap(([key, child]) => {
|
|
37967
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"]];
|
|
37968
38096
|
const name = prefix ? `${prefix} / ${title(key)}` : title(key);
|
|
37969
38097
|
if (Array.isArray(child) && child.some((item) => item && typeof item === "object")) return child.flatMap((item, i) => recordFields(item, `${name} ${i + 1}`));
|
|
37970
38098
|
if (child && typeof child === "object" && !Array.isArray(child)) return recordFields(child, name);
|
|
@@ -38049,7 +38177,7 @@ var init_model = __esm({
|
|
|
38049
38177
|
["account", "Account", "Usage, limits and API keys"],
|
|
38050
38178
|
["icp", "ICP", "Build your ideal customer profile"]
|
|
38051
38179
|
];
|
|
38052
|
-
groupTools = (group) => TOOL_CATALOG.filter((tool) => tool.name.startsWith(`${group}.`));
|
|
38180
|
+
groupTools = (group) => TOOL_CATALOG.filter((tool) => tool.name.startsWith(`${group}.`) && tool.name !== "lookup.find");
|
|
38053
38181
|
toolByName = (name) => TOOL_CATALOG.find((tool) => tool.name === name);
|
|
38054
38182
|
clean = (value) => String(value ?? "").replace(/[\u0000-\u001f\u007f-\u009f]/gu, " ");
|
|
38055
38183
|
title = (value) => value.replaceAll("_", " ").replace(/([a-z])([A-Z])/gu, "$1 $2").replace(/\b\w/gu, (c) => c.toUpperCase());
|
|
@@ -38137,19 +38265,43 @@ var init_install_menu = __esm({
|
|
|
38137
38265
|
});
|
|
38138
38266
|
|
|
38139
38267
|
// src/terminal/banner.ts
|
|
38140
|
-
function
|
|
38141
|
-
const
|
|
38142
|
-
|
|
38143
|
-
|
|
38144
|
-
|
|
38145
|
-
|
|
38146
|
-
const
|
|
38147
|
-
|
|
38148
|
-
|
|
38268
|
+
function markFrame(size, progress = [1, 1, 1]) {
|
|
38269
|
+
const scale = size === "large" ? 3 : 1;
|
|
38270
|
+
return [8, 4, 6].flatMap((units, index) => {
|
|
38271
|
+
const width = Math.round(units * scale * Math.max(0, Math.min(1, progress[index])));
|
|
38272
|
+
const indent = " ".repeat([0, 2, 1][index] * scale);
|
|
38273
|
+
const cap = width > 2 ? indent + " " + "\u2584".repeat(width - 2) : "";
|
|
38274
|
+
const base2 = width ? indent + "\u2580".repeat(width) : "";
|
|
38275
|
+
return size === "large" ? [cap, width ? indent + "\u2588".repeat(width) : "", cap.replaceAll("\u2584", "\u2580")] : [cap, base2];
|
|
38276
|
+
});
|
|
38277
|
+
}
|
|
38278
|
+
function wordmarkFrame(frame = BANNER_FRAMES - 1) {
|
|
38279
|
+
const visible = frame < 5 ? Math.ceil((frame + 1) / 5 * WORDMARK_WIDTH) : WORDMARK_WIDTH;
|
|
38280
|
+
return Array.from({ length: 6 }, (_, row) => {
|
|
38281
|
+
const higher = [..."HIGHER"].map((letter) => GLYPHS[letter][row]).join(" ") + " ";
|
|
38282
|
+
const data = [..."DATA"].map((letter) => GLYPHS[letter][row]).join(" ");
|
|
38283
|
+
return { higher: higher.slice(0, visible), data: data.slice(0, Math.max(0, visible - higher.length)) };
|
|
38149
38284
|
});
|
|
38150
|
-
return [...full.map((line) => " ".repeat(indent) + line.slice(0, visible)), "", ...logo, frame >= 10 ? " ".repeat(Math.max(0, Math.floor((columns - 23) / 2))) + "HIGHERDATA by HigherOps" : ""].map((line) => line.trimEnd());
|
|
38151
38285
|
}
|
|
38152
|
-
|
|
38286
|
+
function homeBrandLayout(columns, rows, extraRows = 0) {
|
|
38287
|
+
const sideBySide = columns - 4 >= WORDMARK_WIDTH + 3 + MARK_WIDTH;
|
|
38288
|
+
const headerRows = sideBySide ? 10 : 17;
|
|
38289
|
+
return { large: columns - 4 >= WORDMARK_WIDTH && rows >= headerRows + 14 + extraRows, sideBySide, headerRows };
|
|
38290
|
+
}
|
|
38291
|
+
function busyFrame(frame, size = "large") {
|
|
38292
|
+
return markFrame(size, [0, 1, 2].map((index) => 0.65 + 0.35 * (1 + Math.sin(frame * Math.PI / 4 - index * Math.PI / 2)) / 2));
|
|
38293
|
+
}
|
|
38294
|
+
function bannerFrame(frame, columns) {
|
|
38295
|
+
const wordmark = wordmarkFrame(frame).map((line) => line.higher + line.data);
|
|
38296
|
+
const indent = " ".repeat(Math.max(0, Math.floor((columns - WORDMARK_WIDTH) / 2)));
|
|
38297
|
+
const logo = markFrame("large", [0, 1, 2].map((index) => Math.max(0, Math.min(1, (frame - 5 - index) / 2))));
|
|
38298
|
+
const markIndent = " ".repeat(Math.max(0, Math.floor((columns - MARK_WIDTH) / 2)));
|
|
38299
|
+
return [...wordmark.map((line) => indent + line), "", ...logo.map((line) => markIndent + line), frame >= 10 ? " ".repeat(Math.max(0, Math.floor((columns - 23) / 2))) + "HIGHERDATA by HigherOps" : ""].map((line) => line.trimEnd());
|
|
38300
|
+
}
|
|
38301
|
+
function animationOptions(args = process.argv.slice(2)) {
|
|
38302
|
+
return { banner: !args.includes("--no-banner"), json: args.includes("--json"), jsonl: args.includes("--jsonl") };
|
|
38303
|
+
}
|
|
38304
|
+
var GLYPHS, BANNER_FRAMES, BANNER_DURATION_MS, MARK_WIDTH, WORDMARK_WIDTH, shouldAnimate;
|
|
38153
38305
|
var init_banner = __esm({
|
|
38154
38306
|
"src/terminal/banner.ts"() {
|
|
38155
38307
|
"use strict";
|
|
@@ -38165,13 +38317,15 @@ var init_banner = __esm({
|
|
|
38165
38317
|
};
|
|
38166
38318
|
BANNER_FRAMES = 11;
|
|
38167
38319
|
BANNER_DURATION_MS = 1210;
|
|
38168
|
-
|
|
38320
|
+
MARK_WIDTH = 24;
|
|
38321
|
+
WORDMARK_WIDTH = [..."HIGHERDATA"].reduce((width, letter) => width + GLYPHS[letter][0].length, "HIGHERDATA".length - 1);
|
|
38169
38322
|
shouldAnimate = (tty, options, env) => tty && options.banner !== false && !options.json && !options.jsonl && !Object.hasOwn(env, "CI");
|
|
38170
38323
|
}
|
|
38171
38324
|
});
|
|
38172
38325
|
|
|
38173
38326
|
// src/terminal/screens.tsx
|
|
38174
|
-
import {
|
|
38327
|
+
import { useEffect, useState } from "react";
|
|
38328
|
+
import { Box, Text, useStdout } from "ink";
|
|
38175
38329
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
38176
38330
|
function Menu({ items, selected, limit, color, width }) {
|
|
38177
38331
|
const start = Math.max(0, Math.min(selected - Math.floor(limit / 2), items.length - limit));
|
|
@@ -38194,17 +38348,54 @@ function Menu({ items, selected, limit, color, width }) {
|
|
|
38194
38348
|
] })
|
|
38195
38349
|
] });
|
|
38196
38350
|
}
|
|
38351
|
+
function Mark({ lines, color }) {
|
|
38352
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: lines.map((line, i) => /* @__PURE__ */ jsx(Text, { color, children: line || " " }, i)) });
|
|
38353
|
+
}
|
|
38354
|
+
function Wordmark({ color, frame }) {
|
|
38355
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", width: WORDMARK_WIDTH, children: wordmarkFrame(frame).map((line, i) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
38356
|
+
line.higher,
|
|
38357
|
+
/* @__PURE__ */ jsx(Text, { color, children: line.data })
|
|
38358
|
+
] }, i)) });
|
|
38359
|
+
}
|
|
38360
|
+
function BusyMark({ color, size = "large", options = animationOptions(), env = process.env }) {
|
|
38361
|
+
const { stdout } = useStdout(), [frame, setFrame] = useState(0);
|
|
38362
|
+
const animate = shouldAnimate(Boolean(stdout.isTTY), options, env);
|
|
38363
|
+
useEffect(() => {
|
|
38364
|
+
if (!animate) return;
|
|
38365
|
+
const timer = setInterval(() => setFrame((value) => (value + 1) % 8), 120);
|
|
38366
|
+
return () => clearInterval(timer);
|
|
38367
|
+
}, [animate]);
|
|
38368
|
+
return /* @__PURE__ */ jsx(Mark, { lines: animate ? busyFrame(frame, size) : markFrame(size), color });
|
|
38369
|
+
}
|
|
38197
38370
|
function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "default", space = "Default", workspace = "HigherOps", remaining = "--" }) {
|
|
38198
38371
|
const width = Math.max(40, columns), color = colors ? "#f2b705" : void 0;
|
|
38199
|
-
const limit = Math.max(4, rows -
|
|
38372
|
+
const limit = Math.max(4, rows - 15);
|
|
38373
|
+
const extraRows = [state.error, state.notice].reduce((count, text2) => count + Math.ceil(clean(text2).length / (width - 4)), 0);
|
|
38374
|
+
const brand = homeBrandLayout(width, rows, extraRows), largeHome = state.screen === "home" && brand.large;
|
|
38200
38375
|
if (state.screen === "banner") return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width, children: [
|
|
38201
|
-
|
|
38376
|
+
/* @__PURE__ */ jsx(Box, { paddingLeft: Math.max(0, Math.floor((width - WORDMARK_WIDTH) / 2)), children: /* @__PURE__ */ jsx(Wordmark, { color, frame: state.frame }) }),
|
|
38377
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
38378
|
+
/* @__PURE__ */ jsx(Mark, { lines: bannerFrame(state.frame, width).slice(7, 16), color }),
|
|
38379
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: bannerFrame(state.frame, width)[16] || " " }),
|
|
38202
38380
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press any key to start" })
|
|
38203
38381
|
] });
|
|
38204
38382
|
const fields = state.tool ? fieldsFor(state.tool.input, state.input, state.variant) : [];
|
|
38205
38383
|
let help = "Up/Down choose. Enter opens. Esc back. Ctrl+C quit.";
|
|
38206
38384
|
let content;
|
|
38207
|
-
if (state.screen === "home")
|
|
38385
|
+
if (state.screen === "home") help = "Up/Down choose. Enter opens. / Look up. Ctrl+C quit.";
|
|
38386
|
+
if (state.screen === "home") content = /* @__PURE__ */ jsx(Menu, { items: homeItems, selected: state.selected, limit: Math.max(4, rows - (largeHome ? brand.headerRows : 6) - 8 - extraRows), color, width: width - 4 });
|
|
38387
|
+
if (state.screen === "lookup") {
|
|
38388
|
+
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38389
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Look up" }),
|
|
38390
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Name, work email, international phone, domain, LinkedIn or record id" }),
|
|
38391
|
+
/* @__PURE__ */ jsxs(Text, { color, wrap: "wrap", children: [
|
|
38392
|
+
"> ",
|
|
38393
|
+
clean(state.text),
|
|
38394
|
+
"_"
|
|
38395
|
+
] })
|
|
38396
|
+
] });
|
|
38397
|
+
help = "Type or paste. Enter looks up. Esc home.";
|
|
38398
|
+
}
|
|
38208
38399
|
if (state.screen === "install") {
|
|
38209
38400
|
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38210
38401
|
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
@@ -38275,6 +38466,12 @@ function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "d
|
|
|
38275
38466
|
] });
|
|
38276
38467
|
help = "Enter edit/run. Arrays: comma separated. Blank clears. Esc back.";
|
|
38277
38468
|
}
|
|
38469
|
+
if (state.screen === "download-choice") {
|
|
38470
|
+
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38471
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Download search results" }),
|
|
38472
|
+
/* @__PURE__ */ jsx(Menu, { items: [{ label: "This page", hint: "Loaded rows, no new request" }, { label: "All results", hint: "Same search, up to 5,000 rows" }], selected: state.selected, limit: 2, color, width: width - 4 })
|
|
38473
|
+
] });
|
|
38474
|
+
}
|
|
38278
38475
|
if (["edit", "upload", "download", "space"].includes(state.screen)) {
|
|
38279
38476
|
const field = fields.find((field2) => field2.path === state.field);
|
|
38280
38477
|
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -38296,7 +38493,7 @@ function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "d
|
|
|
38296
38493
|
}
|
|
38297
38494
|
if (state.screen === "busy") {
|
|
38298
38495
|
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38299
|
-
|
|
38496
|
+
/* @__PURE__ */ jsx(BusyMark, { color, size: rows >= 28 ? "large" : "compact" }),
|
|
38300
38497
|
/* @__PURE__ */ jsx(Text, { children: state.notice || "Working..." })
|
|
38301
38498
|
] });
|
|
38302
38499
|
help = "The current operation is running. It is never retried automatically.";
|
|
@@ -38315,35 +38512,58 @@ function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "d
|
|
|
38315
38512
|
}
|
|
38316
38513
|
if (state.screen === "results") {
|
|
38317
38514
|
const items = rowsOf(state.result);
|
|
38318
|
-
|
|
38319
|
-
|
|
38320
|
-
|
|
38321
|
-
|
|
38322
|
-
|
|
38323
|
-
|
|
38324
|
-
|
|
38325
|
-
|
|
38326
|
-
|
|
38327
|
-
|
|
38328
|
-
|
|
38329
|
-
|
|
38330
|
-
|
|
38331
|
-
|
|
38332
|
-
|
|
38333
|
-
|
|
38334
|
-
|
|
38335
|
-
|
|
38336
|
-
|
|
38337
|
-
] }
|
|
38338
|
-
|
|
38339
|
-
|
|
38340
|
-
|
|
38341
|
-
|
|
38342
|
-
|
|
38343
|
-
|
|
38344
|
-
|
|
38345
|
-
|
|
38346
|
-
|
|
38515
|
+
if (state.tool?.name === "lookup.find") {
|
|
38516
|
+
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38517
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
38518
|
+
"Look up: ",
|
|
38519
|
+
clean(state.input.query)
|
|
38520
|
+
] }),
|
|
38521
|
+
items.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38522
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "KIND / NAME / DETAILS" }),
|
|
38523
|
+
/* @__PURE__ */ jsx(Menu, { items: items.map((row) => {
|
|
38524
|
+
const match = lookupMatchColumns(row);
|
|
38525
|
+
return { label: `${match.kind}: ${match.name}`, hint: match.details };
|
|
38526
|
+
}), selected: state.selected, limit: limit - 2, color, width: width - 4 })
|
|
38527
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38528
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
38529
|
+
"No match for ",
|
|
38530
|
+
clean(state.input.query)
|
|
38531
|
+
] }),
|
|
38532
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Try Search to find companies or people with filters." })
|
|
38533
|
+
] })
|
|
38534
|
+
] });
|
|
38535
|
+
help = "Enter detail. E edit lookup. Esc home.";
|
|
38536
|
+
} else {
|
|
38537
|
+
const list = state.tool?.name === "lists.get" && state.input.id && Array.isArray(state.result.lists) ? state.result.lists[0] : void 0;
|
|
38538
|
+
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38539
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: state.tool?.name ?? "Enrichment job" }),
|
|
38540
|
+
list && /* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
|
|
38541
|
+
clean(list.name),
|
|
38542
|
+
" / ",
|
|
38543
|
+
clean(list.type),
|
|
38544
|
+
" / ",
|
|
38545
|
+
list.recurringEnabled ? "Each release" : "On demand",
|
|
38546
|
+
" / ",
|
|
38547
|
+
clean(list.maxRecords),
|
|
38548
|
+
" records / ",
|
|
38549
|
+
clean(list.maxNewRecordsPerRefresh),
|
|
38550
|
+
" new records per refresh"
|
|
38551
|
+
] }),
|
|
38552
|
+
items.length ? /* @__PURE__ */ jsx(Menu, { items: items.map((row) => ({ label: rowLabel(row), hint: row.matchesCriteria === false ? "No longer matches" : clean(row.status ?? row.jobTitle ?? row.normalizedDomain ?? row.domain ?? row.headquartersCountryCode) })), selected: state.selected, limit: limit - (list ? 3 : 2), color, width: width - 4 }) : recordFields(state.result).slice(state.selected, state.selected + limit).map(([key, value]) => /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", children: [
|
|
38553
|
+
key,
|
|
38554
|
+
": ",
|
|
38555
|
+
value
|
|
38556
|
+
] }, key)),
|
|
38557
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
38558
|
+
items.length ? `${items.length} on this page. ` : "",
|
|
38559
|
+
state.result.nextCursor ? "More records available." : "End of page."
|
|
38560
|
+
] })
|
|
38561
|
+
] });
|
|
38562
|
+
help = "Enter detail. N next page. R refresh. D download. E edit inputs. Esc back.";
|
|
38563
|
+
if (!state.tool) help = "E installation options. Esc home. ";
|
|
38564
|
+
if (state.tool?.name === "searches.list") help = "Enter reopen search. A create audience. N next page. E edit. Esc back.";
|
|
38565
|
+
if (state.tool?.name === "lists.get" && state.input.id) help += " P preview refresh.";
|
|
38566
|
+
}
|
|
38347
38567
|
}
|
|
38348
38568
|
if (state.screen === "detail") {
|
|
38349
38569
|
const row = detailRecord(state.row), isCore = coreRecord(state.row);
|
|
@@ -38390,26 +38610,45 @@ function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "d
|
|
|
38390
38610
|
help = "Enter sends. Ctrl+B step limit. Ctrl+N new conversation. Esc home.";
|
|
38391
38611
|
}
|
|
38392
38612
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width, borderStyle: "double", paddingX: 1, children: [
|
|
38393
|
-
/* @__PURE__ */ jsxs(
|
|
38613
|
+
largeHome ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38614
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: brand.sideBySide ? "row" : "column", gap: brand.sideBySide ? 3 : 1, children: [
|
|
38615
|
+
/* @__PURE__ */ jsx(Wordmark, { color }),
|
|
38616
|
+
/* @__PURE__ */ jsx(Mark, { lines: markFrame("large"), color })
|
|
38617
|
+
] }),
|
|
38618
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
|
|
38619
|
+
"by HigherOps / ",
|
|
38620
|
+
clean(profile),
|
|
38621
|
+
" / ",
|
|
38622
|
+
clean(workspace),
|
|
38623
|
+
" / ",
|
|
38624
|
+
clean(space),
|
|
38625
|
+
" / ",
|
|
38626
|
+
clean(remaining),
|
|
38627
|
+
" email verifications remaining"
|
|
38628
|
+
] })
|
|
38629
|
+
] }) : /* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", children: [
|
|
38394
38630
|
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
38395
|
-
/* @__PURE__ */ jsx(
|
|
38631
|
+
/* @__PURE__ */ jsx(Mark, { lines: markFrame("compact"), color }),
|
|
38396
38632
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
38397
|
-
/* @__PURE__ */
|
|
38633
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
38634
|
+
"Higher",
|
|
38635
|
+
/* @__PURE__ */ jsx(Text, { color, children: "Data" })
|
|
38636
|
+
] }),
|
|
38398
38637
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "by HigherOps" }),
|
|
38399
38638
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: clean(profile) })
|
|
38400
38639
|
] })
|
|
38401
38640
|
] }),
|
|
38402
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", alignItems: "flex-end", children: [
|
|
38641
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", alignItems: "flex-end", flexShrink: 1, children: [
|
|
38403
38642
|
/* @__PURE__ */ jsx(Text, { wrap: "truncate-end", children: clean(workspace) }),
|
|
38404
38643
|
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "truncate-end", children: clean(space) }),
|
|
38405
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
38644
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
|
|
38406
38645
|
clean(remaining),
|
|
38407
38646
|
" email verifications remaining"
|
|
38408
38647
|
] })
|
|
38409
38648
|
] })
|
|
38410
38649
|
] }),
|
|
38411
38650
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2550".repeat(Math.max(1, width - 4)) }),
|
|
38412
|
-
/* @__PURE__ */ jsx(Box, { flexDirection: "column", width: width - 4, minHeight: Math.min(rows -
|
|
38651
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", width: width - 4, minHeight: largeHome ? 0 : Math.max(0, Math.min(rows - 16, 13)), children: content }),
|
|
38413
38652
|
state.error && /* @__PURE__ */ jsx(Text, { color: colors ? "red" : void 0, children: clean(state.error) }),
|
|
38414
38653
|
state.notice && state.screen !== "busy" && /* @__PURE__ */ jsx(Text, { dimColor: true, children: clean(state.notice) }),
|
|
38415
38654
|
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "wrap", children: help })
|
|
@@ -38419,6 +38658,7 @@ var initialState, accountItems, homeItems;
|
|
|
38419
38658
|
var init_screens = __esm({
|
|
38420
38659
|
"src/terminal/screens.tsx"() {
|
|
38421
38660
|
"use strict";
|
|
38661
|
+
init_output();
|
|
38422
38662
|
init_tool_commands();
|
|
38423
38663
|
init_banner();
|
|
38424
38664
|
init_install_menu();
|
|
@@ -38432,8 +38672,8 @@ var init_screens = __esm({
|
|
|
38432
38672
|
{ id: "skills-install", label: "Install skills", hint: "Five task guides for Claude Code or Codex" },
|
|
38433
38673
|
{ id: "quit", label: "Quit", hint: "" }
|
|
38434
38674
|
];
|
|
38435
|
-
homeItems = [["Find", ["search", "searches", "lookup", "icp", "ask"]], ["Work", ["lists", "enrich", "email", "jobs"]], ["Govern", ["suppress", "crm", "changes", "hygiene"]], ["Account", ["account"]]].flatMap(([section, ids]) => ids.map((id, index) => {
|
|
38436
|
-
const group = GROUPS.find(([name]) => name === id);
|
|
38675
|
+
homeItems = [["Find", ["find", "search", "searches", "lookup", "icp", "ask"]], ["Work", ["lists", "enrich", "email", "jobs"]], ["Govern", ["suppress", "crm", "changes", "hygiene"]], ["Account", ["account"]]].flatMap(([section, ids]) => ids.map((id, index) => {
|
|
38676
|
+
const group = id === "find" ? ["find", "Look up", "Name, email, phone, domain, LinkedIn or record id"] : GROUPS.find(([name]) => name === id);
|
|
38437
38677
|
return { id, label: group?.[1] ?? "Ask HigherData", hint: group?.[2] ?? "Plan a request, limit its steps", section: index === 0 ? section : "" };
|
|
38438
38678
|
}));
|
|
38439
38679
|
}
|
|
@@ -38448,25 +38688,25 @@ __export(app_exports, {
|
|
|
38448
38688
|
});
|
|
38449
38689
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
38450
38690
|
import { createReadStream as createReadStream2 } from "fs";
|
|
38451
|
-
import { open as
|
|
38452
|
-
import { useEffect, useRef, useState } from "react";
|
|
38691
|
+
import { open as open7 } from "fs/promises";
|
|
38692
|
+
import { useEffect as useEffect2, useRef, useState as useState2 } from "react";
|
|
38453
38693
|
import { render, useApp, useInput, useWindowSize } from "ink";
|
|
38454
38694
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
38455
38695
|
function InteractiveApp({ session }) {
|
|
38456
38696
|
const { exit } = useApp(), { columns, rows } = useWindowSize();
|
|
38457
38697
|
const settings = session.settings();
|
|
38458
|
-
const [chrome, setChrome] =
|
|
38459
|
-
const [state, setState] =
|
|
38698
|
+
const [chrome, setChrome] = useState2({ workspace: "Workspace", remaining: "--" });
|
|
38699
|
+
const [state, setState] = useState2(() => ({ ...initialState(), screen: shouldAnimate(true, session.options, session.runtime.env) ? "banner" : "home" }));
|
|
38460
38700
|
const current = useRef(state);
|
|
38461
38701
|
current.current = state;
|
|
38462
38702
|
const mounted = useRef(true), request = useRef(false), back = useRef(initialState());
|
|
38463
|
-
|
|
38703
|
+
useEffect2(() => {
|
|
38464
38704
|
mounted.current = true;
|
|
38465
38705
|
return () => {
|
|
38466
38706
|
mounted.current = false;
|
|
38467
38707
|
};
|
|
38468
38708
|
}, []);
|
|
38469
|
-
|
|
38709
|
+
useEffect2(() => {
|
|
38470
38710
|
let active = true;
|
|
38471
38711
|
if (!settings.apiKey || !settings.space) return;
|
|
38472
38712
|
void Promise.all([session.call("account.whoami", {}), session.call("account.usage", {})]).then(([identity, usage]) => {
|
|
@@ -38479,12 +38719,12 @@ function InteractiveApp({ session }) {
|
|
|
38479
38719
|
active = false;
|
|
38480
38720
|
};
|
|
38481
38721
|
}, [session, settings.apiKey, settings.space]);
|
|
38482
|
-
|
|
38722
|
+
useEffect2(() => {
|
|
38483
38723
|
if (state.screen !== "banner") return;
|
|
38484
38724
|
const timer = setInterval(() => setState((s) => s.frame >= BANNER_FRAMES - 1 ? { ...s, screen: "home" } : { ...s, frame: s.frame + 1 }), BANNER_DURATION_MS / BANNER_FRAMES);
|
|
38485
38725
|
return () => clearInterval(timer);
|
|
38486
38726
|
}, [state.screen]);
|
|
38487
|
-
|
|
38727
|
+
useEffect2(() => {
|
|
38488
38728
|
const job = state.result.job;
|
|
38489
38729
|
const id = job?.id ?? (state.tool?.name === "jobs.get" ? state.result.id : void 0);
|
|
38490
38730
|
const status = job?.status ?? state.result.status;
|
|
@@ -38542,6 +38782,7 @@ function InteractiveApp({ session }) {
|
|
|
38542
38782
|
function activate(item) {
|
|
38543
38783
|
const s = current.current;
|
|
38544
38784
|
if (item.id === "quit") exit();
|
|
38785
|
+
else if (item.id === "find") patch({ screen: "lookup", tool: toolByName("lookup.find"), input: {}, text: "", selected: 0 });
|
|
38545
38786
|
else if (item.id === "mcp-install" || item.id === "skills-install") patch({ screen: "install", group: item.id === "mcp-install" ? "mcp" : "skills", tool: null, input: { agent: "claude", scope: "user", profile: "default" }, selected: 0 });
|
|
38546
38787
|
else if (item.id === "space") {
|
|
38547
38788
|
back.current = s;
|
|
@@ -38568,12 +38809,27 @@ function InteractiveApp({ session }) {
|
|
|
38568
38809
|
return;
|
|
38569
38810
|
}
|
|
38570
38811
|
if (s.screen === "busy") return;
|
|
38812
|
+
if (s.screen === "home" && input2 === "/") {
|
|
38813
|
+
activate({ id: "find" });
|
|
38814
|
+
return;
|
|
38815
|
+
}
|
|
38571
38816
|
if (key.escape && s.screen === "filter-group") {
|
|
38572
38817
|
patch({ screen: "form", selected: searchGroups(s.tool.input, s.input).findIndex((group) => group.group === s.filterGroup) });
|
|
38573
38818
|
return;
|
|
38574
38819
|
}
|
|
38575
38820
|
if (key.escape) {
|
|
38576
|
-
patch(s.screen === "home" ? { screen: "home" } : ["edit", "download", "space", "upload"].includes(s.screen) ? { ...back.current } : { screen: s.screen === "detail" ? "results" : s.screen === "form" ? "tools" : "home", selected: 0 });
|
|
38821
|
+
patch(s.screen === "home" ? { screen: "home" } : ["edit", "download", "download-choice", "space", "upload"].includes(s.screen) ? { ...back.current } : { screen: s.screen === "detail" ? "results" : s.screen === "form" ? "tools" : "home", selected: 0 });
|
|
38822
|
+
return;
|
|
38823
|
+
}
|
|
38824
|
+
if (s.screen === "lookup") {
|
|
38825
|
+
if (key.return && s.text.trim()) void work("Looking up your record...", () => session.lookup(s.text));
|
|
38826
|
+
else if (key.backspace || key.delete) patch({ text: s.text.slice(0, -1) });
|
|
38827
|
+
else if (!key.return && !key.ctrl && !key.meta && !key.upArrow && !key.downArrow) patch({ text: s.text + input2 });
|
|
38828
|
+
return;
|
|
38829
|
+
}
|
|
38830
|
+
if (s.screen === "download-choice") {
|
|
38831
|
+
if (key.upArrow || key.downArrow) patch({ selected: s.selected === 0 ? 1 : 0 });
|
|
38832
|
+
else if (key.return) patch({ screen: "download", field: "New destination .csv or .jsonl file", text: "" });
|
|
38577
38833
|
return;
|
|
38578
38834
|
}
|
|
38579
38835
|
if (["edit", "download", "space", "upload"].includes(s.screen)) {
|
|
@@ -38587,8 +38843,10 @@ function InteractiveApp({ session }) {
|
|
|
38587
38843
|
}
|
|
38588
38844
|
if (s.screen === "download") {
|
|
38589
38845
|
void work("Downloading into a new file...", async () => {
|
|
38590
|
-
await session.download(back.current, s.text)
|
|
38591
|
-
|
|
38846
|
+
const notice = await session.download(back.current, s.text, { all: isSearchResults(back.current.tool?.name) && s.selected === 1, progress: (text2) => {
|
|
38847
|
+
if (mounted.current) patch({ notice: text2 });
|
|
38848
|
+
} });
|
|
38849
|
+
return { ...back.current, notice: `Saved ${s.text}${notice ? `. ${notice}` : ""}` };
|
|
38592
38850
|
});
|
|
38593
38851
|
return;
|
|
38594
38852
|
}
|
|
@@ -38697,15 +38955,15 @@ function InteractiveApp({ session }) {
|
|
|
38697
38955
|
patch({ input: { ...s.input, cursor: s.result.nextCursor } });
|
|
38698
38956
|
void work("Loading the next page...", async () => ({ screen: "results", selected: 0, input: { ...s.input, cursor: s.result.nextCursor }, result: await session.call(s.tool.name, { ...s.input, cursor: s.result.nextCursor }) }));
|
|
38699
38957
|
} else if (input2 === "r" && s.tool) runTool(!needsConfirmation(s.tool));
|
|
38700
|
-
else if (input2 === "e") patch({ screen: s.tool ? "form" : "install", selected: 0 });
|
|
38958
|
+
else if (input2 === "e") patch({ screen: s.tool?.name === "lookup.find" ? "lookup" : s.tool ? "form" : "install", text: s.tool?.name === "lookup.find" ? String(s.input.query ?? "") : s.text, selected: 0 });
|
|
38701
38959
|
else if (input2 === "d") {
|
|
38702
38960
|
back.current = s;
|
|
38703
|
-
patch({ screen: "download", field: "New destination .csv or .jsonl file", text: "" });
|
|
38961
|
+
patch({ screen: isSearchResults(s.tool?.name) ? "download-choice" : "download", selected: 0, field: "New destination .csv or .jsonl file", text: "" });
|
|
38704
38962
|
} else if (input2 === "a" && s.tool?.name === "searches.list") {
|
|
38705
38963
|
const row = rowsOf(s.result)[s.selected];
|
|
38706
38964
|
if (row) form("lists.create", { type: "audience", savedSearchId: row.id, recurringEnabled: true, maxRecords: 1e3, maxNewRecordsPerRefresh: 1e3, removeNonmatches: false });
|
|
38707
38965
|
} else if (input2 === "p" && s.tool?.name === "lists.get" && typeof s.input.id === "string") form("lists.refresh", { id: s.input.id, maxNewRecords: 1e3 });
|
|
38708
|
-
else if (key.return) {
|
|
38966
|
+
else if (key.return && (rowsOf(s.result).length || s.tool?.name !== "lookup.find")) {
|
|
38709
38967
|
void work("Opening the record...", () => session.openRow(s));
|
|
38710
38968
|
}
|
|
38711
38969
|
} else if (s.screen === "detail") {
|
|
@@ -38735,6 +38993,7 @@ var TerminalSession;
|
|
|
38735
38993
|
var init_app = __esm({
|
|
38736
38994
|
"src/terminal/app.tsx"() {
|
|
38737
38995
|
"use strict";
|
|
38996
|
+
init_search_download2();
|
|
38738
38997
|
init_tool_commands();
|
|
38739
38998
|
init_api2();
|
|
38740
38999
|
init_config();
|
|
@@ -38758,6 +39017,12 @@ var init_app = __esm({
|
|
|
38758
39017
|
async load() {
|
|
38759
39018
|
this.config = await this.runtime.readConfig();
|
|
38760
39019
|
}
|
|
39020
|
+
async lookup(query) {
|
|
39021
|
+
const result = await this.call("lookup.find", { query });
|
|
39022
|
+
const state = { ...initialState(), screen: "results", tool: toolByName("lookup.find"), input: { query }, result };
|
|
39023
|
+
if (result.exactMatch === true && rowsOf(result).length === 1) return { ...state, ...await this.openRow(state) };
|
|
39024
|
+
return state;
|
|
39025
|
+
}
|
|
38761
39026
|
settings() {
|
|
38762
39027
|
return resolveSettings(this.config, this.options, this.runtime.env);
|
|
38763
39028
|
}
|
|
@@ -38787,15 +39052,22 @@ var init_app = __esm({
|
|
|
38787
39052
|
this.config.profiles[this.config.activeProfile] = { apiUrl: settings.apiUrl, apiKey: key };
|
|
38788
39053
|
await this.runtime.writeConfig(this.config);
|
|
38789
39054
|
}
|
|
38790
|
-
async download(state, path2) {
|
|
39055
|
+
async download(state, path2, options = {}) {
|
|
38791
39056
|
if (!path2.trim()) throw new CliError("Enter a new destination file.");
|
|
38792
39057
|
path2 = path2.trim();
|
|
38793
39058
|
if (!/\.(csv|jsonl)$/.test(path2)) throw new CliError("Choose a new .csv or .jsonl destination.");
|
|
39059
|
+
if (isSearchResults(state.tool?.name)) {
|
|
39060
|
+
const input2 = { ...state.input };
|
|
39061
|
+
const loadedPage = !options.all || !input2.cursor ? state.result : void 0;
|
|
39062
|
+
if (options.all) delete input2.cursor;
|
|
39063
|
+
const result = await downloadSearch(this.api(), state.tool.name, input2, path2, { ...options, loadedPage, sleep: this.runtime.sleep });
|
|
39064
|
+
return result.capped ? SEARCH_DOWNLOAD_CAP_NOTICE : "";
|
|
39065
|
+
}
|
|
38794
39066
|
const job = state.result.job;
|
|
38795
39067
|
const jobId = state.result.jobId ?? job?.id ?? (state.tool?.name.startsWith("jobs.") ? state.result.id ?? state.input.jobId : void 0);
|
|
38796
39068
|
const exportTool = state.tool?.name === "lists.get" && state.input.id ? "lists.export" : state.tool?.name;
|
|
38797
39069
|
if (typeof jobId !== "string" && !["lists.export", "suppress.export"].includes(exportTool ?? "")) throw new CliError("Open a completed job or a list export to download a file.");
|
|
38798
|
-
const file2 = await
|
|
39070
|
+
const file2 = await open7(path2.trim(), "wx", 384);
|
|
38799
39071
|
try {
|
|
38800
39072
|
const format2 = path2.endsWith(".jsonl") ? "jsonl" : "csv";
|
|
38801
39073
|
if (typeof jobId === "string") await downloadBulkJob(this.api(), jobId, format2, async (text2) => {
|
|
@@ -38935,11 +39207,12 @@ async function buildFilters(api, options, kind) {
|
|
|
38935
39207
|
|
|
38936
39208
|
// src/commands.ts
|
|
38937
39209
|
init_output();
|
|
39210
|
+
init_search_download2();
|
|
38938
39211
|
|
|
38939
39212
|
// src/pagination.ts
|
|
38940
39213
|
init_zod();
|
|
38941
39214
|
init_api2();
|
|
38942
|
-
var
|
|
39215
|
+
var pageSchema3 = external_exports.object({ items: external_exports.array(external_exports.record(external_exports.string(), external_exports.unknown())).max(50), nextCursor: external_exports.string().min(1).max(2048).nullable(), zeroResults: external_exports.boolean() });
|
|
38943
39216
|
var exportSchema = external_exports.object({ content: external_exports.string(), mimeType: external_exports.enum(["text/csv", "application/x-ndjson"]), nextCursor: external_exports.string().min(1).max(2048).nullable(), zeroResults: external_exports.boolean() });
|
|
38944
39217
|
async function pagedTool(api, name, input2, all, exporting = false) {
|
|
38945
39218
|
if (all && api.settings.idempotencyKey) throw new CliError("An idempotency key applies to one page. Omit --all.");
|
|
@@ -38952,7 +39225,7 @@ async function pagedTool(api, name, input2, all, exporting = false) {
|
|
|
38952
39225
|
let empty = true;
|
|
38953
39226
|
while (true) {
|
|
38954
39227
|
const raw = await api.tool(name, { ...input2, ...cursor === void 0 ? {} : { cursor } });
|
|
38955
|
-
const page = (exporting ? exportSchema :
|
|
39228
|
+
const page = (exporting ? exportSchema : pageSchema3).safeParse(raw);
|
|
38956
39229
|
if (!page.success) throw new CliError("The API returned an invalid cursor page.");
|
|
38957
39230
|
if ("items" in page.data) records.push(...page.data.items);
|
|
38958
39231
|
else {
|
|
@@ -39182,8 +39455,158 @@ function registerSuppressCommands(program2, helpers) {
|
|
|
39182
39455
|
|
|
39183
39456
|
// src/commands.ts
|
|
39184
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
|
|
39185
39608
|
function cliRuntime(overrides = {}) {
|
|
39186
|
-
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) => {
|
|
39187
39610
|
overrides.out(text2);
|
|
39188
39611
|
} : (text2) => new Promise((resolve2, reject) => {
|
|
39189
39612
|
process.stdout.write(text2, (error63) => error63 ? reject(error63) : resolve2());
|
|
@@ -39246,10 +39669,18 @@ function registerCommands(program2, runtime) {
|
|
|
39246
39669
|
emit(identity, mode);
|
|
39247
39670
|
});
|
|
39248
39671
|
const search = program2.command("search").description("Search HigherData Core");
|
|
39249
|
-
for (const kind of ["companies", "people"]) pageOptions(excludeList(addFilterOptions(search.command(kind).description(`Find ${kind}`), kind === "people"))).action(async (options, command) => {
|
|
39672
|
+
for (const kind of ["companies", "people"]) pageOptions(excludeList(addFilterOptions(search.command(kind).description(`Find ${kind}`), kind === "people"))).option("--out <path>", "Download to a new .csv or .jsonl file (up to 5,000 rows with --all)").action(async (options, command) => {
|
|
39250
39673
|
const { api, mode } = await session(command);
|
|
39674
|
+
if (options.out) searchDownloadFormat(options.out);
|
|
39251
39675
|
const filters = await buildFilters(api, options, kind);
|
|
39252
|
-
|
|
39676
|
+
const input2 = { ...filters, limit: options.limit, ...options.cursor ? { cursor: options.cursor } : {}, ...excluded(options) };
|
|
39677
|
+
if (options.out) {
|
|
39678
|
+
const result = await downloadSearch(api, `search.${kind}`, input2, options.out, { all: Boolean(options.all), sleep: runtime.sleep, progress: (text2) => runtime.err(`${text2}
|
|
39679
|
+
`) });
|
|
39680
|
+
if (result.capped) runtime.err(`${SEARCH_DOWNLOAD_CAP_NOTICE}
|
|
39681
|
+
`);
|
|
39682
|
+
emit({ path: options.out, ...result }, mode);
|
|
39683
|
+
} else emit(await pagedTool(api, `search.${kind}`, input2, Boolean(options.all)), mode);
|
|
39253
39684
|
});
|
|
39254
39685
|
addFilterOptions(program2.command("count").description("Estimate companies and their contacts")).action(async (options, command) => {
|
|
39255
39686
|
const { api, mode } = await session(command);
|
|
@@ -39339,9 +39770,21 @@ function createProgram(overrides = {}) {
|
|
|
39339
39770
|
} else program2.outputHelp();
|
|
39340
39771
|
});
|
|
39341
39772
|
program2.hook("preAction", async (_program, command) => {
|
|
39342
|
-
if (
|
|
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;
|
|
39343
39775
|
const settings = resolveSettings(await runtime.readConfig(), command.optsWithGlobals(), runtime.env);
|
|
39344
|
-
|
|
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
|
+
`);
|
|
39345
39788
|
});
|
|
39346
39789
|
registerCommands(program2, runtime);
|
|
39347
39790
|
registerToolCommands(program2, runtime);
|
|
@@ -39352,6 +39795,18 @@ async function runCli(args = process.argv.slice(2), overrides = {}) {
|
|
|
39352
39795
|
const runtime = cliRuntime(overrides);
|
|
39353
39796
|
const program2 = createProgram(runtime);
|
|
39354
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
|
+
}
|
|
39355
39810
|
await program2.parseAsync(args, { from: "user" });
|
|
39356
39811
|
return EXIT_CODES.OK;
|
|
39357
39812
|
} catch (error63) {
|