@oxygen-agent/cli 1.45.4 → 1.50.37
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 +13 -1
- package/dist/browser-login.d.ts +0 -1
- package/dist/browser-login.js +0 -1
- package/dist/credentials.d.ts +0 -1
- package/dist/credentials.js +114 -44
- package/dist/http-client.d.ts +1 -2
- package/dist/http-client.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +436 -87
- package/dist/local-custom-http-column.d.ts +0 -1
- package/dist/local-custom-http-column.js +1 -2
- package/dist/session.d.ts +0 -1
- package/dist/session.js +0 -1
- package/dist/update.d.ts +31 -0
- package/dist/update.js +116 -0
- package/node_modules/@oxygen/recipe-sdk/dist/index.d.ts +0 -1
- package/node_modules/@oxygen/recipe-sdk/dist/index.js +0 -1
- package/node_modules/@oxygen/shared/dist/billing.d.ts +2 -2
- package/node_modules/@oxygen/shared/dist/billing.js +2 -2
- package/node_modules/@oxygen/shared/dist/cell-format.d.ts +60 -0
- package/node_modules/@oxygen/shared/dist/cell-format.js +278 -0
- package/node_modules/@oxygen/shared/dist/column-types.d.ts +2 -2
- package/node_modules/@oxygen/shared/dist/column-types.js +3 -3
- package/node_modules/@oxygen/shared/dist/credit-guidance.d.ts +0 -1
- package/node_modules/@oxygen/shared/dist/credit-guidance.js +0 -1
- package/node_modules/@oxygen/shared/dist/file-import.d.ts +0 -1
- package/node_modules/@oxygen/shared/dist/file-import.js +1 -2
- package/node_modules/@oxygen/shared/dist/index.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/index.js +1 -1
- package/node_modules/@oxygen/shared/dist/log.d.ts +0 -1
- package/node_modules/@oxygen/shared/dist/log.js +14 -6
- package/node_modules/@oxygen/shared/dist/redaction.d.ts +0 -1
- package/node_modules/@oxygen/shared/dist/redaction.js +0 -1
- package/node_modules/@oxygen/shared/dist/telemetry.d.ts +0 -1
- package/node_modules/@oxygen/shared/dist/telemetry.js +0 -1
- package/node_modules/@oxygen/shared/dist/version.d.ts +1 -2
- package/node_modules/@oxygen/shared/dist/version.js +1 -2
- package/node_modules/@oxygen/workflows/dist/index.d.ts +145 -144
- package/node_modules/@oxygen/workflows/dist/index.js +30 -27
- package/package.json +6 -1
- package/dist/browser-login.d.ts.map +0 -1
- package/dist/browser-login.js.map +0 -1
- package/dist/credentials.d.ts.map +0 -1
- package/dist/credentials.js.map +0 -1
- package/dist/http-client.d.ts.map +0 -1
- package/dist/http-client.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/local-custom-http-column.d.ts.map +0 -1
- package/dist/local-custom-http-column.js.map +0 -1
- package/dist/session.d.ts.map +0 -1
- package/dist/session.js.map +0 -1
- package/node_modules/@oxygen/recipe-sdk/dist/index.d.ts.map +0 -1
- package/node_modules/@oxygen/recipe-sdk/dist/index.js.map +0 -1
- package/node_modules/@oxygen/shared/dist/billing.d.ts.map +0 -1
- package/node_modules/@oxygen/shared/dist/billing.js.map +0 -1
- package/node_modules/@oxygen/shared/dist/column-types.d.ts.map +0 -1
- package/node_modules/@oxygen/shared/dist/column-types.js.map +0 -1
- package/node_modules/@oxygen/shared/dist/credit-guidance.d.ts.map +0 -1
- package/node_modules/@oxygen/shared/dist/credit-guidance.js.map +0 -1
- package/node_modules/@oxygen/shared/dist/file-import.d.ts.map +0 -1
- package/node_modules/@oxygen/shared/dist/file-import.js.map +0 -1
- package/node_modules/@oxygen/shared/dist/index.d.ts.map +0 -1
- package/node_modules/@oxygen/shared/dist/index.js.map +0 -1
- package/node_modules/@oxygen/shared/dist/log.d.ts.map +0 -1
- package/node_modules/@oxygen/shared/dist/log.js.map +0 -1
- package/node_modules/@oxygen/shared/dist/redaction.d.ts.map +0 -1
- package/node_modules/@oxygen/shared/dist/redaction.js.map +0 -1
- package/node_modules/@oxygen/shared/dist/telemetry.d.ts.map +0 -1
- package/node_modules/@oxygen/shared/dist/telemetry.js.map +0 -1
- package/node_modules/@oxygen/shared/dist/version.d.ts.map +0 -1
- package/node_modules/@oxygen/shared/dist/version.js.map +0 -1
- package/node_modules/@oxygen/workflows/dist/index.d.ts.map +0 -1
- package/node_modules/@oxygen/workflows/dist/index.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
// skipcq: JS-0271 — bin entry source; build chmod+x on dist/index.js
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
3
4
|
import { createHash } from "node:crypto";
|
|
4
5
|
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
5
6
|
import { tmpdir } from "node:os";
|
|
@@ -8,7 +9,7 @@ import { createInterface } from "node:readline/promises";
|
|
|
8
9
|
import { stdin as input, stdout as output } from "node:process";
|
|
9
10
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
10
11
|
import { Command } from "commander";
|
|
11
|
-
import { OXYGEN_VERSION, OxygenError, success, toFailure } from "@oxygen/shared";
|
|
12
|
+
import { formatCellForDisplay, OXYGEN_VERSION, OxygenError, success, toFailure } from "@oxygen/shared";
|
|
12
13
|
import { inferRowsFileFormat, normalizeRowsForNewTable, normalizeRowsFormat, parseRowsFileBuffer, } from "@oxygen/shared/file-import";
|
|
13
14
|
import { assertRecipeBundleSafe, assertWorkflowManifest, buildRecipeManifest, compileWorkflowDefinition, isAnyWorkflowManifest, isRecipeManifest, isWorkflowDefinition, isWorkflowManifest, } from "@oxygen/workflows";
|
|
14
15
|
import { isRecipeDefinition } from "@oxygen/recipe-sdk";
|
|
@@ -17,6 +18,7 @@ import { clearCredentials, defaultApiUrl, listCredentialProfiles, normalizeApiUr
|
|
|
17
18
|
import { requestOxygen } from "./http-client.js";
|
|
18
19
|
import { runLocalCustomHttpColumn } from "./local-custom-http-column.js";
|
|
19
20
|
import { addSessionOutput, addSessionStatus, getSessionUsage, startSession, updateSessionStep, } from "./session.js";
|
|
21
|
+
import { updateCli } from "./update.js";
|
|
20
22
|
const BROWSER_LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
|
|
21
23
|
const OXYGEN_SPINNER_INTERVAL_MS = 90;
|
|
22
24
|
const OXYGEN_SPINNER_FRAMES = [
|
|
@@ -43,7 +45,6 @@ const TABLE_INGESTION_WAIT_DEFAULT_TIMEOUT_SECONDS = 600;
|
|
|
43
45
|
const TABLE_INGESTION_WAIT_DEFAULT_INTERVAL_SECONDS = 5;
|
|
44
46
|
const WORKFLOW_TAIL_DEFAULT_TIMEOUT_SECONDS = 600;
|
|
45
47
|
const WORKFLOW_TAIL_DEFAULT_INTERVAL_SECONDS = 2;
|
|
46
|
-
const DEFAULT_CLI_PACKAGE_SPEC = "@oxygen-agent/cli@latest";
|
|
47
48
|
const CLI_MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
48
49
|
const RECIPE_ESBUILD_NODE_PATHS = [
|
|
49
50
|
resolve("node_modules"),
|
|
@@ -227,6 +228,36 @@ export function createProgram() {
|
|
|
227
228
|
.action(async (options) => {
|
|
228
229
|
await handleUpdateAction(options);
|
|
229
230
|
});
|
|
231
|
+
program
|
|
232
|
+
.command("api-keys")
|
|
233
|
+
.description("Manage Oxygen CLI API keys for the current organization.")
|
|
234
|
+
.addCommand(new Command("list")
|
|
235
|
+
.description("List active CLI API keys for the current user and organization.")
|
|
236
|
+
.option("--json", "Print a JSON envelope.")
|
|
237
|
+
.action(async (options) => {
|
|
238
|
+
await handleAsyncAction("api-keys list", options, async () => requestOxygen("/api/cli/api-keys"));
|
|
239
|
+
}))
|
|
240
|
+
.addCommand(new Command("create")
|
|
241
|
+
.description("Create a CLI API key. The token is shown once.")
|
|
242
|
+
.option("--name <name>", "Key name. Defaults to 'CLI key'.")
|
|
243
|
+
.option("--expires-at <iso>", "Expiration timestamp as ISO 8601.")
|
|
244
|
+
.option("--expires-in-days <days>", "Expire the key after this many days.")
|
|
245
|
+
.option("--json", "Print a JSON envelope.")
|
|
246
|
+
.action(async (options) => {
|
|
247
|
+
await handleAsyncAction("api-keys create", options, async () => requestOxygen("/api/cli/api-keys", {
|
|
248
|
+
method: "POST",
|
|
249
|
+
body: buildApiKeyCreateBody(options),
|
|
250
|
+
}));
|
|
251
|
+
}))
|
|
252
|
+
.addCommand(new Command("revoke")
|
|
253
|
+
.description("Revoke a CLI API key for the current user and organization.")
|
|
254
|
+
.argument("<key-id>", "CLI API key id.")
|
|
255
|
+
.option("--json", "Print a JSON envelope.")
|
|
256
|
+
.action(async (keyId, options) => {
|
|
257
|
+
await handleAsyncAction("api-keys revoke", options, async () => requestOxygen(`/api/cli/api-keys/${encodeURIComponent(keyId)}`, {
|
|
258
|
+
method: "DELETE",
|
|
259
|
+
}));
|
|
260
|
+
}));
|
|
230
261
|
program
|
|
231
262
|
.command("whoami")
|
|
232
263
|
.description("Show the current Oxygen CLI identity.")
|
|
@@ -488,9 +519,9 @@ export function createProgram() {
|
|
|
488
519
|
await handleAsyncAction("tables import", options, async () => importRows(table, options));
|
|
489
520
|
}))
|
|
490
521
|
.addCommand(new Command("export")
|
|
491
|
-
.description("Export workspace table rows as JSON, JSONL, or
|
|
522
|
+
.description("Export workspace table rows as JSON, JSONL, CSV, or a human-readable table.")
|
|
492
523
|
.argument("<table>", "Table id or slug.")
|
|
493
|
-
.option("--format <format>", "json, jsonl, or
|
|
524
|
+
.option("--format <format>", "json, jsonl, csv, or table. Defaults to json. Use table for a typed, human-readable rendering with thousands grouping.")
|
|
494
525
|
.option("--output <path>", "Write export content to a file.")
|
|
495
526
|
.option("--limit <n>", "Maximum rows to export. Defaults to 100; hard cap is 1000.")
|
|
496
527
|
.option("--json", "Print a JSON envelope.")
|
|
@@ -587,6 +618,17 @@ export function createProgram() {
|
|
|
587
618
|
method: "POST",
|
|
588
619
|
body: { table },
|
|
589
620
|
}));
|
|
621
|
+
}))
|
|
622
|
+
.addCommand(new Command("move")
|
|
623
|
+
.description("Move a workspace table to a different project.")
|
|
624
|
+
.argument("<table>", "Table id or slug.")
|
|
625
|
+
.requiredOption("--project <project>", "Destination project id or slug.")
|
|
626
|
+
.option("--json", "Print a JSON envelope.")
|
|
627
|
+
.action(async (table, options) => {
|
|
628
|
+
await handleAsyncAction("tables move", options, async () => requestOxygen("/api/cli/tables/move", {
|
|
629
|
+
method: "POST",
|
|
630
|
+
body: { table, project: options.project },
|
|
631
|
+
}));
|
|
590
632
|
}));
|
|
591
633
|
tablesCommand.addCommand(new Command("webhook")
|
|
592
634
|
.description("Create and manage direct table webhooks.")
|
|
@@ -691,6 +733,139 @@ export function createProgram() {
|
|
|
691
733
|
body: { id: assetId },
|
|
692
734
|
}));
|
|
693
735
|
})));
|
|
736
|
+
program
|
|
737
|
+
.command("templates")
|
|
738
|
+
.description("Reusable prompt templates layered into AI columns at run time.")
|
|
739
|
+
.addCommand(new Command("list")
|
|
740
|
+
.description("List prompt templates in the workspace.")
|
|
741
|
+
.option("--kind <kind>", "Filter by ai_column_system, scoring_rubric, or other.")
|
|
742
|
+
.option("--include-archived", "Include archived templates.")
|
|
743
|
+
.option("--json", "Print a JSON envelope.")
|
|
744
|
+
.action(async (options) => {
|
|
745
|
+
await handleAsyncAction("templates list", options, async () => {
|
|
746
|
+
const params = new URLSearchParams();
|
|
747
|
+
if (readOption(options.kind))
|
|
748
|
+
params.set("kind", readOption(options.kind));
|
|
749
|
+
if (options.includeArchived)
|
|
750
|
+
params.set("include_archived", "true");
|
|
751
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
752
|
+
return requestOxygen(`/api/cli/templates${qs}`);
|
|
753
|
+
});
|
|
754
|
+
}))
|
|
755
|
+
.addCommand(new Command("get")
|
|
756
|
+
.description("Read one prompt template by id or slug.")
|
|
757
|
+
.argument("<id_or_slug>", "Template UUID or slug.")
|
|
758
|
+
.option("--json", "Print a JSON envelope.")
|
|
759
|
+
.action(async (idOrSlug, options) => {
|
|
760
|
+
await handleAsyncAction("templates get", options, async () => requestOxygen("/api/cli/templates/get", {
|
|
761
|
+
method: "POST",
|
|
762
|
+
body: idOrSlug.includes("-") && idOrSlug.length >= 32
|
|
763
|
+
? { id: idOrSlug }
|
|
764
|
+
: { slug: idOrSlug },
|
|
765
|
+
}));
|
|
766
|
+
}))
|
|
767
|
+
.addCommand(new Command("upsert")
|
|
768
|
+
.description("Create or update a prompt template.")
|
|
769
|
+
.option("--id <id>", "Existing template UUID to update. Omit to create.")
|
|
770
|
+
.option("--slug <slug>", "Stable slug (kebab-case).")
|
|
771
|
+
.option("--name <name>", "Human-readable name.")
|
|
772
|
+
.option("--description <text>", "Short description.")
|
|
773
|
+
.option("--kind <kind>", "Template kind: ai_column_system, scoring_rubric, or other.")
|
|
774
|
+
.option("--body <text>", "Prompt body.")
|
|
775
|
+
.option("--body-file <path>", "Path to a file containing the prompt body.")
|
|
776
|
+
.option("--json", "Print a JSON envelope.")
|
|
777
|
+
.action(async (options) => {
|
|
778
|
+
await handleAsyncAction("templates upsert", options, async () => {
|
|
779
|
+
const body = {};
|
|
780
|
+
if (readOption(options.id))
|
|
781
|
+
body.id = readOption(options.id);
|
|
782
|
+
if (readOption(options.slug))
|
|
783
|
+
body.slug = readOption(options.slug);
|
|
784
|
+
if (readOption(options.name))
|
|
785
|
+
body.name = readOption(options.name);
|
|
786
|
+
if (readOption(options.description) !== undefined)
|
|
787
|
+
body.description = readOption(options.description);
|
|
788
|
+
if (readOption(options.kind))
|
|
789
|
+
body.kind = readOption(options.kind);
|
|
790
|
+
if (readOption(options.body))
|
|
791
|
+
body.body = readOption(options.body);
|
|
792
|
+
else if (readOption(options.bodyFile)) {
|
|
793
|
+
const path = readOption(options.bodyFile);
|
|
794
|
+
const fs = await import("node:fs/promises");
|
|
795
|
+
body.body = await fs.readFile(path, "utf8");
|
|
796
|
+
}
|
|
797
|
+
return requestOxygen("/api/cli/templates/upsert", { method: "POST", body });
|
|
798
|
+
});
|
|
799
|
+
}))
|
|
800
|
+
.addCommand(new Command("archive")
|
|
801
|
+
.description("Archive a prompt template. Seeded templates cannot be archived.")
|
|
802
|
+
.argument("<id>", "Template UUID.")
|
|
803
|
+
.option("--json", "Print a JSON envelope.")
|
|
804
|
+
.action(async (id, options) => {
|
|
805
|
+
await handleAsyncAction("templates archive", options, async () => requestOxygen("/api/cli/templates/archive", { method: "POST", body: { id } }));
|
|
806
|
+
}));
|
|
807
|
+
program
|
|
808
|
+
.command("reviews")
|
|
809
|
+
.description("Human-in-the-loop reviews for AI-generated outreach messages.")
|
|
810
|
+
.addCommand(new Command("list")
|
|
811
|
+
.description("List message reviews.")
|
|
812
|
+
.option("--status <status>", "Filter by pending, accepted, rejected, or superseded.")
|
|
813
|
+
.option("--table <table_id>", "Filter by table id.")
|
|
814
|
+
.option("--limit <n>", "Max rows to return (default 50, max 200).")
|
|
815
|
+
.option("--json", "Print a JSON envelope.")
|
|
816
|
+
.action(async (options) => {
|
|
817
|
+
await handleAsyncAction("reviews list", options, async () => {
|
|
818
|
+
const params = new URLSearchParams();
|
|
819
|
+
if (readOption(options.status))
|
|
820
|
+
params.set("status", readOption(options.status));
|
|
821
|
+
if (readOption(options.table))
|
|
822
|
+
params.set("table_id", readOption(options.table));
|
|
823
|
+
if (readOption(options.limit))
|
|
824
|
+
params.set("limit", readOption(options.limit));
|
|
825
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
826
|
+
return requestOxygen(`/api/cli/message-reviews${qs}`);
|
|
827
|
+
});
|
|
828
|
+
}))
|
|
829
|
+
.addCommand(new Command("next")
|
|
830
|
+
.description("Read the oldest pending review.")
|
|
831
|
+
.option("--table <table_id>", "Filter by table id.")
|
|
832
|
+
.option("--json", "Print a JSON envelope.")
|
|
833
|
+
.action(async (options) => {
|
|
834
|
+
await handleAsyncAction("reviews next", options, async () => {
|
|
835
|
+
const params = new URLSearchParams();
|
|
836
|
+
if (readOption(options.table))
|
|
837
|
+
params.set("table_id", readOption(options.table));
|
|
838
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
839
|
+
return requestOxygen(`/api/cli/message-reviews/next${qs}`);
|
|
840
|
+
});
|
|
841
|
+
}))
|
|
842
|
+
.addCommand(new Command("accept")
|
|
843
|
+
.description("Accept a pending message review.")
|
|
844
|
+
.argument("<review_id>", "Message review UUID.")
|
|
845
|
+
.option("--json", "Print a JSON envelope.")
|
|
846
|
+
.action(async (reviewId, options) => {
|
|
847
|
+
await handleAsyncAction("reviews accept", options, async () => requestOxygen("/api/cli/message-reviews/decide", {
|
|
848
|
+
method: "POST",
|
|
849
|
+
body: { id: reviewId, decision: "accept" },
|
|
850
|
+
}));
|
|
851
|
+
}))
|
|
852
|
+
.addCommand(new Command("reject")
|
|
853
|
+
.description("Reject a pending message review with optional highlights and auto-rerun.")
|
|
854
|
+
.argument("<review_id>", "Message review UUID.")
|
|
855
|
+
.option("--highlights-json <json>", "JSON array of {start,end,comment} highlight objects.")
|
|
856
|
+
.option("--auto-rerun", "Trigger a single-row rerun of the column after rejecting.")
|
|
857
|
+
.option("--json", "Print a JSON envelope.")
|
|
858
|
+
.action(async (reviewId, options) => {
|
|
859
|
+
await handleAsyncAction("reviews reject", options, async () => {
|
|
860
|
+
const body = { id: reviewId, decision: "reject" };
|
|
861
|
+
if (readOption(options.highlightsJson)) {
|
|
862
|
+
body.highlights = JSON.parse(readOption(options.highlightsJson));
|
|
863
|
+
}
|
|
864
|
+
if (options.autoRerun)
|
|
865
|
+
body.auto_rerun = true;
|
|
866
|
+
return requestOxygen("/api/cli/message-reviews/decide", { method: "POST", body });
|
|
867
|
+
});
|
|
868
|
+
}));
|
|
694
869
|
program
|
|
695
870
|
.command("columns")
|
|
696
871
|
.description("Workspace table column commands.")
|
|
@@ -795,6 +970,24 @@ export function createProgram() {
|
|
|
795
970
|
},
|
|
796
971
|
});
|
|
797
972
|
});
|
|
973
|
+
}))
|
|
974
|
+
.addCommand(new Command("rerun")
|
|
975
|
+
.description("Re-run a single AI column cell, optionally threading a prior message review's feedback into the prompt.")
|
|
976
|
+
.requiredOption("--table <table>", "Table id or slug.")
|
|
977
|
+
.requiredOption("--column <column>", "Column id or key.")
|
|
978
|
+
.requiredOption("--row <row_id>", "Row UUID.")
|
|
979
|
+
.option("--from-review-id <review_id>", "Prior message review whose feedback to thread into the regeneration prompt.")
|
|
980
|
+
.option("--json", "Print a JSON envelope.")
|
|
981
|
+
.action(async (options) => {
|
|
982
|
+
await handleAsyncAction("columns rerun", options, async () => requestOxygen("/api/cli/columns/rerun", {
|
|
983
|
+
method: "POST",
|
|
984
|
+
body: {
|
|
985
|
+
table: options.table,
|
|
986
|
+
column: options.column,
|
|
987
|
+
row_id: options.row,
|
|
988
|
+
...(readOption(options.fromReviewId) ? { from_review_id: readOption(options.fromReviewId) } : {}),
|
|
989
|
+
},
|
|
990
|
+
}));
|
|
798
991
|
}))
|
|
799
992
|
.addCommand(new Command("materialize")
|
|
800
993
|
.description("Materialize useful fields from a JSONB result column into target columns.")
|
|
@@ -1181,6 +1374,48 @@ export function createProgram() {
|
|
|
1181
1374
|
},
|
|
1182
1375
|
}));
|
|
1183
1376
|
}));
|
|
1377
|
+
program
|
|
1378
|
+
.command("companies")
|
|
1379
|
+
.description("Company prospecting and account enrichment workflows.")
|
|
1380
|
+
.addCommand(new Command("enrich")
|
|
1381
|
+
.description("Preview or run a company enrichment waterfall over an existing table.")
|
|
1382
|
+
.addCommand(new Command("preview")
|
|
1383
|
+
.description("Inspect missing company fields, provider routing, and credit estimates without provider calls.")
|
|
1384
|
+
.argument("<table>", "Table id or slug.")
|
|
1385
|
+
.option("--missing-fields <fields>", "Comma-separated fields to fill: domain,linkedin_url,headcount,industry,funding,technologies,hiring_signals,company_profile.")
|
|
1386
|
+
.option("--providers <providers>", "Comma-separated provider order pool. Defaults to blitzapi,crustdata,ai_ark,prospeo,leadmagic.")
|
|
1387
|
+
.option("--all", "Preview all rows.")
|
|
1388
|
+
.option("--limit <n>", "Preview a limited row scope.")
|
|
1389
|
+
.option("--row-ids <ids>", "Comma-separated row ids.")
|
|
1390
|
+
.option("--filter-json <json>", "Filter object or array for row selection.")
|
|
1391
|
+
.option("--selection-json <json>", "Raw table action selection JSON.")
|
|
1392
|
+
.option("--json", "Print a JSON envelope.")
|
|
1393
|
+
.action(async (table, options) => {
|
|
1394
|
+
await handleAsyncAction("companies enrich preview", options, async () => requestOxygen("/api/cli/company-enrichment/preview", {
|
|
1395
|
+
method: "POST",
|
|
1396
|
+
body: readCompaniesEnrichBody(table, options),
|
|
1397
|
+
}));
|
|
1398
|
+
}))
|
|
1399
|
+
.addCommand(new Command("run")
|
|
1400
|
+
.description("Queue a live company enrichment waterfall, or return a dry-run plan.")
|
|
1401
|
+
.argument("<table>", "Table id or slug.")
|
|
1402
|
+
.option("--missing-fields <fields>", "Comma-separated fields to fill.")
|
|
1403
|
+
.option("--providers <providers>", "Comma-separated provider pool.")
|
|
1404
|
+
.option("--mode <mode>", "dry_run or live. Defaults to live.")
|
|
1405
|
+
.option("--max-credits <n>", "Required credit ceiling for live runs.")
|
|
1406
|
+
.option("--all", "Run on all rows.")
|
|
1407
|
+
.option("--limit <n>", "Run on a limited row scope.")
|
|
1408
|
+
.option("--row-ids <ids>", "Comma-separated row ids.")
|
|
1409
|
+
.option("--filter-json <json>", "Filter object or array for row selection.")
|
|
1410
|
+
.option("--selection-json <json>", "Raw table action selection JSON.")
|
|
1411
|
+
.option("--force", "Re-run the waterfall audit column even when it already has a value.")
|
|
1412
|
+
.option("--json", "Print a JSON envelope.")
|
|
1413
|
+
.action(async (table, options) => {
|
|
1414
|
+
await handleAsyncAction("companies enrich run", options, async () => requestOxygen("/api/cli/company-enrichment/run", {
|
|
1415
|
+
method: "POST",
|
|
1416
|
+
body: readCompaniesEnrichBody(table, options),
|
|
1417
|
+
}));
|
|
1418
|
+
})));
|
|
1184
1419
|
program
|
|
1185
1420
|
.command("worker")
|
|
1186
1421
|
.description("Background worker commands.")
|
|
@@ -1614,8 +1849,9 @@ export function createProgram() {
|
|
|
1614
1849
|
.description("Configure provider events that can trigger workflows.")
|
|
1615
1850
|
.addCommand(new Command("list")
|
|
1616
1851
|
.description("List supported provider events and this org's enabled subscriptions.")
|
|
1617
|
-
.option("--source <source>", "Filter by event source, such as hubspot.")
|
|
1852
|
+
.option("--source <source>", "Filter by event source, such as hubspot or composio.gmail.")
|
|
1618
1853
|
.option("--event <event>", "Filter by event type, such as contact.created.")
|
|
1854
|
+
.option("--toolkit <id>", "Filter by toolkit / integration id, such as gmail.")
|
|
1619
1855
|
.option("--json", "Print a JSON envelope.")
|
|
1620
1856
|
.action(async (options) => {
|
|
1621
1857
|
await handleAsyncAction("integrations events list", options, async () => {
|
|
@@ -1624,25 +1860,47 @@ export function createProgram() {
|
|
|
1624
1860
|
query.set("source", readOption(options.source) ?? "");
|
|
1625
1861
|
if (readOption(options.event))
|
|
1626
1862
|
query.set("event", readOption(options.event) ?? "");
|
|
1863
|
+
if (readOption(options.toolkit))
|
|
1864
|
+
query.set("toolkit", readOption(options.toolkit) ?? "");
|
|
1627
1865
|
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
1628
1866
|
return requestOxygen(`/api/cli/integrations/events${suffix}`);
|
|
1629
1867
|
});
|
|
1630
1868
|
}))
|
|
1631
1869
|
.addCommand(new Command("enable")
|
|
1632
1870
|
.description("Enable a provider event for a connected integration account.")
|
|
1633
|
-
.requiredOption("--source <source>", "Event source, such as hubspot.")
|
|
1871
|
+
.requiredOption("--source <source>", "Event source, such as hubspot or composio.gmail.")
|
|
1634
1872
|
.requiredOption("--event <event>", "Event type, such as contact.created.")
|
|
1635
1873
|
.option("--connection-id <connection_id>", "Specific integration connection id. Defaults to the active default connection.")
|
|
1874
|
+
.option("--trigger-config <json>", "JSON object passed to the provider when registering the trigger (Composio triggers only).")
|
|
1636
1875
|
.option("--json", "Print a JSON envelope.")
|
|
1637
1876
|
.action(async (options) => {
|
|
1638
|
-
await handleAsyncAction("integrations events enable", options, async () =>
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1877
|
+
await handleAsyncAction("integrations events enable", options, async () => {
|
|
1878
|
+
const triggerConfigRaw = readOption(options.triggerConfig);
|
|
1879
|
+
let triggerConfig;
|
|
1880
|
+
if (triggerConfigRaw) {
|
|
1881
|
+
try {
|
|
1882
|
+
const parsed = JSON.parse(triggerConfigRaw);
|
|
1883
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1884
|
+
throw new Error("--trigger-config must be a JSON object.");
|
|
1885
|
+
}
|
|
1886
|
+
triggerConfig = parsed;
|
|
1887
|
+
}
|
|
1888
|
+
catch (error) {
|
|
1889
|
+
throw new Error(error instanceof Error
|
|
1890
|
+
? `Invalid --trigger-config: ${error.message}`
|
|
1891
|
+
: "Invalid --trigger-config");
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
return requestOxygen("/api/cli/integrations/events/enable", {
|
|
1895
|
+
method: "POST",
|
|
1896
|
+
body: {
|
|
1897
|
+
source: readOption(options.source),
|
|
1898
|
+
event: readOption(options.event),
|
|
1899
|
+
...(readOption(options.connectionId) ? { connection_id: readOption(options.connectionId) } : {}),
|
|
1900
|
+
...(triggerConfig ? { trigger_config: triggerConfig } : {}),
|
|
1901
|
+
},
|
|
1902
|
+
});
|
|
1903
|
+
});
|
|
1646
1904
|
}))
|
|
1647
1905
|
.addCommand(new Command("disable")
|
|
1648
1906
|
.description("Disable a provider event for a connected integration account.")
|
|
@@ -2153,6 +2411,7 @@ function referencesRecipeSdk(source) {
|
|
|
2153
2411
|
// Escape Next static analysis (the CLI is bundled by tsc, but mirror the
|
|
2154
2412
|
// worker's escape so both load identically).
|
|
2155
2413
|
const dynamicRecipeImport = new Function("specifier", "return import(specifier);");
|
|
2414
|
+
// skipcq: JS-R1003
|
|
2156
2415
|
async function importRecipeModule(specifier) {
|
|
2157
2416
|
try {
|
|
2158
2417
|
return await dynamicRecipeImport(specifier);
|
|
@@ -2354,6 +2613,55 @@ function readTableRunSelection(options) {
|
|
|
2354
2613
|
exitCode: 1,
|
|
2355
2614
|
});
|
|
2356
2615
|
}
|
|
2616
|
+
function readCompaniesEnrichBody(table, options) {
|
|
2617
|
+
const body = { table };
|
|
2618
|
+
const fields = readCsvOption(options.missingFields);
|
|
2619
|
+
const providers = readCsvOption(options.providers);
|
|
2620
|
+
const selection = readCompaniesEnrichSelection(options);
|
|
2621
|
+
const mode = readOption(options.mode);
|
|
2622
|
+
const maxCredits = readPositiveNumber(options.maxCredits);
|
|
2623
|
+
if (fields.length > 0)
|
|
2624
|
+
body.missing_fields = fields;
|
|
2625
|
+
if (providers.length > 0)
|
|
2626
|
+
body.providers = providers;
|
|
2627
|
+
if (selection)
|
|
2628
|
+
body.selection = selection;
|
|
2629
|
+
if (mode)
|
|
2630
|
+
body.mode = mode;
|
|
2631
|
+
if (maxCredits !== undefined)
|
|
2632
|
+
body.max_credits = maxCredits;
|
|
2633
|
+
if (options.force !== undefined)
|
|
2634
|
+
body.force = Boolean(options.force);
|
|
2635
|
+
return body;
|
|
2636
|
+
}
|
|
2637
|
+
function readCompaniesEnrichSelection(options) {
|
|
2638
|
+
const explicitSelection = readSelectionJsonOption(options.selectionJson);
|
|
2639
|
+
const hasAll = Boolean(options.all);
|
|
2640
|
+
const limit = readPositiveInt(options.limit);
|
|
2641
|
+
const rowIds = readCsvOption(options.rowIds);
|
|
2642
|
+
const filterSelection = readFilterSelectionOption(options.filterJson);
|
|
2643
|
+
const selectedModes = [
|
|
2644
|
+
Boolean(explicitSelection),
|
|
2645
|
+
hasAll,
|
|
2646
|
+
Boolean(limit),
|
|
2647
|
+
rowIds.length > 0,
|
|
2648
|
+
Boolean(filterSelection),
|
|
2649
|
+
].filter(Boolean).length;
|
|
2650
|
+
if (selectedModes > 1) {
|
|
2651
|
+
throw new OxygenError("invalid_company_enrichment", "Pass only one row scope option.", { exitCode: 1 });
|
|
2652
|
+
}
|
|
2653
|
+
if (explicitSelection)
|
|
2654
|
+
return explicitSelection;
|
|
2655
|
+
if (hasAll)
|
|
2656
|
+
return { mode: "all" };
|
|
2657
|
+
if (limit)
|
|
2658
|
+
return { mode: "limit", limit };
|
|
2659
|
+
if (rowIds.length > 0)
|
|
2660
|
+
return { mode: "row_ids", row_ids: rowIds };
|
|
2661
|
+
if (filterSelection)
|
|
2662
|
+
return filterSelection;
|
|
2663
|
+
return undefined;
|
|
2664
|
+
}
|
|
2357
2665
|
function readFilterSelectionOption(value) {
|
|
2358
2666
|
const filters = readFilterJsonOption(value);
|
|
2359
2667
|
return filters ? { mode: "filter", filters } : undefined;
|
|
@@ -2569,11 +2877,13 @@ async function prepareImportTarget(table, options, parsedRows) {
|
|
|
2569
2877
|
exitCode: 1,
|
|
2570
2878
|
});
|
|
2571
2879
|
}
|
|
2880
|
+
const createdWebUrl = readRecordString(created, "web_url")
|
|
2881
|
+
?? readRecordString(created, "deepLink");
|
|
2572
2882
|
return {
|
|
2573
2883
|
tableRef: createdSlug,
|
|
2574
2884
|
rows: normalized.rows,
|
|
2575
2885
|
createdTable: created,
|
|
2576
|
-
tableWebUrl: tableWebUrl(createdSlug),
|
|
2886
|
+
tableWebUrl: createdWebUrl ?? tableWebUrl(createdSlug),
|
|
2577
2887
|
upsertKey: normalizeCreatedTableUpsertKey(options.upsertKey, normalized.keyBySource),
|
|
2578
2888
|
};
|
|
2579
2889
|
}
|
|
@@ -2756,16 +3066,17 @@ async function exportRows(table, options) {
|
|
|
2756
3066
|
...(limit ? { limit } : {}),
|
|
2757
3067
|
},
|
|
2758
3068
|
});
|
|
2759
|
-
const
|
|
3069
|
+
const formatted = formatRows(result.rows, format, result.columns);
|
|
2760
3070
|
if (options.output) {
|
|
2761
|
-
writeFileSync(options.output, content);
|
|
3071
|
+
writeFileSync(options.output, formatted.content);
|
|
2762
3072
|
}
|
|
2763
3073
|
return {
|
|
2764
3074
|
table: result.table ?? null,
|
|
2765
3075
|
format,
|
|
2766
3076
|
rowCount: result.rows.length,
|
|
2767
3077
|
output: options.output ?? null,
|
|
2768
|
-
...(options.output ? {} : { content }),
|
|
3078
|
+
...(options.output ? {} : { content: formatted.content }),
|
|
3079
|
+
...(formatted.rescuedCount > 0 ? { rescuedNumericCells: formatted.rescuedCount } : {}),
|
|
2769
3080
|
};
|
|
2770
3081
|
}
|
|
2771
3082
|
async function readRowsFile(path, format, sheet) {
|
|
@@ -2778,18 +3089,26 @@ function normalizeCreatedTableUpsertKey(value, keyBySource) {
|
|
|
2778
3089
|
}
|
|
2779
3090
|
function normalizeExportRowsFormat(value) {
|
|
2780
3091
|
const normalized = value?.trim().toLowerCase() || "json";
|
|
2781
|
-
if (normalized === "json"
|
|
3092
|
+
if (normalized === "json"
|
|
3093
|
+
|| normalized === "jsonl"
|
|
3094
|
+
|| normalized === "csv"
|
|
3095
|
+
|| normalized === "table")
|
|
2782
3096
|
return normalized;
|
|
2783
|
-
throw new OxygenError("invalid_format", "Export format must be json, jsonl, or
|
|
3097
|
+
throw new OxygenError("invalid_format", "Export format must be json, jsonl, csv, or table.", {
|
|
2784
3098
|
details: { format: value },
|
|
2785
3099
|
exitCode: 1,
|
|
2786
3100
|
});
|
|
2787
3101
|
}
|
|
2788
3102
|
function formatRows(rows, format, columns) {
|
|
2789
|
-
if (format === "json")
|
|
2790
|
-
return `${JSON.stringify(rows, null, 2)}\n
|
|
2791
|
-
|
|
2792
|
-
|
|
3103
|
+
if (format === "json") {
|
|
3104
|
+
return { content: `${JSON.stringify(rows, null, 2)}\n`, rescuedCount: 0 };
|
|
3105
|
+
}
|
|
3106
|
+
if (format === "jsonl") {
|
|
3107
|
+
return {
|
|
3108
|
+
content: `${rows.map((row) => JSON.stringify(row)).join("\n")}\n`,
|
|
3109
|
+
rescuedCount: 0,
|
|
3110
|
+
};
|
|
3111
|
+
} // skipcq: JS-0246
|
|
2793
3112
|
const keys = [
|
|
2794
3113
|
"_row_id",
|
|
2795
3114
|
"_created_at",
|
|
@@ -2797,10 +3116,57 @@ function formatRows(rows, format, columns) {
|
|
|
2797
3116
|
...(columns?.map((column) => column.key) ?? []),
|
|
2798
3117
|
...rows.flatMap((row) => Object.keys(row)),
|
|
2799
3118
|
].filter((key, index, all) => all.indexOf(key) === index && rows.some((row) => key in row));
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
3119
|
+
if (format === "csv") {
|
|
3120
|
+
return {
|
|
3121
|
+
content: [
|
|
3122
|
+
keys.map(escapeCsvField).join(","),
|
|
3123
|
+
...rows.map((row) => keys.map((key) => escapeCsvField(row[key])).join(",")),
|
|
3124
|
+
].join("\n") + "\n",
|
|
3125
|
+
rescuedCount: 0,
|
|
3126
|
+
};
|
|
3127
|
+
}
|
|
3128
|
+
// "table": render with type-aware formatting and a Markdown-style frame.
|
|
3129
|
+
const columnByKey = new Map(columns?.map((c) => [c.key, c]) ?? []);
|
|
3130
|
+
let rescuedCount = 0;
|
|
3131
|
+
const headers = keys.map((key) => columnByKey.get(key)?.label ?? key);
|
|
3132
|
+
const formattedRows = rows.map((row) => keys.map((key) => {
|
|
3133
|
+
const column = columnByKey.get(key) ?? null;
|
|
3134
|
+
const formatted = formatCellForDisplay(row[key], column, {
|
|
3135
|
+
surface: "cli",
|
|
3136
|
+
onRescued: () => {
|
|
3137
|
+
rescuedCount += 1;
|
|
3138
|
+
},
|
|
3139
|
+
});
|
|
3140
|
+
// Pipe and any line-break char are the row/cell delimiters of the
|
|
3141
|
+
// Markdown frame — raw values containing them would corrupt the layout.
|
|
3142
|
+
// Match on the line-break class (not just `\r?\n`) so a standalone `\r`
|
|
3143
|
+
// doesn't slip through and split the row visually.
|
|
3144
|
+
return formatted.replace(/[\r\n]+/g, " ↵ ").replace(/\|/g, "\\|");
|
|
3145
|
+
}));
|
|
3146
|
+
const widths = headers.map((header, columnIndex) => {
|
|
3147
|
+
let max = header.length;
|
|
3148
|
+
for (const row of formattedRows) {
|
|
3149
|
+
const cell = row[columnIndex] ?? "";
|
|
3150
|
+
if (cell.length > max)
|
|
3151
|
+
max = cell.length;
|
|
3152
|
+
}
|
|
3153
|
+
return Math.min(max, 60);
|
|
3154
|
+
});
|
|
3155
|
+
const renderRow = (cells) => "| " + cells.map((cell, i) => clipCell(cell, widths[i]).padEnd(widths[i])).join(" | ") + " |";
|
|
3156
|
+
const separator = "|" + widths.map((w) => "-".repeat(w + 2)).join("|") + "|";
|
|
3157
|
+
const lines = [renderRow(headers), separator, ...formattedRows.map(renderRow)];
|
|
3158
|
+
if (rescuedCount > 0) {
|
|
3159
|
+
lines.push("");
|
|
3160
|
+
lines.push(`# Note: reformatted ${rescuedCount} cell${rescuedCount === 1 ? "" : "s"} that look numeric in text columns. Run \`oxygen columns retype --to numeric\` to make this permanent.`);
|
|
3161
|
+
}
|
|
3162
|
+
return { content: lines.join("\n") + "\n", rescuedCount };
|
|
3163
|
+
}
|
|
3164
|
+
function clipCell(value, width) {
|
|
3165
|
+
if (value.length <= width)
|
|
3166
|
+
return value;
|
|
3167
|
+
if (width <= 1)
|
|
3168
|
+
return value.slice(0, width);
|
|
3169
|
+
return value.slice(0, width - 1) + "…";
|
|
2804
3170
|
}
|
|
2805
3171
|
function escapeCsvField(value) {
|
|
2806
3172
|
const text = value === null || value === undefined
|
|
@@ -3000,64 +3366,46 @@ async function handleUpdateAction(options) {
|
|
|
3000
3366
|
process.exitCode = error instanceof OxygenError ? error.exitCode : 1;
|
|
3001
3367
|
}
|
|
3002
3368
|
}
|
|
3003
|
-
function
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3369
|
+
function buildApiKeyCreateBody(options) {
|
|
3370
|
+
const body = {};
|
|
3371
|
+
const name = readOption(options.name);
|
|
3372
|
+
if (name)
|
|
3373
|
+
body.name = name;
|
|
3374
|
+
const expiresAt = resolveApiKeyExpiresAt(options);
|
|
3375
|
+
if (expiresAt)
|
|
3376
|
+
body.expires_at = expiresAt;
|
|
3377
|
+
return body;
|
|
3378
|
+
}
|
|
3379
|
+
function resolveApiKeyExpiresAt(options) {
|
|
3380
|
+
const expiresAt = readOption(options.expiresAt);
|
|
3381
|
+
const expiresInDays = readOption(options.expiresInDays);
|
|
3382
|
+
if (expiresAt && expiresInDays) {
|
|
3383
|
+
throw new OxygenError("conflicting_flags", "Pass either --expires-at or --expires-in-days, not both.", {
|
|
3384
|
+
exitCode: 1,
|
|
3385
|
+
});
|
|
3386
|
+
}
|
|
3387
|
+
if (expiresAt) {
|
|
3388
|
+
const date = new Date(expiresAt);
|
|
3389
|
+
if (!Number.isFinite(date.getTime())) {
|
|
3390
|
+
throw new OxygenError("invalid_expires_at", "--expires-at must be a valid ISO 8601 timestamp.", {
|
|
3391
|
+
details: { expires_at: expiresAt },
|
|
3392
|
+
exitCode: 1,
|
|
3393
|
+
});
|
|
3014
3394
|
}
|
|
3395
|
+
return date.toISOString();
|
|
3015
3396
|
}
|
|
3016
|
-
|
|
3017
|
-
|
|
3397
|
+
if (expiresInDays) {
|
|
3398
|
+
const days = readPositiveInt(expiresInDays);
|
|
3399
|
+
if (!days) {
|
|
3400
|
+
throw new OxygenError("invalid_number", "--expires-in-days must be a positive integer.", {
|
|
3401
|
+
details: { value: expiresInDays },
|
|
3402
|
+
exitCode: 1,
|
|
3403
|
+
});
|
|
3404
|
+
}
|
|
3405
|
+
return new Date(Date.now() + days * 24 * 60 * 60 * 1000).toISOString();
|
|
3018
3406
|
}
|
|
3019
3407
|
return null;
|
|
3020
3408
|
}
|
|
3021
|
-
function updateCli(options) {
|
|
3022
|
-
const packageSpec = readOption(options.package) ?? DEFAULT_CLI_PACKAGE_SPEC;
|
|
3023
|
-
const prefix = detectCliInstallPrefix();
|
|
3024
|
-
const args = prefix
|
|
3025
|
-
? ["install", "-g", "--prefix", prefix, packageSpec]
|
|
3026
|
-
: ["install", "-g", packageSpec];
|
|
3027
|
-
const command = ["npm", ...args].join(" ");
|
|
3028
|
-
if (options.dryRun) {
|
|
3029
|
-
return {
|
|
3030
|
-
current_version: OXYGEN_VERSION,
|
|
3031
|
-
package: packageSpec,
|
|
3032
|
-
command,
|
|
3033
|
-
dry_run: true,
|
|
3034
|
-
updated: false,
|
|
3035
|
-
};
|
|
3036
|
-
}
|
|
3037
|
-
const result = spawnSync("npm", args, {
|
|
3038
|
-
encoding: "utf8",
|
|
3039
|
-
stdio: options.json ? ["ignore", "pipe", "pipe"] : "inherit",
|
|
3040
|
-
});
|
|
3041
|
-
if (result.error || result.status !== 0) {
|
|
3042
|
-
throw new OxygenError("cli_update_failed", "Unable to update the Oxygen CLI.", {
|
|
3043
|
-
details: {
|
|
3044
|
-
command,
|
|
3045
|
-
package: packageSpec,
|
|
3046
|
-
exit_code: result.status,
|
|
3047
|
-
reason: result.error instanceof Error ? result.error.message : null,
|
|
3048
|
-
stderr: typeof result.stderr === "string" && result.stderr.trim() ? result.stderr.trim().slice(0, 4000) : null,
|
|
3049
|
-
},
|
|
3050
|
-
exitCode: 1,
|
|
3051
|
-
});
|
|
3052
|
-
}
|
|
3053
|
-
return {
|
|
3054
|
-
current_version: OXYGEN_VERSION,
|
|
3055
|
-
package: packageSpec,
|
|
3056
|
-
command,
|
|
3057
|
-
dry_run: false,
|
|
3058
|
-
updated: true,
|
|
3059
|
-
};
|
|
3060
|
-
}
|
|
3061
3409
|
async function login(options) {
|
|
3062
3410
|
const apiUrl = normalizeApiUrl(readOption(options.apiUrl) ?? defaultApiUrl());
|
|
3063
3411
|
const token = readOption(options.token) ?? await promptForToken({
|
|
@@ -3255,6 +3603,7 @@ function formatLoginSuccess(identity, credentials, profile) {
|
|
|
3255
3603
|
.update(`oxygen-cli:${credentials.token}`)
|
|
3256
3604
|
.digest("hex");
|
|
3257
3605
|
const c = ansi(output.isTTY === true && !process.env.NO_COLOR);
|
|
3606
|
+
// skipcq: JS-0820 — not a React component; rule misfire on array of tuples
|
|
3258
3607
|
const rows = [
|
|
3259
3608
|
["Account", email],
|
|
3260
3609
|
["Organization", org],
|
|
@@ -3331,7 +3680,7 @@ function formatProfileUseSuccess(profile) {
|
|
|
3331
3680
|
` ${c.dim("Fingerprint")} ${profile.token_fingerprint}`,
|
|
3332
3681
|
"",
|
|
3333
3682
|
].join("\n");
|
|
3334
|
-
}
|
|
3683
|
+
} // skipcq: JS-C1002
|
|
3335
3684
|
function formatLogoutSuccess(result) {
|
|
3336
3685
|
const c = ansi(output.isTTY === true && !process.env.NO_COLOR);
|
|
3337
3686
|
const removed = result.removedProfile
|
|
@@ -3342,7 +3691,7 @@ function formatLogoutSuccess(result) {
|
|
|
3342
3691
|
`${c.green("[OK]")} ${c.bold("CLI logged out")}`,
|
|
3343
3692
|
"",
|
|
3344
3693
|
` ${c.dim("Credentials")} ${removed}`,
|
|
3345
|
-
` ${c.dim("Profiles left")} ${String(result.remainingProfiles)}`,
|
|
3694
|
+
` ${c.dim("Profiles left")} ${String(result.remainingProfiles)}`, // skipcq: JS-C1002
|
|
3346
3695
|
"",
|
|
3347
3696
|
].join("\n");
|
|
3348
3697
|
}
|
|
@@ -3357,7 +3706,7 @@ function formatUpdateSuccess(result) {
|
|
|
3357
3706
|
` ${c.dim("Command")} ${result.command}`,
|
|
3358
3707
|
"",
|
|
3359
3708
|
].join("\n");
|
|
3360
|
-
}
|
|
3709
|
+
} // skipcq: JS-C1002
|
|
3361
3710
|
function renderBox(lines) {
|
|
3362
3711
|
const width = Math.max(...lines.map(visibleLength), 0);
|
|
3363
3712
|
const border = `+${"-".repeat(width + 2)}+`;
|
|
@@ -3365,6 +3714,7 @@ function renderBox(lines) {
|
|
|
3365
3714
|
return [border, ...body, border].join("\n");
|
|
3366
3715
|
}
|
|
3367
3716
|
function visibleLength(value) {
|
|
3717
|
+
// skipcq: JS-0004 — ESC (\x1b) is the ANSI CSI introducer; required to strip color codes
|
|
3368
3718
|
return value.replace(/\x1b\[[0-9;]*m/g, "").length;
|
|
3369
3719
|
}
|
|
3370
3720
|
function ansi(enabled) {
|
|
@@ -3372,7 +3722,7 @@ function ansi(enabled) {
|
|
|
3372
3722
|
? (text) => `\x1b[${open}m${text}\x1b[${close}m`
|
|
3373
3723
|
: (text) => text;
|
|
3374
3724
|
return {
|
|
3375
|
-
bold: wrap(1, 22),
|
|
3725
|
+
bold: wrap(1, 22), // skipcq: JS-0117 // skipcq: JS-W1035
|
|
3376
3726
|
dim: wrap(2, 22),
|
|
3377
3727
|
green: wrap(32, 39),
|
|
3378
3728
|
};
|
|
@@ -3520,4 +3870,3 @@ function muteTokenEcho() {
|
|
|
3520
3870
|
}
|
|
3521
3871
|
}
|
|
3522
3872
|
await createProgram().parseAsync(process.argv);
|
|
3523
|
-
//# sourceMappingURL=index.js.map
|