higherdata 0.2.2 → 0.3.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/README.md +2 -0
- package/dist/index.js +349 -82
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -222,3 +222,5 @@ The metadata request times out after three seconds. On network failure the CLI
|
|
|
222
222
|
uses its last known policy; with no cached policy it allows the command. Failed
|
|
223
223
|
checks are cached for a day too. A read-only cache directory allows commands but
|
|
224
224
|
cannot persist the daily check, so subsequent invocations may check again.
|
|
225
|
+
|
|
226
|
+
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.
|
package/dist/index.js
CHANGED
|
@@ -28133,6 +28133,10 @@ function retryAfter(response, data, now) {
|
|
|
28133
28133
|
const date5 = Date.parse(value);
|
|
28134
28134
|
if (Number.isFinite(date5)) return Math.max(0, (date5 - now) / 1e3);
|
|
28135
28135
|
}
|
|
28136
|
+
if (response.status === 429) {
|
|
28137
|
+
const reset = response.headers.get("ratelimit-reset");
|
|
28138
|
+
if (reset !== null && /^\d+(?:\.\d+)?$/.test(reset.trim())) return Number(reset);
|
|
28139
|
+
}
|
|
28136
28140
|
const parsed = failure2.safeParse(data);
|
|
28137
28141
|
return parsed.success && typeof parsed.data.error !== "string" ? parsed.data.error.retry_after : void 0;
|
|
28138
28142
|
}
|
|
@@ -28340,8 +28344,16 @@ var init_api2 = __esm({
|
|
|
28340
28344
|
async request(path2, input2, options = {}) {
|
|
28341
28345
|
if (options.authenticated && !this.settings.apiKey) throw new CliError("Run higherdata login or set HIGHERDATA_API_KEY.", EXIT_CODES.AUTH);
|
|
28342
28346
|
try {
|
|
28343
|
-
|
|
28344
|
-
|
|
28347
|
+
for (let attempt = 0; ; attempt++) {
|
|
28348
|
+
try {
|
|
28349
|
+
return await this.transport.request(path2, input2, { ...options, idempotencyKey: this.settings.idempotencyKey });
|
|
28350
|
+
} catch (error63) {
|
|
28351
|
+
if (!(error63 instanceof HigherDataError) || error63.status !== 429 || !options.rateLimitRecovery || attempt >= 5) throw error63;
|
|
28352
|
+
const wait = (error63.retryAfter ?? 1) * 1e3;
|
|
28353
|
+
if (!Number.isFinite(wait) || wait > 3e5) throw error63;
|
|
28354
|
+
await options.rateLimitRecovery.sleep(Math.max(100, wait));
|
|
28355
|
+
}
|
|
28356
|
+
}
|
|
28345
28357
|
} catch (error63) {
|
|
28346
28358
|
if (error63 instanceof HigherDataError) {
|
|
28347
28359
|
if (error63.status) throw apiFailure(error63.status, { error: { code: error63.code, message: error63.message } });
|
|
@@ -31914,7 +31926,7 @@ var init_package = __esm({
|
|
|
31914
31926
|
"package.json"() {
|
|
31915
31927
|
package_default = {
|
|
31916
31928
|
name: "higherdata",
|
|
31917
|
-
version: "0.
|
|
31929
|
+
version: "0.3.0",
|
|
31918
31930
|
type: "module",
|
|
31919
31931
|
bin: {
|
|
31920
31932
|
higherdata: "dist/index.js"
|
|
@@ -34894,6 +34906,9 @@ function cell(value) {
|
|
|
34894
34906
|
const text2 = value == null ? "" : typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
34895
34907
|
return text2.replace(/[\u0000-\u001f\u007f-\u009f]/gu, " ");
|
|
34896
34908
|
}
|
|
34909
|
+
function lookupMatchColumns(row) {
|
|
34910
|
+
return { kind: cell(row.kind), name: cell(row.label), details: cell(row.detail) };
|
|
34911
|
+
}
|
|
34897
34912
|
function customerOutput(value) {
|
|
34898
34913
|
if (Array.isArray(value)) return value.map(customerOutput);
|
|
34899
34914
|
if (!value || typeof value !== "object") return value;
|
|
@@ -34903,10 +34918,10 @@ function renderOutput(value, mode) {
|
|
|
34903
34918
|
value = customerOutput(value);
|
|
34904
34919
|
if (mode === "json") return `${JSON.stringify(value)}
|
|
34905
34920
|
`;
|
|
34906
|
-
const records = Array.isArray(value.items) ? value.items : Array.isArray(value.candidates) ? value.candidates : [value];
|
|
34921
|
+
const records = Array.isArray(value.items) ? value.items : Array.isArray(value.candidates) ? value.candidates : Array.isArray(value.matches) ? value.matches : [value];
|
|
34907
34922
|
if (mode === "jsonl") return records.map((record2) => JSON.stringify(record2)).join("\n") + (records.length ? "\n" : "");
|
|
34908
34923
|
if (!records.length) return "No results.\n";
|
|
34909
|
-
const rows = records.map((record2) => record2);
|
|
34924
|
+
const rows = records.map((record2) => Array.isArray(value.matches) ? lookupMatchColumns(record2) : record2);
|
|
34910
34925
|
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
34926
|
const headings = columns.map((column) => column.replace(/([a-z])([A-Z])/gu, "$1 $2").toUpperCase());
|
|
34912
34927
|
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 +34937,105 @@ var init_output = __esm({
|
|
|
34922
34937
|
}
|
|
34923
34938
|
});
|
|
34924
34939
|
|
|
34940
|
+
// ../../src/lib/csv/search-download.ts
|
|
34941
|
+
function csvCell(value) {
|
|
34942
|
+
let text2 = value === null || value === void 0 ? "" : String(value);
|
|
34943
|
+
if (/^[\s\u0000-\u001f]*[=+\-@]/.test(text2)) text2 = `'${text2}`;
|
|
34944
|
+
return `"${text2.replaceAll('"', '""')}"`;
|
|
34945
|
+
}
|
|
34946
|
+
function pageCsv(headers, rows) {
|
|
34947
|
+
const lines = [headers.map(csvCell).join(","), ...rows.map((row) => row.map(csvCell).join(","))];
|
|
34948
|
+
return `${lines.join("\r\n")}\r
|
|
34949
|
+
`;
|
|
34950
|
+
}
|
|
34951
|
+
function companyPageCsv(items) {
|
|
34952
|
+
return pageCsv(
|
|
34953
|
+
[...COMPANY_DOWNLOAD_FIELDS],
|
|
34954
|
+
items.map((item) => COMPANY_DOWNLOAD_FIELDS.map((field) => item[field]))
|
|
34955
|
+
);
|
|
34956
|
+
}
|
|
34957
|
+
function peoplePageCsv(items) {
|
|
34958
|
+
return pageCsv(
|
|
34959
|
+
[...PEOPLE_DOWNLOAD_FIELDS],
|
|
34960
|
+
items.map((item) => PEOPLE_DOWNLOAD_FIELDS.map((field) => item[field]))
|
|
34961
|
+
);
|
|
34962
|
+
}
|
|
34963
|
+
function searchPageJsonl(kind, items) {
|
|
34964
|
+
const fields = kind === "companies" ? COMPANY_DOWNLOAD_FIELDS : PEOPLE_DOWNLOAD_FIELDS;
|
|
34965
|
+
return items.map((item) => JSON.stringify(Object.fromEntries(fields.map((field) => [field, item[field] ?? null]))) + "\n").join("");
|
|
34966
|
+
}
|
|
34967
|
+
var COMPANY_DOWNLOAD_FIELDS, PEOPLE_DOWNLOAD_FIELDS;
|
|
34968
|
+
var init_search_download = __esm({
|
|
34969
|
+
"../../src/lib/csv/search-download.ts"() {
|
|
34970
|
+
"use strict";
|
|
34971
|
+
COMPANY_DOWNLOAD_FIELDS = ["id", "companyName", "normalizedDomain", "headquartersCountryCode", "industryLinkedin", "employeeCountEstimate"];
|
|
34972
|
+
PEOPLE_DOWNLOAD_FIELDS = ["id", "fullName", "jobTitle", "companyName", "emailAddress", "countryCode"];
|
|
34973
|
+
}
|
|
34974
|
+
});
|
|
34975
|
+
|
|
34976
|
+
// src/search-download.ts
|
|
34977
|
+
import { open as open5 } from "fs/promises";
|
|
34978
|
+
function searchDownloadFormat(path2) {
|
|
34979
|
+
if (!/\.(csv|jsonl)$/.test(path2)) throw new CliError("Choose a new .csv or .jsonl destination.");
|
|
34980
|
+
return path2.endsWith(".jsonl") ? "jsonl" : "csv";
|
|
34981
|
+
}
|
|
34982
|
+
async function downloadSearch(api, name, input2, path2, options) {
|
|
34983
|
+
const format2 = searchDownloadFormat(path2);
|
|
34984
|
+
if (options.all && api.settings.idempotencyKey) throw new CliError("An idempotency key applies to one page. Omit --all.");
|
|
34985
|
+
const file2 = await open5(path2, "wx", 384);
|
|
34986
|
+
let count = 0, first = true, cursor = input2.cursor, loaded = options.loadedPage;
|
|
34987
|
+
const seen = /* @__PURE__ */ new Set();
|
|
34988
|
+
if (typeof cursor === "string") seen.add(cursor);
|
|
34989
|
+
try {
|
|
34990
|
+
while (true) {
|
|
34991
|
+
let raw, headers;
|
|
34992
|
+
if (loaded) {
|
|
34993
|
+
raw = loaded;
|
|
34994
|
+
loaded = void 0;
|
|
34995
|
+
} else {
|
|
34996
|
+
const response = await api.request(`/api/v1/tools/${name}`, { ...input2, ...cursor === void 0 ? {} : { cursor } }, { authenticated: true, rateLimitRecovery: options });
|
|
34997
|
+
raw = response.data;
|
|
34998
|
+
headers = response.headers;
|
|
34999
|
+
}
|
|
35000
|
+
const page = pageSchema2.safeParse(raw);
|
|
35001
|
+
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.");
|
|
35002
|
+
const items = page.data.items.slice(0, SEARCH_DOWNLOAD_CAP - count);
|
|
35003
|
+
if (format2 === "jsonl") await file2.writeFile(searchPageJsonl(name === "search.companies" ? "companies" : "people", items));
|
|
35004
|
+
else {
|
|
35005
|
+
const csv = (name === "search.companies" ? companyPageCsv : peoplePageCsv)(items);
|
|
35006
|
+
await file2.writeFile(first ? csv : csv.slice(csv.indexOf("\r\n") + 2));
|
|
35007
|
+
}
|
|
35008
|
+
first = false;
|
|
35009
|
+
count += items.length;
|
|
35010
|
+
options.progress?.(`Downloaded ${count.toLocaleString("en-US")} of 5,000`);
|
|
35011
|
+
const next = page.data.nextCursor;
|
|
35012
|
+
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) };
|
|
35013
|
+
if (seen.has(next)) throw new CliError("The API repeated a cursor. Pagination stopped.");
|
|
35014
|
+
seen.add(next);
|
|
35015
|
+
cursor = next;
|
|
35016
|
+
if (headers?.get("ratelimit-remaining") === "0") {
|
|
35017
|
+
const reset = headers.get("ratelimit-reset");
|
|
35018
|
+
if (reset !== null && /^\d+(?:\.\d+)?$/.test(reset.trim())) await options.sleep(Number(reset) * 1e3);
|
|
35019
|
+
}
|
|
35020
|
+
}
|
|
35021
|
+
} finally {
|
|
35022
|
+
await file2.close();
|
|
35023
|
+
}
|
|
35024
|
+
}
|
|
35025
|
+
var SEARCH_DOWNLOAD_CAP, SEARCH_DOWNLOAD_CAP_NOTICE, isSearchResults, pageSchema2;
|
|
35026
|
+
var init_search_download2 = __esm({
|
|
35027
|
+
"src/search-download.ts"() {
|
|
35028
|
+
"use strict";
|
|
35029
|
+
init_zod();
|
|
35030
|
+
init_search_download();
|
|
35031
|
+
init_api2();
|
|
35032
|
+
SEARCH_DOWNLOAD_CAP = 5e3;
|
|
35033
|
+
SEARCH_DOWNLOAD_CAP_NOTICE = "Download stopped at 5,000 rows. Save the search to a list and export the list for larger sets.";
|
|
35034
|
+
isSearchResults = (name) => name === "search.companies" || name === "search.people";
|
|
35035
|
+
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() });
|
|
35036
|
+
}
|
|
35037
|
+
});
|
|
35038
|
+
|
|
34925
35039
|
// ../../node_modules/smol-toml/dist/error.js
|
|
34926
35040
|
function getLineColFromPtr(string4, ptr) {
|
|
34927
35041
|
let lines = string4.slice(0, ptr).split(/\r?\n/);
|
|
@@ -37342,7 +37456,7 @@ var init_main = __esm({
|
|
|
37342
37456
|
|
|
37343
37457
|
// src/install.ts
|
|
37344
37458
|
import { constants } from "fs";
|
|
37345
|
-
import { access, chmod as chmod2, lstat, mkdir as mkdir3, open as
|
|
37459
|
+
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
37460
|
import { execFile as execFile2 } from "child_process";
|
|
37347
37461
|
import { promisify, isDeepStrictEqual } from "util";
|
|
37348
37462
|
import { homedir as homedir2 } from "os";
|
|
@@ -37416,7 +37530,7 @@ async function safeParents(path2) {
|
|
|
37416
37530
|
await mkdir3(dirname3(path2), { recursive: true, mode: 448 });
|
|
37417
37531
|
}
|
|
37418
37532
|
async function privateFile(path2, text2) {
|
|
37419
|
-
const file2 = await
|
|
37533
|
+
const file2 = await open6(path2, "wx", 384);
|
|
37420
37534
|
try {
|
|
37421
37535
|
await file2.writeFile(text2, "utf8");
|
|
37422
37536
|
} finally {
|
|
@@ -38049,7 +38163,7 @@ var init_model = __esm({
|
|
|
38049
38163
|
["account", "Account", "Usage, limits and API keys"],
|
|
38050
38164
|
["icp", "ICP", "Build your ideal customer profile"]
|
|
38051
38165
|
];
|
|
38052
|
-
groupTools = (group) => TOOL_CATALOG.filter((tool) => tool.name.startsWith(`${group}.`));
|
|
38166
|
+
groupTools = (group) => TOOL_CATALOG.filter((tool) => tool.name.startsWith(`${group}.`) && tool.name !== "lookup.find");
|
|
38053
38167
|
toolByName = (name) => TOOL_CATALOG.find((tool) => tool.name === name);
|
|
38054
38168
|
clean = (value) => String(value ?? "").replace(/[\u0000-\u001f\u007f-\u009f]/gu, " ");
|
|
38055
38169
|
title = (value) => value.replaceAll("_", " ").replace(/([a-z])([A-Z])/gu, "$1 $2").replace(/\b\w/gu, (c) => c.toUpperCase());
|
|
@@ -38137,19 +38251,43 @@ var init_install_menu = __esm({
|
|
|
38137
38251
|
});
|
|
38138
38252
|
|
|
38139
38253
|
// src/terminal/banner.ts
|
|
38140
|
-
function
|
|
38141
|
-
const
|
|
38142
|
-
|
|
38143
|
-
|
|
38144
|
-
|
|
38145
|
-
|
|
38146
|
-
const
|
|
38147
|
-
|
|
38148
|
-
|
|
38254
|
+
function markFrame(size, progress = [1, 1, 1]) {
|
|
38255
|
+
const scale = size === "large" ? 3 : 1;
|
|
38256
|
+
return [8, 4, 6].flatMap((units, index) => {
|
|
38257
|
+
const width = Math.round(units * scale * Math.max(0, Math.min(1, progress[index])));
|
|
38258
|
+
const indent = " ".repeat([0, 2, 1][index] * scale);
|
|
38259
|
+
const cap = width > 2 ? indent + " " + "\u2584".repeat(width - 2) : "";
|
|
38260
|
+
const base2 = width ? indent + "\u2580".repeat(width) : "";
|
|
38261
|
+
return size === "large" ? [cap, width ? indent + "\u2588".repeat(width) : "", cap.replaceAll("\u2584", "\u2580")] : [cap, base2];
|
|
38262
|
+
});
|
|
38263
|
+
}
|
|
38264
|
+
function wordmarkFrame(frame = BANNER_FRAMES - 1) {
|
|
38265
|
+
const visible = frame < 5 ? Math.ceil((frame + 1) / 5 * WORDMARK_WIDTH) : WORDMARK_WIDTH;
|
|
38266
|
+
return Array.from({ length: 6 }, (_, row) => {
|
|
38267
|
+
const higher = [..."HIGHER"].map((letter) => GLYPHS[letter][row]).join(" ") + " ";
|
|
38268
|
+
const data = [..."DATA"].map((letter) => GLYPHS[letter][row]).join(" ");
|
|
38269
|
+
return { higher: higher.slice(0, visible), data: data.slice(0, Math.max(0, visible - higher.length)) };
|
|
38149
38270
|
});
|
|
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
38271
|
}
|
|
38152
|
-
|
|
38272
|
+
function homeBrandLayout(columns, rows, extraRows = 0) {
|
|
38273
|
+
const sideBySide = columns - 4 >= WORDMARK_WIDTH + 3 + MARK_WIDTH;
|
|
38274
|
+
const headerRows = sideBySide ? 10 : 17;
|
|
38275
|
+
return { large: columns - 4 >= WORDMARK_WIDTH && rows >= headerRows + 14 + extraRows, sideBySide, headerRows };
|
|
38276
|
+
}
|
|
38277
|
+
function busyFrame(frame, size = "large") {
|
|
38278
|
+
return markFrame(size, [0, 1, 2].map((index) => 0.65 + 0.35 * (1 + Math.sin(frame * Math.PI / 4 - index * Math.PI / 2)) / 2));
|
|
38279
|
+
}
|
|
38280
|
+
function bannerFrame(frame, columns) {
|
|
38281
|
+
const wordmark = wordmarkFrame(frame).map((line) => line.higher + line.data);
|
|
38282
|
+
const indent = " ".repeat(Math.max(0, Math.floor((columns - WORDMARK_WIDTH) / 2)));
|
|
38283
|
+
const logo = markFrame("large", [0, 1, 2].map((index) => Math.max(0, Math.min(1, (frame - 5 - index) / 2))));
|
|
38284
|
+
const markIndent = " ".repeat(Math.max(0, Math.floor((columns - MARK_WIDTH) / 2)));
|
|
38285
|
+
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());
|
|
38286
|
+
}
|
|
38287
|
+
function animationOptions(args = process.argv.slice(2)) {
|
|
38288
|
+
return { banner: !args.includes("--no-banner"), json: args.includes("--json"), jsonl: args.includes("--jsonl") };
|
|
38289
|
+
}
|
|
38290
|
+
var GLYPHS, BANNER_FRAMES, BANNER_DURATION_MS, MARK_WIDTH, WORDMARK_WIDTH, shouldAnimate;
|
|
38153
38291
|
var init_banner = __esm({
|
|
38154
38292
|
"src/terminal/banner.ts"() {
|
|
38155
38293
|
"use strict";
|
|
@@ -38165,13 +38303,15 @@ var init_banner = __esm({
|
|
|
38165
38303
|
};
|
|
38166
38304
|
BANNER_FRAMES = 11;
|
|
38167
38305
|
BANNER_DURATION_MS = 1210;
|
|
38168
|
-
|
|
38306
|
+
MARK_WIDTH = 24;
|
|
38307
|
+
WORDMARK_WIDTH = [..."HIGHERDATA"].reduce((width, letter) => width + GLYPHS[letter][0].length, "HIGHERDATA".length - 1);
|
|
38169
38308
|
shouldAnimate = (tty, options, env) => tty && options.banner !== false && !options.json && !options.jsonl && !Object.hasOwn(env, "CI");
|
|
38170
38309
|
}
|
|
38171
38310
|
});
|
|
38172
38311
|
|
|
38173
38312
|
// src/terminal/screens.tsx
|
|
38174
|
-
import {
|
|
38313
|
+
import { useEffect, useState } from "react";
|
|
38314
|
+
import { Box, Text, useStdout } from "ink";
|
|
38175
38315
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
38176
38316
|
function Menu({ items, selected, limit, color, width }) {
|
|
38177
38317
|
const start = Math.max(0, Math.min(selected - Math.floor(limit / 2), items.length - limit));
|
|
@@ -38194,17 +38334,54 @@ function Menu({ items, selected, limit, color, width }) {
|
|
|
38194
38334
|
] })
|
|
38195
38335
|
] });
|
|
38196
38336
|
}
|
|
38337
|
+
function Mark({ lines, color }) {
|
|
38338
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: lines.map((line, i) => /* @__PURE__ */ jsx(Text, { color, children: line || " " }, i)) });
|
|
38339
|
+
}
|
|
38340
|
+
function Wordmark({ color, frame }) {
|
|
38341
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", width: WORDMARK_WIDTH, children: wordmarkFrame(frame).map((line, i) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
38342
|
+
line.higher,
|
|
38343
|
+
/* @__PURE__ */ jsx(Text, { color, children: line.data })
|
|
38344
|
+
] }, i)) });
|
|
38345
|
+
}
|
|
38346
|
+
function BusyMark({ color, size = "large", options = animationOptions(), env = process.env }) {
|
|
38347
|
+
const { stdout } = useStdout(), [frame, setFrame] = useState(0);
|
|
38348
|
+
const animate = shouldAnimate(Boolean(stdout.isTTY), options, env);
|
|
38349
|
+
useEffect(() => {
|
|
38350
|
+
if (!animate) return;
|
|
38351
|
+
const timer = setInterval(() => setFrame((value) => (value + 1) % 8), 120);
|
|
38352
|
+
return () => clearInterval(timer);
|
|
38353
|
+
}, [animate]);
|
|
38354
|
+
return /* @__PURE__ */ jsx(Mark, { lines: animate ? busyFrame(frame, size) : markFrame(size), color });
|
|
38355
|
+
}
|
|
38197
38356
|
function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "default", space = "Default", workspace = "HigherOps", remaining = "--" }) {
|
|
38198
38357
|
const width = Math.max(40, columns), color = colors ? "#f2b705" : void 0;
|
|
38199
|
-
const limit = Math.max(4, rows -
|
|
38358
|
+
const limit = Math.max(4, rows - 15);
|
|
38359
|
+
const extraRows = [state.error, state.notice].reduce((count, text2) => count + Math.ceil(clean(text2).length / (width - 4)), 0);
|
|
38360
|
+
const brand = homeBrandLayout(width, rows, extraRows), largeHome = state.screen === "home" && brand.large;
|
|
38200
38361
|
if (state.screen === "banner") return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width, children: [
|
|
38201
|
-
|
|
38362
|
+
/* @__PURE__ */ jsx(Box, { paddingLeft: Math.max(0, Math.floor((width - WORDMARK_WIDTH) / 2)), children: /* @__PURE__ */ jsx(Wordmark, { color, frame: state.frame }) }),
|
|
38363
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
38364
|
+
/* @__PURE__ */ jsx(Mark, { lines: bannerFrame(state.frame, width).slice(7, 16), color }),
|
|
38365
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: bannerFrame(state.frame, width)[16] || " " }),
|
|
38202
38366
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press any key to start" })
|
|
38203
38367
|
] });
|
|
38204
38368
|
const fields = state.tool ? fieldsFor(state.tool.input, state.input, state.variant) : [];
|
|
38205
38369
|
let help = "Up/Down choose. Enter opens. Esc back. Ctrl+C quit.";
|
|
38206
38370
|
let content;
|
|
38207
|
-
if (state.screen === "home")
|
|
38371
|
+
if (state.screen === "home") help = "Up/Down choose. Enter opens. / Look up. Ctrl+C quit.";
|
|
38372
|
+
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 });
|
|
38373
|
+
if (state.screen === "lookup") {
|
|
38374
|
+
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38375
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Look up" }),
|
|
38376
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Name, work email, international phone, domain, LinkedIn or record id" }),
|
|
38377
|
+
/* @__PURE__ */ jsxs(Text, { color, wrap: "wrap", children: [
|
|
38378
|
+
"> ",
|
|
38379
|
+
clean(state.text),
|
|
38380
|
+
"_"
|
|
38381
|
+
] })
|
|
38382
|
+
] });
|
|
38383
|
+
help = "Type or paste. Enter looks up. Esc home.";
|
|
38384
|
+
}
|
|
38208
38385
|
if (state.screen === "install") {
|
|
38209
38386
|
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38210
38387
|
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
@@ -38275,6 +38452,12 @@ function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "d
|
|
|
38275
38452
|
] });
|
|
38276
38453
|
help = "Enter edit/run. Arrays: comma separated. Blank clears. Esc back.";
|
|
38277
38454
|
}
|
|
38455
|
+
if (state.screen === "download-choice") {
|
|
38456
|
+
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38457
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Download search results" }),
|
|
38458
|
+
/* @__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 })
|
|
38459
|
+
] });
|
|
38460
|
+
}
|
|
38278
38461
|
if (["edit", "upload", "download", "space"].includes(state.screen)) {
|
|
38279
38462
|
const field = fields.find((field2) => field2.path === state.field);
|
|
38280
38463
|
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -38296,7 +38479,7 @@ function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "d
|
|
|
38296
38479
|
}
|
|
38297
38480
|
if (state.screen === "busy") {
|
|
38298
38481
|
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38299
|
-
|
|
38482
|
+
/* @__PURE__ */ jsx(BusyMark, { color, size: rows >= 28 ? "large" : "compact" }),
|
|
38300
38483
|
/* @__PURE__ */ jsx(Text, { children: state.notice || "Working..." })
|
|
38301
38484
|
] });
|
|
38302
38485
|
help = "The current operation is running. It is never retried automatically.";
|
|
@@ -38315,35 +38498,58 @@ function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "d
|
|
|
38315
38498
|
}
|
|
38316
38499
|
if (state.screen === "results") {
|
|
38317
38500
|
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
|
-
|
|
38501
|
+
if (state.tool?.name === "lookup.find") {
|
|
38502
|
+
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38503
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
38504
|
+
"Look up: ",
|
|
38505
|
+
clean(state.input.query)
|
|
38506
|
+
] }),
|
|
38507
|
+
items.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38508
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "KIND / NAME / DETAILS" }),
|
|
38509
|
+
/* @__PURE__ */ jsx(Menu, { items: items.map((row) => {
|
|
38510
|
+
const match = lookupMatchColumns(row);
|
|
38511
|
+
return { label: `${match.kind}: ${match.name}`, hint: match.details };
|
|
38512
|
+
}), selected: state.selected, limit: limit - 2, color, width: width - 4 })
|
|
38513
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38514
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
38515
|
+
"No match for ",
|
|
38516
|
+
clean(state.input.query)
|
|
38517
|
+
] }),
|
|
38518
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Try Search to find companies or people with filters." })
|
|
38519
|
+
] })
|
|
38520
|
+
] });
|
|
38521
|
+
help = "Enter detail. E edit lookup. Esc home.";
|
|
38522
|
+
} else {
|
|
38523
|
+
const list = state.tool?.name === "lists.get" && state.input.id && Array.isArray(state.result.lists) ? state.result.lists[0] : void 0;
|
|
38524
|
+
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38525
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: state.tool?.name ?? "Enrichment job" }),
|
|
38526
|
+
list && /* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
|
|
38527
|
+
clean(list.name),
|
|
38528
|
+
" / ",
|
|
38529
|
+
clean(list.type),
|
|
38530
|
+
" / ",
|
|
38531
|
+
list.recurringEnabled ? "Each release" : "On demand",
|
|
38532
|
+
" / ",
|
|
38533
|
+
clean(list.maxRecords),
|
|
38534
|
+
" records / ",
|
|
38535
|
+
clean(list.maxNewRecordsPerRefresh),
|
|
38536
|
+
" new records per refresh"
|
|
38537
|
+
] }),
|
|
38538
|
+
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: [
|
|
38539
|
+
key,
|
|
38540
|
+
": ",
|
|
38541
|
+
value
|
|
38542
|
+
] }, key)),
|
|
38543
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
38544
|
+
items.length ? `${items.length} on this page. ` : "",
|
|
38545
|
+
state.result.nextCursor ? "More records available." : "End of page."
|
|
38546
|
+
] })
|
|
38547
|
+
] });
|
|
38548
|
+
help = "Enter detail. N next page. R refresh. D download. E edit inputs. Esc back.";
|
|
38549
|
+
if (!state.tool) help = "E installation options. Esc home. ";
|
|
38550
|
+
if (state.tool?.name === "searches.list") help = "Enter reopen search. A create audience. N next page. E edit. Esc back.";
|
|
38551
|
+
if (state.tool?.name === "lists.get" && state.input.id) help += " P preview refresh.";
|
|
38552
|
+
}
|
|
38347
38553
|
}
|
|
38348
38554
|
if (state.screen === "detail") {
|
|
38349
38555
|
const row = detailRecord(state.row), isCore = coreRecord(state.row);
|
|
@@ -38390,26 +38596,45 @@ function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "d
|
|
|
38390
38596
|
help = "Enter sends. Ctrl+B step limit. Ctrl+N new conversation. Esc home.";
|
|
38391
38597
|
}
|
|
38392
38598
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width, borderStyle: "double", paddingX: 1, children: [
|
|
38393
|
-
/* @__PURE__ */ jsxs(
|
|
38599
|
+
largeHome ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38600
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: brand.sideBySide ? "row" : "column", gap: brand.sideBySide ? 3 : 1, children: [
|
|
38601
|
+
/* @__PURE__ */ jsx(Wordmark, { color }),
|
|
38602
|
+
/* @__PURE__ */ jsx(Mark, { lines: markFrame("large"), color })
|
|
38603
|
+
] }),
|
|
38604
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
|
|
38605
|
+
"by HigherOps / ",
|
|
38606
|
+
clean(profile),
|
|
38607
|
+
" / ",
|
|
38608
|
+
clean(workspace),
|
|
38609
|
+
" / ",
|
|
38610
|
+
clean(space),
|
|
38611
|
+
" / ",
|
|
38612
|
+
clean(remaining),
|
|
38613
|
+
" email verifications remaining"
|
|
38614
|
+
] })
|
|
38615
|
+
] }) : /* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", children: [
|
|
38394
38616
|
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
38395
|
-
/* @__PURE__ */ jsx(
|
|
38617
|
+
/* @__PURE__ */ jsx(Mark, { lines: markFrame("compact"), color }),
|
|
38396
38618
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
38397
|
-
/* @__PURE__ */
|
|
38619
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
38620
|
+
"Higher",
|
|
38621
|
+
/* @__PURE__ */ jsx(Text, { color, children: "Data" })
|
|
38622
|
+
] }),
|
|
38398
38623
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "by HigherOps" }),
|
|
38399
38624
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: clean(profile) })
|
|
38400
38625
|
] })
|
|
38401
38626
|
] }),
|
|
38402
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", alignItems: "flex-end", children: [
|
|
38627
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", alignItems: "flex-end", flexShrink: 1, children: [
|
|
38403
38628
|
/* @__PURE__ */ jsx(Text, { wrap: "truncate-end", children: clean(workspace) }),
|
|
38404
38629
|
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "truncate-end", children: clean(space) }),
|
|
38405
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
38630
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
|
|
38406
38631
|
clean(remaining),
|
|
38407
38632
|
" email verifications remaining"
|
|
38408
38633
|
] })
|
|
38409
38634
|
] })
|
|
38410
38635
|
] }),
|
|
38411
38636
|
/* @__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 -
|
|
38637
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", width: width - 4, minHeight: largeHome ? 0 : Math.max(0, Math.min(rows - 16, 13)), children: content }),
|
|
38413
38638
|
state.error && /* @__PURE__ */ jsx(Text, { color: colors ? "red" : void 0, children: clean(state.error) }),
|
|
38414
38639
|
state.notice && state.screen !== "busy" && /* @__PURE__ */ jsx(Text, { dimColor: true, children: clean(state.notice) }),
|
|
38415
38640
|
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "wrap", children: help })
|
|
@@ -38419,6 +38644,7 @@ var initialState, accountItems, homeItems;
|
|
|
38419
38644
|
var init_screens = __esm({
|
|
38420
38645
|
"src/terminal/screens.tsx"() {
|
|
38421
38646
|
"use strict";
|
|
38647
|
+
init_output();
|
|
38422
38648
|
init_tool_commands();
|
|
38423
38649
|
init_banner();
|
|
38424
38650
|
init_install_menu();
|
|
@@ -38432,8 +38658,8 @@ var init_screens = __esm({
|
|
|
38432
38658
|
{ id: "skills-install", label: "Install skills", hint: "Five task guides for Claude Code or Codex" },
|
|
38433
38659
|
{ id: "quit", label: "Quit", hint: "" }
|
|
38434
38660
|
];
|
|
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);
|
|
38661
|
+
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) => {
|
|
38662
|
+
const group = id === "find" ? ["find", "Look up", "Name, email, phone, domain, LinkedIn or record id"] : GROUPS.find(([name]) => name === id);
|
|
38437
38663
|
return { id, label: group?.[1] ?? "Ask HigherData", hint: group?.[2] ?? "Plan a request, limit its steps", section: index === 0 ? section : "" };
|
|
38438
38664
|
}));
|
|
38439
38665
|
}
|
|
@@ -38448,25 +38674,25 @@ __export(app_exports, {
|
|
|
38448
38674
|
});
|
|
38449
38675
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
38450
38676
|
import { createReadStream as createReadStream2 } from "fs";
|
|
38451
|
-
import { open as
|
|
38452
|
-
import { useEffect, useRef, useState } from "react";
|
|
38677
|
+
import { open as open7 } from "fs/promises";
|
|
38678
|
+
import { useEffect as useEffect2, useRef, useState as useState2 } from "react";
|
|
38453
38679
|
import { render, useApp, useInput, useWindowSize } from "ink";
|
|
38454
38680
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
38455
38681
|
function InteractiveApp({ session }) {
|
|
38456
38682
|
const { exit } = useApp(), { columns, rows } = useWindowSize();
|
|
38457
38683
|
const settings = session.settings();
|
|
38458
|
-
const [chrome, setChrome] =
|
|
38459
|
-
const [state, setState] =
|
|
38684
|
+
const [chrome, setChrome] = useState2({ workspace: "Workspace", remaining: "--" });
|
|
38685
|
+
const [state, setState] = useState2(() => ({ ...initialState(), screen: shouldAnimate(true, session.options, session.runtime.env) ? "banner" : "home" }));
|
|
38460
38686
|
const current = useRef(state);
|
|
38461
38687
|
current.current = state;
|
|
38462
38688
|
const mounted = useRef(true), request = useRef(false), back = useRef(initialState());
|
|
38463
|
-
|
|
38689
|
+
useEffect2(() => {
|
|
38464
38690
|
mounted.current = true;
|
|
38465
38691
|
return () => {
|
|
38466
38692
|
mounted.current = false;
|
|
38467
38693
|
};
|
|
38468
38694
|
}, []);
|
|
38469
|
-
|
|
38695
|
+
useEffect2(() => {
|
|
38470
38696
|
let active = true;
|
|
38471
38697
|
if (!settings.apiKey || !settings.space) return;
|
|
38472
38698
|
void Promise.all([session.call("account.whoami", {}), session.call("account.usage", {})]).then(([identity, usage]) => {
|
|
@@ -38479,12 +38705,12 @@ function InteractiveApp({ session }) {
|
|
|
38479
38705
|
active = false;
|
|
38480
38706
|
};
|
|
38481
38707
|
}, [session, settings.apiKey, settings.space]);
|
|
38482
|
-
|
|
38708
|
+
useEffect2(() => {
|
|
38483
38709
|
if (state.screen !== "banner") return;
|
|
38484
38710
|
const timer = setInterval(() => setState((s) => s.frame >= BANNER_FRAMES - 1 ? { ...s, screen: "home" } : { ...s, frame: s.frame + 1 }), BANNER_DURATION_MS / BANNER_FRAMES);
|
|
38485
38711
|
return () => clearInterval(timer);
|
|
38486
38712
|
}, [state.screen]);
|
|
38487
|
-
|
|
38713
|
+
useEffect2(() => {
|
|
38488
38714
|
const job = state.result.job;
|
|
38489
38715
|
const id = job?.id ?? (state.tool?.name === "jobs.get" ? state.result.id : void 0);
|
|
38490
38716
|
const status = job?.status ?? state.result.status;
|
|
@@ -38542,6 +38768,7 @@ function InteractiveApp({ session }) {
|
|
|
38542
38768
|
function activate(item) {
|
|
38543
38769
|
const s = current.current;
|
|
38544
38770
|
if (item.id === "quit") exit();
|
|
38771
|
+
else if (item.id === "find") patch({ screen: "lookup", tool: toolByName("lookup.find"), input: {}, text: "", selected: 0 });
|
|
38545
38772
|
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
38773
|
else if (item.id === "space") {
|
|
38547
38774
|
back.current = s;
|
|
@@ -38568,12 +38795,27 @@ function InteractiveApp({ session }) {
|
|
|
38568
38795
|
return;
|
|
38569
38796
|
}
|
|
38570
38797
|
if (s.screen === "busy") return;
|
|
38798
|
+
if (s.screen === "home" && input2 === "/") {
|
|
38799
|
+
activate({ id: "find" });
|
|
38800
|
+
return;
|
|
38801
|
+
}
|
|
38571
38802
|
if (key.escape && s.screen === "filter-group") {
|
|
38572
38803
|
patch({ screen: "form", selected: searchGroups(s.tool.input, s.input).findIndex((group) => group.group === s.filterGroup) });
|
|
38573
38804
|
return;
|
|
38574
38805
|
}
|
|
38575
38806
|
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 });
|
|
38807
|
+
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 });
|
|
38808
|
+
return;
|
|
38809
|
+
}
|
|
38810
|
+
if (s.screen === "lookup") {
|
|
38811
|
+
if (key.return && s.text.trim()) void work("Looking up your record...", () => session.lookup(s.text));
|
|
38812
|
+
else if (key.backspace || key.delete) patch({ text: s.text.slice(0, -1) });
|
|
38813
|
+
else if (!key.return && !key.ctrl && !key.meta && !key.upArrow && !key.downArrow) patch({ text: s.text + input2 });
|
|
38814
|
+
return;
|
|
38815
|
+
}
|
|
38816
|
+
if (s.screen === "download-choice") {
|
|
38817
|
+
if (key.upArrow || key.downArrow) patch({ selected: s.selected === 0 ? 1 : 0 });
|
|
38818
|
+
else if (key.return) patch({ screen: "download", field: "New destination .csv or .jsonl file", text: "" });
|
|
38577
38819
|
return;
|
|
38578
38820
|
}
|
|
38579
38821
|
if (["edit", "download", "space", "upload"].includes(s.screen)) {
|
|
@@ -38587,8 +38829,10 @@ function InteractiveApp({ session }) {
|
|
|
38587
38829
|
}
|
|
38588
38830
|
if (s.screen === "download") {
|
|
38589
38831
|
void work("Downloading into a new file...", async () => {
|
|
38590
|
-
await session.download(back.current, s.text)
|
|
38591
|
-
|
|
38832
|
+
const notice = await session.download(back.current, s.text, { all: isSearchResults(back.current.tool?.name) && s.selected === 1, progress: (text2) => {
|
|
38833
|
+
if (mounted.current) patch({ notice: text2 });
|
|
38834
|
+
} });
|
|
38835
|
+
return { ...back.current, notice: `Saved ${s.text}${notice ? `. ${notice}` : ""}` };
|
|
38592
38836
|
});
|
|
38593
38837
|
return;
|
|
38594
38838
|
}
|
|
@@ -38697,15 +38941,15 @@ function InteractiveApp({ session }) {
|
|
|
38697
38941
|
patch({ input: { ...s.input, cursor: s.result.nextCursor } });
|
|
38698
38942
|
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
38943
|
} else if (input2 === "r" && s.tool) runTool(!needsConfirmation(s.tool));
|
|
38700
|
-
else if (input2 === "e") patch({ screen: s.tool ? "form" : "install", selected: 0 });
|
|
38944
|
+
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
38945
|
else if (input2 === "d") {
|
|
38702
38946
|
back.current = s;
|
|
38703
|
-
patch({ screen: "download", field: "New destination .csv or .jsonl file", text: "" });
|
|
38947
|
+
patch({ screen: isSearchResults(s.tool?.name) ? "download-choice" : "download", selected: 0, field: "New destination .csv or .jsonl file", text: "" });
|
|
38704
38948
|
} else if (input2 === "a" && s.tool?.name === "searches.list") {
|
|
38705
38949
|
const row = rowsOf(s.result)[s.selected];
|
|
38706
38950
|
if (row) form("lists.create", { type: "audience", savedSearchId: row.id, recurringEnabled: true, maxRecords: 1e3, maxNewRecordsPerRefresh: 1e3, removeNonmatches: false });
|
|
38707
38951
|
} 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) {
|
|
38952
|
+
else if (key.return && (rowsOf(s.result).length || s.tool?.name !== "lookup.find")) {
|
|
38709
38953
|
void work("Opening the record...", () => session.openRow(s));
|
|
38710
38954
|
}
|
|
38711
38955
|
} else if (s.screen === "detail") {
|
|
@@ -38735,6 +38979,7 @@ var TerminalSession;
|
|
|
38735
38979
|
var init_app = __esm({
|
|
38736
38980
|
"src/terminal/app.tsx"() {
|
|
38737
38981
|
"use strict";
|
|
38982
|
+
init_search_download2();
|
|
38738
38983
|
init_tool_commands();
|
|
38739
38984
|
init_api2();
|
|
38740
38985
|
init_config();
|
|
@@ -38758,6 +39003,12 @@ var init_app = __esm({
|
|
|
38758
39003
|
async load() {
|
|
38759
39004
|
this.config = await this.runtime.readConfig();
|
|
38760
39005
|
}
|
|
39006
|
+
async lookup(query) {
|
|
39007
|
+
const result = await this.call("lookup.find", { query });
|
|
39008
|
+
const state = { ...initialState(), screen: "results", tool: toolByName("lookup.find"), input: { query }, result };
|
|
39009
|
+
if (result.exactMatch === true && rowsOf(result).length === 1) return { ...state, ...await this.openRow(state) };
|
|
39010
|
+
return state;
|
|
39011
|
+
}
|
|
38761
39012
|
settings() {
|
|
38762
39013
|
return resolveSettings(this.config, this.options, this.runtime.env);
|
|
38763
39014
|
}
|
|
@@ -38787,15 +39038,22 @@ var init_app = __esm({
|
|
|
38787
39038
|
this.config.profiles[this.config.activeProfile] = { apiUrl: settings.apiUrl, apiKey: key };
|
|
38788
39039
|
await this.runtime.writeConfig(this.config);
|
|
38789
39040
|
}
|
|
38790
|
-
async download(state, path2) {
|
|
39041
|
+
async download(state, path2, options = {}) {
|
|
38791
39042
|
if (!path2.trim()) throw new CliError("Enter a new destination file.");
|
|
38792
39043
|
path2 = path2.trim();
|
|
38793
39044
|
if (!/\.(csv|jsonl)$/.test(path2)) throw new CliError("Choose a new .csv or .jsonl destination.");
|
|
39045
|
+
if (isSearchResults(state.tool?.name)) {
|
|
39046
|
+
const input2 = { ...state.input };
|
|
39047
|
+
const loadedPage = !options.all || !input2.cursor ? state.result : void 0;
|
|
39048
|
+
if (options.all) delete input2.cursor;
|
|
39049
|
+
const result = await downloadSearch(this.api(), state.tool.name, input2, path2, { ...options, loadedPage, sleep: this.runtime.sleep });
|
|
39050
|
+
return result.capped ? SEARCH_DOWNLOAD_CAP_NOTICE : "";
|
|
39051
|
+
}
|
|
38794
39052
|
const job = state.result.job;
|
|
38795
39053
|
const jobId = state.result.jobId ?? job?.id ?? (state.tool?.name.startsWith("jobs.") ? state.result.id ?? state.input.jobId : void 0);
|
|
38796
39054
|
const exportTool = state.tool?.name === "lists.get" && state.input.id ? "lists.export" : state.tool?.name;
|
|
38797
39055
|
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
|
|
39056
|
+
const file2 = await open7(path2.trim(), "wx", 384);
|
|
38799
39057
|
try {
|
|
38800
39058
|
const format2 = path2.endsWith(".jsonl") ? "jsonl" : "csv";
|
|
38801
39059
|
if (typeof jobId === "string") await downloadBulkJob(this.api(), jobId, format2, async (text2) => {
|
|
@@ -38935,11 +39193,12 @@ async function buildFilters(api, options, kind) {
|
|
|
38935
39193
|
|
|
38936
39194
|
// src/commands.ts
|
|
38937
39195
|
init_output();
|
|
39196
|
+
init_search_download2();
|
|
38938
39197
|
|
|
38939
39198
|
// src/pagination.ts
|
|
38940
39199
|
init_zod();
|
|
38941
39200
|
init_api2();
|
|
38942
|
-
var
|
|
39201
|
+
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
39202
|
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
39203
|
async function pagedTool(api, name, input2, all, exporting = false) {
|
|
38945
39204
|
if (all && api.settings.idempotencyKey) throw new CliError("An idempotency key applies to one page. Omit --all.");
|
|
@@ -38952,7 +39211,7 @@ async function pagedTool(api, name, input2, all, exporting = false) {
|
|
|
38952
39211
|
let empty = true;
|
|
38953
39212
|
while (true) {
|
|
38954
39213
|
const raw = await api.tool(name, { ...input2, ...cursor === void 0 ? {} : { cursor } });
|
|
38955
|
-
const page = (exporting ? exportSchema :
|
|
39214
|
+
const page = (exporting ? exportSchema : pageSchema3).safeParse(raw);
|
|
38956
39215
|
if (!page.success) throw new CliError("The API returned an invalid cursor page.");
|
|
38957
39216
|
if ("items" in page.data) records.push(...page.data.items);
|
|
38958
39217
|
else {
|
|
@@ -39246,10 +39505,18 @@ function registerCommands(program2, runtime) {
|
|
|
39246
39505
|
emit(identity, mode);
|
|
39247
39506
|
});
|
|
39248
39507
|
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) => {
|
|
39508
|
+
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
39509
|
const { api, mode } = await session(command);
|
|
39510
|
+
if (options.out) searchDownloadFormat(options.out);
|
|
39251
39511
|
const filters = await buildFilters(api, options, kind);
|
|
39252
|
-
|
|
39512
|
+
const input2 = { ...filters, limit: options.limit, ...options.cursor ? { cursor: options.cursor } : {}, ...excluded(options) };
|
|
39513
|
+
if (options.out) {
|
|
39514
|
+
const result = await downloadSearch(api, `search.${kind}`, input2, options.out, { all: Boolean(options.all), sleep: runtime.sleep, progress: (text2) => runtime.err(`${text2}
|
|
39515
|
+
`) });
|
|
39516
|
+
if (result.capped) runtime.err(`${SEARCH_DOWNLOAD_CAP_NOTICE}
|
|
39517
|
+
`);
|
|
39518
|
+
emit({ path: options.out, ...result }, mode);
|
|
39519
|
+
} else emit(await pagedTool(api, `search.${kind}`, input2, Boolean(options.all)), mode);
|
|
39253
39520
|
});
|
|
39254
39521
|
addFilterOptions(program2.command("count").description("Estimate companies and their contacts")).action(async (options, command) => {
|
|
39255
39522
|
const { api, mode } = await session(command);
|