securewithtrace 0.20.0 → 0.20.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/dist/index.js +246 -99
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24235,6 +24235,14 @@ var ScanTriggerTypeValues = [
|
|
|
24235
24235
|
var ScanTriggerType = external_exports.enum(ScanTriggerTypeValues);
|
|
24236
24236
|
|
|
24237
24237
|
// ../../packages/api-contracts/src/schemas/api/v1/scan.api.ts
|
|
24238
|
+
var ScanProviderValues = ["bedrock"];
|
|
24239
|
+
var ScanConfigurationSchema = external_exports.object({
|
|
24240
|
+
/**
|
|
24241
|
+
* Override the LLM provider used for this scan.
|
|
24242
|
+
* Staff-only — must be enforced server-side.
|
|
24243
|
+
*/
|
|
24244
|
+
provider: external_exports.enum(ScanProviderValues).optional()
|
|
24245
|
+
}).strict();
|
|
24238
24246
|
var ScanIdParamsSchema = OrgIdParamsSchema.extend({
|
|
24239
24247
|
scanId: external_exports.uuid()
|
|
24240
24248
|
});
|
|
@@ -24244,7 +24252,7 @@ var CreateScanRequestSchema = external_exports.discriminatedUnion("scanMode", [
|
|
|
24244
24252
|
webApplicationId: external_exports.uuid(),
|
|
24245
24253
|
targetUrl: external_exports.url(),
|
|
24246
24254
|
userProvidedContext: external_exports.string().optional(),
|
|
24247
|
-
scanConfiguration:
|
|
24255
|
+
scanConfiguration: ScanConfigurationSchema.optional()
|
|
24248
24256
|
}),
|
|
24249
24257
|
external_exports.object({
|
|
24250
24258
|
scanMode: external_exports.literal("SAST"),
|
|
@@ -24252,7 +24260,7 @@ var CreateScanRequestSchema = external_exports.discriminatedUnion("scanMode", [
|
|
|
24252
24260
|
branch: external_exports.string().optional(),
|
|
24253
24261
|
scanType: external_exports.enum(["FULL", "INCREMENTAL"]).optional(),
|
|
24254
24262
|
userProvidedContext: external_exports.string().optional(),
|
|
24255
|
-
scanConfiguration:
|
|
24263
|
+
scanConfiguration: ScanConfigurationSchema.optional()
|
|
24256
24264
|
}),
|
|
24257
24265
|
external_exports.object({
|
|
24258
24266
|
scanMode: external_exports.literal("SCA"),
|
|
@@ -24260,7 +24268,7 @@ var CreateScanRequestSchema = external_exports.discriminatedUnion("scanMode", [
|
|
|
24260
24268
|
branch: external_exports.string().optional(),
|
|
24261
24269
|
scanType: external_exports.enum(["FULL", "INCREMENTAL"]).optional(),
|
|
24262
24270
|
userProvidedContext: external_exports.string().optional(),
|
|
24263
|
-
scanConfiguration:
|
|
24271
|
+
scanConfiguration: ScanConfigurationSchema.optional()
|
|
24264
24272
|
}),
|
|
24265
24273
|
external_exports.object({
|
|
24266
24274
|
scanMode: external_exports.literal("SECRETS"),
|
|
@@ -24268,7 +24276,7 @@ var CreateScanRequestSchema = external_exports.discriminatedUnion("scanMode", [
|
|
|
24268
24276
|
branch: external_exports.string().optional(),
|
|
24269
24277
|
scanType: external_exports.enum(["FULL", "INCREMENTAL"]).optional(),
|
|
24270
24278
|
userProvidedContext: external_exports.string().optional(),
|
|
24271
|
-
scanConfiguration:
|
|
24279
|
+
scanConfiguration: ScanConfigurationSchema.optional()
|
|
24272
24280
|
})
|
|
24273
24281
|
]);
|
|
24274
24282
|
var ScanResponseSchema = external_exports.object({
|
|
@@ -26673,7 +26681,7 @@ Examples:
|
|
|
26673
26681
|
const existingToken = readToken();
|
|
26674
26682
|
if (existingToken) {
|
|
26675
26683
|
console.log(
|
|
26676
|
-
`${colorWarning("You are already logged in.")} Run \`
|
|
26684
|
+
`${colorWarning("You are already logged in.")} Run \`tracecli auth logout\` first to re-authenticate.`
|
|
26677
26685
|
);
|
|
26678
26686
|
return;
|
|
26679
26687
|
}
|
|
@@ -26771,6 +26779,7 @@ Examples:
|
|
|
26771
26779
|
return;
|
|
26772
26780
|
}
|
|
26773
26781
|
if (options.output === "tsv") {
|
|
26782
|
+
console.log("loggedIn expired hasRefreshToken userId orgId activeOrg");
|
|
26774
26783
|
console.log(
|
|
26775
26784
|
[
|
|
26776
26785
|
String(info.loggedIn),
|
|
@@ -26840,6 +26849,7 @@ Examples:
|
|
|
26840
26849
|
return;
|
|
26841
26850
|
}
|
|
26842
26851
|
if (options.output === "tsv") {
|
|
26852
|
+
console.log("name slug organizationId active");
|
|
26843
26853
|
for (const item of items) {
|
|
26844
26854
|
console.log(
|
|
26845
26855
|
[
|
|
@@ -26893,6 +26903,7 @@ Examples:
|
|
|
26893
26903
|
return;
|
|
26894
26904
|
}
|
|
26895
26905
|
if (options.output === "tsv") {
|
|
26906
|
+
console.log("name slug organizationId source");
|
|
26896
26907
|
console.log(
|
|
26897
26908
|
[
|
|
26898
26909
|
tsvSafe(active.name),
|
|
@@ -27353,7 +27364,15 @@ function resolveShell(shellOption) {
|
|
|
27353
27364
|
return shell;
|
|
27354
27365
|
}
|
|
27355
27366
|
function createCompletionCommand(program3) {
|
|
27356
|
-
return new Command("completion").description("Generate shell completion script").option("--shell <shell>", `Shell type (${SUPPORTED_SHELLS.join(", ")})`).
|
|
27367
|
+
return new Command("completion").description("Generate shell completion script").option("--shell <shell>", `Shell type (${SUPPORTED_SHELLS.join(", ")})`).addHelpText(
|
|
27368
|
+
"after",
|
|
27369
|
+
`
|
|
27370
|
+
Examples:
|
|
27371
|
+
tracecli completion --shell bash
|
|
27372
|
+
tracecli completion --shell zsh
|
|
27373
|
+
tracecli completion --shell fish
|
|
27374
|
+
tracecli completion # auto-detects shell from $SHELL`
|
|
27375
|
+
).action((options) => {
|
|
27357
27376
|
const shell = resolveShell(options.shell);
|
|
27358
27377
|
const script = generateCompletion(program3, shell);
|
|
27359
27378
|
const writtenPath = writeCompletionFile(shell, script);
|
|
@@ -27457,6 +27476,10 @@ Run \`tracecli pentest list\` to see available pentests.`
|
|
|
27457
27476
|
}
|
|
27458
27477
|
function createListCommand() {
|
|
27459
27478
|
return new Command("list").description("List pentests for your organization").option(
|
|
27479
|
+
"--status <status>",
|
|
27480
|
+
"Filter by status (SCOPING, IN_PROGRESS, REMEDIATION, CLOSED)",
|
|
27481
|
+
(value) => value.toUpperCase()
|
|
27482
|
+
).option(
|
|
27460
27483
|
"-L, --limit <n>",
|
|
27461
27484
|
`Max results to return (default: ${DEFAULT_LIMIT}, max: ${MAX_LIMIT})`,
|
|
27462
27485
|
(v) => {
|
|
@@ -27471,6 +27494,7 @@ function createListCommand() {
|
|
|
27471
27494
|
`
|
|
27472
27495
|
Examples:
|
|
27473
27496
|
tracecli pentest list
|
|
27497
|
+
tracecli pentest list --status IN_PROGRESS
|
|
27474
27498
|
tracecli pentest list --limit 10
|
|
27475
27499
|
tracecli pentest list --output json | jq '.[].title'
|
|
27476
27500
|
tracecli pentest list --output tsv | cut -f1,2`
|
|
@@ -27489,8 +27513,12 @@ Examples:
|
|
|
27489
27513
|
console.error(`Failed to list pentests (status ${result.status}).`);
|
|
27490
27514
|
process.exit(1);
|
|
27491
27515
|
}
|
|
27516
|
+
let filteredPentests = result.body;
|
|
27517
|
+
if (options.status) {
|
|
27518
|
+
filteredPentests = filteredPentests.filter((p2) => p2.status === options.status);
|
|
27519
|
+
}
|
|
27492
27520
|
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
27493
|
-
const pentests =
|
|
27521
|
+
const pentests = filteredPentests.slice(0, limit);
|
|
27494
27522
|
const isJson = options.output === "json";
|
|
27495
27523
|
const isTsv = options.output === "tsv";
|
|
27496
27524
|
if (pentests.length === 0) {
|
|
@@ -27540,89 +27568,119 @@ Examples:
|
|
|
27540
27568
|
});
|
|
27541
27569
|
}
|
|
27542
27570
|
function createFindingsListCommand() {
|
|
27543
|
-
return new Command("list").description("List findings for a pentest").requiredOption("--pentest <id>", "Pentest display ID (e.g. PT-3) or UUID").option(
|
|
27571
|
+
return new Command("list").description("List findings for a pentest").requiredOption("--pentest <id>", "Pentest display ID (e.g. PT-3) or UUID").option(
|
|
27572
|
+
"--severity <severity>",
|
|
27573
|
+
"Filter by severity (CRITICAL, HIGH, MEDIUM, LOW, INFORMATIONAL)",
|
|
27574
|
+
(value) => value.toUpperCase()
|
|
27575
|
+
).option(
|
|
27576
|
+
"--status <status>",
|
|
27577
|
+
"Filter by status (OPEN, IN_PROGRESS, CONTESTED, REMEDIATED, VERIFIED_FIXED, VERIFIED_OPEN, DISMISSED)",
|
|
27578
|
+
(value) => value.toUpperCase()
|
|
27579
|
+
).option(
|
|
27580
|
+
"-L, --limit <n>",
|
|
27581
|
+
`Max results to return (default: ${DEFAULT_LIMIT}, max: ${MAX_LIMIT})`,
|
|
27582
|
+
(v) => {
|
|
27583
|
+
const n = Number.parseInt(v, 10);
|
|
27584
|
+
if (Number.isNaN(n) || n < 1) {
|
|
27585
|
+
throw new Error("--limit must be a positive integer");
|
|
27586
|
+
}
|
|
27587
|
+
return Math.min(n, MAX_LIMIT);
|
|
27588
|
+
}
|
|
27589
|
+
).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
27544
27590
|
"after",
|
|
27545
27591
|
`
|
|
27546
27592
|
Examples:
|
|
27547
27593
|
tracecli pentest findings list --pentest PT-3
|
|
27594
|
+
tracecli pentest findings list --pentest PT-3 --severity CRITICAL
|
|
27595
|
+
tracecli pentest findings list --pentest PT-3 --status OPEN --limit 20
|
|
27548
27596
|
tracecli pentest findings list --pentest PT-3 --output json
|
|
27549
27597
|
tracecli pentest findings list --pentest PT-3 --output tsv | cut -f1,4`
|
|
27550
|
-
).action(
|
|
27551
|
-
|
|
27552
|
-
|
|
27553
|
-
|
|
27554
|
-
|
|
27555
|
-
|
|
27556
|
-
|
|
27557
|
-
|
|
27558
|
-
if (result.status === 401) {
|
|
27559
|
-
console.error("Authentication failed. Run `tracecli auth login` to re-authenticate.");
|
|
27560
|
-
process.exit(1);
|
|
27561
|
-
}
|
|
27562
|
-
if (result.status === 404) {
|
|
27563
|
-
console.error(
|
|
27564
|
-
`Pentest '${options.pentest}' not found. Verify the ID with \`tracecli pentest list\`.`
|
|
27598
|
+
).action(
|
|
27599
|
+
async (options) => {
|
|
27600
|
+
const organizationId = await resolveOrganizationId();
|
|
27601
|
+
const pentestId = await resolvePentestId(organizationId, options.pentest);
|
|
27602
|
+
const result = await authenticatedRequest(
|
|
27603
|
+
(client) => client.pentestFinding.listFindings({
|
|
27604
|
+
params: { organizationId, pentestId }
|
|
27605
|
+
})
|
|
27565
27606
|
);
|
|
27566
|
-
|
|
27567
|
-
|
|
27568
|
-
|
|
27569
|
-
|
|
27570
|
-
|
|
27571
|
-
|
|
27572
|
-
|
|
27573
|
-
|
|
27574
|
-
|
|
27575
|
-
|
|
27607
|
+
if (result.status === 401) {
|
|
27608
|
+
console.error("Authentication failed. Run `tracecli auth login` to re-authenticate.");
|
|
27609
|
+
process.exit(1);
|
|
27610
|
+
}
|
|
27611
|
+
if (result.status === 404) {
|
|
27612
|
+
console.error(
|
|
27613
|
+
`Pentest '${options.pentest}' not found. Verify the ID with \`tracecli pentest list\`.`
|
|
27614
|
+
);
|
|
27615
|
+
process.exit(1);
|
|
27616
|
+
}
|
|
27617
|
+
if (result.status !== 200) {
|
|
27618
|
+
console.error(`Failed to list findings (status ${result.status}).`);
|
|
27619
|
+
process.exit(1);
|
|
27620
|
+
}
|
|
27621
|
+
let filteredFindings = result.body;
|
|
27622
|
+
if (options.severity) {
|
|
27623
|
+
filteredFindings = filteredFindings.filter((f) => f.severity === options.severity);
|
|
27624
|
+
}
|
|
27625
|
+
if (options.status) {
|
|
27626
|
+
filteredFindings = filteredFindings.filter((f) => f.status === options.status);
|
|
27627
|
+
}
|
|
27628
|
+
filteredFindings.sort(
|
|
27629
|
+
(a, b) => (SEVERITY_ORDER[a.severity] ?? 99) - (SEVERITY_ORDER[b.severity] ?? 99)
|
|
27630
|
+
);
|
|
27631
|
+
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
27632
|
+
const findings = filteredFindings.slice(0, limit);
|
|
27633
|
+
const isJson = options.output === "json";
|
|
27634
|
+
const isTsv = options.output === "tsv";
|
|
27635
|
+
if (findings.length === 0) {
|
|
27636
|
+
if (isJson) {
|
|
27637
|
+
console.log("[]");
|
|
27638
|
+
} else if (isTsv) {
|
|
27639
|
+
console.log("severity status category title cweIds cvssScore");
|
|
27640
|
+
} else {
|
|
27641
|
+
console.log("No findings found for this pentest.");
|
|
27642
|
+
}
|
|
27643
|
+
return;
|
|
27644
|
+
}
|
|
27576
27645
|
if (isJson) {
|
|
27577
|
-
console.log(
|
|
27578
|
-
|
|
27579
|
-
console.log("severity status category title cweIds cvssScore");
|
|
27580
|
-
} else {
|
|
27581
|
-
console.log("No findings found for this pentest.");
|
|
27646
|
+
console.log(JSON.stringify(findings, null, 2));
|
|
27647
|
+
return;
|
|
27582
27648
|
}
|
|
27583
|
-
|
|
27584
|
-
|
|
27585
|
-
|
|
27586
|
-
|
|
27587
|
-
|
|
27588
|
-
|
|
27589
|
-
|
|
27590
|
-
|
|
27591
|
-
|
|
27592
|
-
|
|
27593
|
-
|
|
27594
|
-
|
|
27595
|
-
|
|
27596
|
-
|
|
27597
|
-
finding.status,
|
|
27598
|
-
tsvSafe2(finding.category),
|
|
27599
|
-
tsvSafe2(finding.title),
|
|
27600
|
-
finding.cweIds.join(";"),
|
|
27601
|
-
finding.cvssScore != null ? String(finding.cvssScore) : ""
|
|
27602
|
-
];
|
|
27603
|
-
console.log(cols.join(" "));
|
|
27649
|
+
if (isTsv) {
|
|
27650
|
+
console.log("severity status category title cweIds cvssScore");
|
|
27651
|
+
for (const finding of findings) {
|
|
27652
|
+
const cols = [
|
|
27653
|
+
finding.severity,
|
|
27654
|
+
finding.status,
|
|
27655
|
+
tsvSafe2(finding.category),
|
|
27656
|
+
tsvSafe2(finding.title),
|
|
27657
|
+
finding.cweIds.join(";"),
|
|
27658
|
+
finding.cvssScore != null ? String(finding.cvssScore) : ""
|
|
27659
|
+
];
|
|
27660
|
+
console.log(cols.join(" "));
|
|
27661
|
+
}
|
|
27662
|
+
return;
|
|
27604
27663
|
}
|
|
27605
|
-
|
|
27606
|
-
}
|
|
27607
|
-
console.log(`Found ${findings.length} finding${findings.length === 1 ? "" : "s"}:
|
|
27664
|
+
console.log(`Found ${findings.length} finding${findings.length === 1 ? "" : "s"}:
|
|
27608
27665
|
`);
|
|
27609
|
-
|
|
27610
|
-
|
|
27611
|
-
|
|
27612
|
-
|
|
27613
|
-
|
|
27614
|
-
|
|
27615
|
-
|
|
27616
|
-
|
|
27617
|
-
|
|
27618
|
-
|
|
27619
|
-
|
|
27620
|
-
|
|
27666
|
+
for (const finding of findings) {
|
|
27667
|
+
const sev = formatFindingSeverity(finding.severity);
|
|
27668
|
+
const severityLabel = colorSeverity(finding.severity, sev);
|
|
27669
|
+
const status = formatStatus(finding.status);
|
|
27670
|
+
const cwes = finding.cweIds.length > 0 ? ` | ${finding.cweIds.join(", ")}` : "";
|
|
27671
|
+
const score = finding.cvssScore != null ? ` | CVSS ${finding.cvssScore.toFixed(1)}` : "";
|
|
27672
|
+
console.log(` [${severityLabel}] ${finding.title}`);
|
|
27673
|
+
console.log(` ${finding.category} \xB7 ${status}${cwes}${score}`);
|
|
27674
|
+
if (finding.repositories.length > 0) {
|
|
27675
|
+
for (const repo of finding.repositories) {
|
|
27676
|
+
const location = repo.filePath ? `${repo.repositoryName} \xB7 ${repo.filePath}${repo.startLine != null ? `:${repo.startLine}` : ""}` : repo.repositoryName;
|
|
27677
|
+
console.log(` ${location}`);
|
|
27678
|
+
}
|
|
27621
27679
|
}
|
|
27680
|
+
console.log("");
|
|
27622
27681
|
}
|
|
27623
|
-
console.log("");
|
|
27624
27682
|
}
|
|
27625
|
-
|
|
27683
|
+
);
|
|
27626
27684
|
}
|
|
27627
27685
|
function createFindingsCommand() {
|
|
27628
27686
|
const findings = new Command("findings").description("Manage pentest findings");
|
|
@@ -27917,6 +27975,22 @@ function printRepositoriesTsv(repositories) {
|
|
|
27917
27975
|
);
|
|
27918
27976
|
}
|
|
27919
27977
|
}
|
|
27978
|
+
function printRepositoriesTable(repositories) {
|
|
27979
|
+
const headers = ["Repository URL", "Platform", "Status"];
|
|
27980
|
+
const rows = repositories.map(
|
|
27981
|
+
(repo) => [
|
|
27982
|
+
stripAnsi(String(repo.repositoryUrl)),
|
|
27983
|
+
stripAnsi(String(repo.platform)).toUpperCase(),
|
|
27984
|
+
repo.status === "CONNECTED" ? "connected" : "disconnected"
|
|
27985
|
+
]
|
|
27986
|
+
);
|
|
27987
|
+
const colWidths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => r[i].length)));
|
|
27988
|
+
const pad = (s, w3) => s.padEnd(w3);
|
|
27989
|
+
console.log(headers.map((h, i) => pad(h, colWidths[i] ?? h.length)).join(" "));
|
|
27990
|
+
for (const row of rows) {
|
|
27991
|
+
console.log(row.map((cell, i) => pad(cell, colWidths[i] ?? 0)).join(" "));
|
|
27992
|
+
}
|
|
27993
|
+
}
|
|
27920
27994
|
function collectFilterExpression(value, previous) {
|
|
27921
27995
|
previous.push(value);
|
|
27922
27996
|
return previous;
|
|
@@ -28040,7 +28114,7 @@ function addRepositoryFilterOptions(command) {
|
|
|
28040
28114
|
"Advanced filter expression. Repeatable. Examples: platform=GITHUB, repo:trace, status!=DISCONNECTED",
|
|
28041
28115
|
collectFilterExpression,
|
|
28042
28116
|
[]
|
|
28043
|
-
).option("-o, --output <format>", "Output format: table
|
|
28117
|
+
).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").option(
|
|
28044
28118
|
"-L, --limit <n>",
|
|
28045
28119
|
`Maximum repositories to display (default ${DEFAULT_LIMIT2}, max ${MAX_LIMIT2})`,
|
|
28046
28120
|
parseListLimit,
|
|
@@ -28098,12 +28172,7 @@ async function runRepositoryListCommand(options) {
|
|
|
28098
28172
|
printRepositoriesTsv(displayedRepositories);
|
|
28099
28173
|
return;
|
|
28100
28174
|
}
|
|
28101
|
-
|
|
28102
|
-
const status = repo.status === "CONNECTED" ? "connected" : "disconnected";
|
|
28103
|
-
const url2 = stripAnsi(String(repo.repositoryUrl));
|
|
28104
|
-
const platform = stripAnsi(String(repo.platform)).toLowerCase();
|
|
28105
|
-
console.log(`${url2} (${platform}, ${status})`);
|
|
28106
|
-
}
|
|
28175
|
+
printRepositoriesTable(displayedRepositories);
|
|
28107
28176
|
}
|
|
28108
28177
|
async function runDependencyFilter(organizationId, options) {
|
|
28109
28178
|
const dependency = options.dependency;
|
|
@@ -28164,6 +28233,7 @@ async function runDependencyFilter(organizationId, options) {
|
|
|
28164
28233
|
return;
|
|
28165
28234
|
}
|
|
28166
28235
|
if (options.output === "tsv") {
|
|
28236
|
+
console.log("repository versions");
|
|
28167
28237
|
for (const repo of displayedRepos) {
|
|
28168
28238
|
console.log(`${tsvSafe(repo.fullName)} ${tsvSafe(repo.versions.join(","))}`);
|
|
28169
28239
|
}
|
|
@@ -28517,16 +28587,87 @@ function resolveRegistryUrl() {
|
|
|
28517
28587
|
if (typeof override === "string" && override.trim().length > 0) {
|
|
28518
28588
|
return override;
|
|
28519
28589
|
}
|
|
28520
|
-
return `https://registry.npmjs.org/${encodeURIComponent(CLI_PACKAGE_NAME)}
|
|
28590
|
+
return `https://registry.npmjs.org/${encodeURIComponent(CLI_PACKAGE_NAME)}`;
|
|
28591
|
+
}
|
|
28592
|
+
function isRecord(value) {
|
|
28593
|
+
return typeof value === "object" && value !== null;
|
|
28594
|
+
}
|
|
28595
|
+
function selectNewestVersion(versions) {
|
|
28596
|
+
let newestVersion = null;
|
|
28597
|
+
for (const version2 of versions) {
|
|
28598
|
+
if (newestVersion === null) {
|
|
28599
|
+
newestVersion = version2;
|
|
28600
|
+
continue;
|
|
28601
|
+
}
|
|
28602
|
+
const comparison = compareSemver(version2, newestVersion);
|
|
28603
|
+
if (comparison !== null && comparison > 0) {
|
|
28604
|
+
newestVersion = version2;
|
|
28605
|
+
}
|
|
28606
|
+
}
|
|
28607
|
+
return newestVersion;
|
|
28608
|
+
}
|
|
28609
|
+
function isStableSemver(version2) {
|
|
28610
|
+
const parsed = parseSemver(version2);
|
|
28611
|
+
return parsed !== null && parsed.prerelease.length === 0;
|
|
28612
|
+
}
|
|
28613
|
+
function extractPublishedVersions(payload) {
|
|
28614
|
+
const versionsField = payload["versions"];
|
|
28615
|
+
if (!isRecord(versionsField)) {
|
|
28616
|
+
return [];
|
|
28617
|
+
}
|
|
28618
|
+
const publishedVersions = [];
|
|
28619
|
+
for (const version2 of Object.keys(versionsField)) {
|
|
28620
|
+
if (parseSemver(version2) !== null) {
|
|
28621
|
+
publishedVersions.push(version2);
|
|
28622
|
+
}
|
|
28623
|
+
}
|
|
28624
|
+
return publishedVersions;
|
|
28625
|
+
}
|
|
28626
|
+
function extractDistTagLatestVersion(payload) {
|
|
28627
|
+
const distTags = payload["dist-tags"];
|
|
28628
|
+
if (!isRecord(distTags)) {
|
|
28629
|
+
return null;
|
|
28630
|
+
}
|
|
28631
|
+
if (typeof distTags["latest"] !== "string") {
|
|
28632
|
+
return null;
|
|
28633
|
+
}
|
|
28634
|
+
const candidate = distTags["latest"].trim();
|
|
28635
|
+
if (candidate.length === 0 || parseSemver(candidate) === null) {
|
|
28636
|
+
return null;
|
|
28637
|
+
}
|
|
28638
|
+
return candidate;
|
|
28639
|
+
}
|
|
28640
|
+
function extractLatestEndpointVersion(payload) {
|
|
28641
|
+
if (typeof payload["version"] !== "string") {
|
|
28642
|
+
return null;
|
|
28643
|
+
}
|
|
28644
|
+
const candidate = payload["version"].trim();
|
|
28645
|
+
if (candidate.length === 0 || parseSemver(candidate) === null) {
|
|
28646
|
+
return null;
|
|
28647
|
+
}
|
|
28648
|
+
return candidate;
|
|
28521
28649
|
}
|
|
28522
28650
|
function extractLatestVersionFromRegistryPayload(payload) {
|
|
28523
|
-
if (
|
|
28651
|
+
if (!isRecord(payload)) {
|
|
28524
28652
|
return null;
|
|
28525
28653
|
}
|
|
28526
|
-
|
|
28527
|
-
|
|
28654
|
+
const publishedVersions = extractPublishedVersions(payload);
|
|
28655
|
+
const hasPublishedVersions = publishedVersions.length > 0;
|
|
28656
|
+
const publishedVersionSet = new Set(publishedVersions);
|
|
28657
|
+
const distTagLatestVersion = extractDistTagLatestVersion(payload);
|
|
28658
|
+
if (distTagLatestVersion && (!hasPublishedVersions || publishedVersionSet.has(distTagLatestVersion))) {
|
|
28659
|
+
return distTagLatestVersion;
|
|
28528
28660
|
}
|
|
28529
|
-
|
|
28661
|
+
const latestEndpointVersion = extractLatestEndpointVersion(payload);
|
|
28662
|
+
if (latestEndpointVersion && (!hasPublishedVersions || publishedVersionSet.has(latestEndpointVersion))) {
|
|
28663
|
+
return latestEndpointVersion;
|
|
28664
|
+
}
|
|
28665
|
+
const stablePublishedVersions = publishedVersions.filter((version2) => isStableSemver(version2));
|
|
28666
|
+
const newestStableVersion = selectNewestVersion(stablePublishedVersions);
|
|
28667
|
+
if (newestStableVersion) {
|
|
28668
|
+
return newestStableVersion;
|
|
28669
|
+
}
|
|
28670
|
+
return selectNewestVersion(publishedVersions);
|
|
28530
28671
|
}
|
|
28531
28672
|
async function fetchLatestVersionFromRegistry() {
|
|
28532
28673
|
try {
|
|
@@ -28593,15 +28734,21 @@ async function maybeNotifyUpdateAvailable(commandName) {
|
|
|
28593
28734
|
return;
|
|
28594
28735
|
}
|
|
28595
28736
|
noticePrinted = true;
|
|
28596
|
-
|
|
28597
|
-
|
|
28598
|
-
`
|
|
28599
|
-
|
|
28600
|
-
|
|
28601
|
-
|
|
28602
|
-
}
|
|
28603
|
-
|
|
28604
|
-
const
|
|
28737
|
+
const lines = [
|
|
28738
|
+
`A new tracecli version is available: ${availability.currentVersion} -> ${availability.latestVersion}`,
|
|
28739
|
+
"Run `tracecli upgrade` to install the latest version."
|
|
28740
|
+
];
|
|
28741
|
+
const maxLen = Math.max(...lines.map((l) => l.length));
|
|
28742
|
+
const pad = (s) => s + " ".repeat(maxLen - s.length);
|
|
28743
|
+
const top = `\u256D${"\u2500".repeat(maxLen + 2)}\u256E`;
|
|
28744
|
+
const bottom = `\u2570${"\u2500".repeat(maxLen + 2)}\u256F`;
|
|
28745
|
+
const boxed = [top, ...lines.map((l) => `\u2502 ${pad(l)} \u2502`), bottom].join("\n");
|
|
28746
|
+
console.log("");
|
|
28747
|
+
console.log(colorMuted(boxed));
|
|
28748
|
+
console.log("");
|
|
28749
|
+
}
|
|
28750
|
+
function resolveUpgradePlan(targetVersion) {
|
|
28751
|
+
const packageSpec = targetVersion ? `${CLI_PACKAGE_NAME}@${targetVersion}` : `${CLI_PACKAGE_NAME}@latest`;
|
|
28605
28752
|
if (Bun.which("npm")) {
|
|
28606
28753
|
return { command: "npm", args: ["install", "-g", packageSpec] };
|
|
28607
28754
|
}
|
|
@@ -28665,7 +28812,7 @@ Examples:
|
|
|
28665
28812
|
console.log("Upgrade cancelled.");
|
|
28666
28813
|
return;
|
|
28667
28814
|
}
|
|
28668
|
-
const plan = resolveUpgradePlan();
|
|
28815
|
+
const plan = resolveUpgradePlan(availability.latestVersion);
|
|
28669
28816
|
if (!plan) {
|
|
28670
28817
|
console.error(
|
|
28671
28818
|
`No supported package manager found (npm, bun, pnpm). Install the latest version manually from https://www.npmjs.com/package/${CLI_PACKAGE_NAME}`
|
|
@@ -28899,7 +29046,7 @@ function createVulnerabilitiesCommand() {
|
|
|
28899
29046
|
// src/index.ts
|
|
28900
29047
|
var program2 = new Command();
|
|
28901
29048
|
program2.name("tracecli").description("Trace CLI").version(CLI_VERSION);
|
|
28902
|
-
program2.hook("
|
|
29049
|
+
program2.hook("postAction", async (_thisCommand, actionCommand) => {
|
|
28903
29050
|
await maybeNotifyUpdateAvailable(actionCommand.name());
|
|
28904
29051
|
});
|
|
28905
29052
|
program2.action(() => {
|