securewithtrace 0.52.0 → 0.54.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/dist/index.js CHANGED
@@ -3427,10 +3427,11 @@ var Permission = {
3427
3427
  VIEW_RESULTS: "VIEW_RESULTS",
3428
3428
  EXPORT_ORG_DATA: "EXPORT_ORG_DATA",
3429
3429
  DELETE_ORG_DATA: "DELETE_ORG_DATA",
3430
- MANAGE_AI_INTEGRATION: "MANAGE_AI_INTEGRATION",
3430
+ /** Connecting and configuring third-party integrations. */
3431
+ MANAGE_INTEGRATIONS: "MANAGE_INTEGRATIONS",
3431
3432
  MANAGE_INTEGRATED_REPOSITORIES: "MANAGE_INTEGRATED_REPOSITORIES",
3432
3433
  MANAGE_USERS: "MANAGE_USERS",
3433
- /** Invite or remove org members (admin + analyst). Distinct from MANAGE_USERS (admin-only API keys / role changes). */
3434
+ /** Invite or remove org members. Distinct from MANAGE_USERS (role changes, API keys). */
3434
3435
  INVITE_USERS: "INVITE_USERS",
3435
3436
  MANAGE_ORGANIZATION: "MANAGE_ORGANIZATION",
3436
3437
  MANAGE_PENTESTS: "MANAGE_PENTESTS",
@@ -3440,16 +3441,15 @@ var Permission = {
3440
3441
  // ../../packages/core/src/auth/permissions.ts
3441
3442
  var ROLE_PERMISSIONS = {
3442
3443
  [Role.developer]: /* @__PURE__ */ new Set([Permission.RUN_SCAN, Permission.VIEW_RESULTS]),
3444
+ // Shown as Manager: sets up and runs testing. Billing, people and API keys stay admin-only.
3443
3445
  [Role.analyst]: /* @__PURE__ */ new Set([
3444
3446
  Permission.RUN_SCAN,
3445
3447
  Permission.VIEW_RESULTS,
3446
3448
  Permission.EXPORT_ORG_DATA,
3447
3449
  Permission.MANAGE_INTEGRATED_REPOSITORIES,
3448
- Permission.MANAGE_AI_INTEGRATION,
3449
- Permission.INVITE_USERS
3450
- // MANAGE_PENTESTS removed — pentest writes now `requireStaff`
3451
- // (PR-0b-i M3 / D14). Constant stays in the enum for backward compat
3452
- // until v2 cleanup; analysts no longer get it.
3450
+ Permission.MANAGE_INTEGRATIONS,
3451
+ Permission.MANAGE_APPLICATIONS,
3452
+ Permission.MANAGE_PENTESTS
3453
3453
  ]),
3454
3454
  [Role.admin]: new Set(Object.values(Permission))
3455
3455
  };
@@ -6283,7 +6283,7 @@ var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => {
6283
6283
  function isValidBase64URL(data) {
6284
6284
  if (!base64url.test(data))
6285
6285
  return false;
6286
- const base644 = data.replace(/[-_]/g, (c84) => c84 === "-" ? "+" : "/");
6286
+ const base644 = data.replace(/[-_]/g, (c86) => c86 === "-" ? "+" : "/");
6287
6287
  const padded = base644.padEnd(Math.ceil(base644.length / 4) * 4, "=");
6288
6288
  return isValidBase64(padded);
6289
6289
  }
@@ -16327,9 +16327,9 @@ var ZodDate = /* @__PURE__ */ $constructor("ZodDate", (inst, def) => {
16327
16327
  inst._zod.processJSONSchema = (ctx, json2, params3) => dateProcessor(inst, ctx, json2, params3);
16328
16328
  inst.min = (value, params3) => inst.check(_gte(value, params3));
16329
16329
  inst.max = (value, params3) => inst.check(_lte(value, params3));
16330
- const c84 = inst._zod.bag;
16331
- inst.minDate = c84.minimum ? new Date(c84.minimum) : null;
16332
- inst.maxDate = c84.maximum ? new Date(c84.maximum) : null;
16330
+ const c86 = inst._zod.bag;
16331
+ inst.minDate = c86.minimum ? new Date(c86.minimum) : null;
16332
+ inst.maxDate = c86.maximum ? new Date(c86.maximum) : null;
16333
16333
  });
16334
16334
  function date3(params3) {
16335
16335
  return _date(ZodDate, params3);
@@ -17460,6 +17460,7 @@ config(en_default());
17460
17460
 
17461
17461
  // ../../packages/core/src/text/prompt-sanitize.ts
17462
17462
  var CREDENTIAL_KEY_SOURCE = "password|secret|token|access[_ -]?token|refresh[_ -]?token|cookie|authorization|bearer|api[_ -]?key|private[_ -]?key|session|credential|(?<![A-Za-z])(?:passwd|pwd|pass)";
17463
+ var PROVIDER_KEY_SOURCE = String.raw`\bsk-[A-Za-z0-9_-]{16,}\b`;
17463
17464
  var HIGH_ENTROPY_RUN_SOURCE = String.raw`\b(sk-[A-Za-z0-9_-]{16,}|[A-Za-z0-9+/_=-]{40,})\b`;
17464
17465
 
17465
17466
  // ../../packages/core/src/text/evidence-redact.ts
@@ -17711,7 +17712,14 @@ var ENVIRONMENT_AWARE_PROMPT_VERSIONS = /* @__PURE__ */ new Set([
17711
17712
  "operator-openai-v26",
17712
17713
  "operator-openai-v27",
17713
17714
  "operator-openai-v28",
17714
- "operator-openai-v29"
17715
+ "operator-openai-v29",
17716
+ // The Claude operator pins every provider launches.
17717
+ "operator-v30",
17718
+ "operator-v31",
17719
+ "operator-v32",
17720
+ "operator-v33",
17721
+ "operator-v34",
17722
+ "operator-v35"
17715
17723
  ]);
17716
17724
  var OOB_PROFILE_SUCCESSIONS = [
17717
17725
  {
@@ -18298,6 +18306,26 @@ var STAGE_RETIRED_OOB_PROFILE_SUCCESSIONS = [
18298
18306
  }
18299
18307
  }
18300
18308
  ];
18309
+ var ENVIRONMENT_AWARE_OPERATOR_OOB_PROFILE_SUCCESSIONS = [
18310
+ {
18311
+ successor: { promptVersion: "operator-v30", toolsetVersion: "operator-tools-v14" },
18312
+ predecessor: { promptVersion: "operator-v31", toolsetVersion: "operator-tools-v15" }
18313
+ },
18314
+ {
18315
+ successor: { promptVersion: "operator-v32", toolsetVersion: "operator-tools-v16" },
18316
+ predecessor: { promptVersion: "operator-v31", toolsetVersion: "operator-tools-v15" }
18317
+ }
18318
+ ];
18319
+ var ACCOUNT_OPERATOR_OOB_PROFILE_SUCCESSIONS = [
18320
+ {
18321
+ successor: { promptVersion: "operator-v33", toolsetVersion: "operator-tools-v17" },
18322
+ predecessor: { promptVersion: "operator-v34", toolsetVersion: "operator-tools-v18" }
18323
+ },
18324
+ {
18325
+ successor: { promptVersion: "operator-v35", toolsetVersion: "operator-tools-v19" },
18326
+ predecessor: { promptVersion: "operator-v34", toolsetVersion: "operator-tools-v18" }
18327
+ }
18328
+ ];
18301
18329
  var ALL_OOB_PROFILE_SUCCESSIONS = [
18302
18330
  ...OOB_PROFILE_SUCCESSIONS,
18303
18331
  ...STAFF_NOTIFICATION_OOB_PROFILE_SUCCESSIONS,
@@ -18315,7 +18343,9 @@ var ALL_OOB_PROFILE_SUCCESSIONS = [
18315
18343
  ...VALIDATION_V40_OOB_PROFILE_SUCCESSIONS,
18316
18344
  ...WRITER_REPRO_OOB_PROFILE_SUCCESSIONS,
18317
18345
  ...RETEST_REPRO_OOB_PROFILE_SUCCESSIONS,
18318
- ...STAGE_RETIRED_OOB_PROFILE_SUCCESSIONS
18346
+ ...STAGE_RETIRED_OOB_PROFILE_SUCCESSIONS,
18347
+ ...ENVIRONMENT_AWARE_OPERATOR_OOB_PROFILE_SUCCESSIONS,
18348
+ ...ACCOUNT_OPERATOR_OOB_PROFILE_SUCCESSIONS
18319
18349
  ];
18320
18350
  var OOB_CAPABLE_TOOLSETS = new Set(
18321
18351
  ALL_OOB_PROFILE_SUCCESSIONS.map(({ successor }) => successor.toolsetVersion)
@@ -18340,9 +18370,10 @@ var STAFF_NOTIFICATION_TOOLSET_VERSIONS = /* @__PURE__ */ new Set([
18340
18370
  "report-tools-bsk-v3",
18341
18371
  "report-tools-v4",
18342
18372
  "report-tools-bsk-v4",
18343
- // API_COVERAGE_TOOLSET_VERSION and its predecessor, written out because they are declared below.
18373
+ // API_COVERAGE_TOOLSET_VERSION and its predecessors, written out because they are declared below.
18344
18374
  "api-coverage-tools-v1",
18345
18375
  "api-coverage-tools-v2",
18376
+ "api-coverage-tools-v3",
18346
18377
  // SETUP_TOOLSET_VERSION, written out for the same reason.
18347
18378
  "setup-tools-v1",
18348
18379
  ...STAFF_NOTIFICATION_OOB_PROFILE_SUCCESSIONS.flatMap(({ successor, predecessor }) => [
@@ -18357,6 +18388,10 @@ var STAFF_NOTIFICATION_TOOLSET_VERSIONS = /* @__PURE__ */ new Set([
18357
18388
  predecessor.toolsetVersion,
18358
18389
  successor.toolsetVersion
18359
18390
  ]),
18391
+ ...ACCOUNT_OPERATOR_OOB_PROFILE_SUCCESSIONS.flatMap(({ successor, predecessor }) => [
18392
+ predecessor.toolsetVersion,
18393
+ successor.toolsetVersion
18394
+ ]),
18360
18395
  ...FEATURE_COVERAGE_OOB_PROFILE_SUCCESSIONS.flatMap(({ successor, predecessor }) => [
18361
18396
  predecessor.toolsetVersion,
18362
18397
  successor.toolsetVersion
@@ -23308,8 +23343,8 @@ var CreateAgentSessionRequestSchema = external_exports.discriminatedUnion("type"
23308
23343
  codeUploadId: AndroidBuildUnderTestSchema,
23309
23344
  /**
23310
23345
  * REVIEW launches the review session: an operator session that premise-checks every
23311
- * unpublished finding before its first turn and does not publish. Claude providers only
23312
- * (`REVIEW_PROVIDER_UNSUPPORTED`).
23346
+ * unpublished finding before its first turn and does not publish. Its premise checks run on
23347
+ * the session's provider.
23313
23348
  */
23314
23349
  purpose: OperatorSessionPurpose.optional()
23315
23350
  }),
@@ -23610,6 +23645,20 @@ var OperatorPentestContextSchema = external_exports.object({
23610
23645
  reason: external_exports.string().nullable()
23611
23646
  })
23612
23647
  ),
23648
+ /**
23649
+ * Features excluded from this engagement, read at call time: an exclusion staff add after launch
23650
+ * reaches a running session here, never through its brief. `handle` is `<ordinal>/<slug>`, as
23651
+ * the brief's do-not-test list names it. Optional for the same host raw-cast reason as
23652
+ * `applications`.
23653
+ */
23654
+ excludedFeatures: external_exports.array(
23655
+ external_exports.object({
23656
+ handle: external_exports.string(),
23657
+ name: external_exports.string(),
23658
+ reason: external_exports.string(),
23659
+ endpoints: external_exports.array(external_exports.string())
23660
+ })
23661
+ ).optional(),
23613
23662
  // From the session's immutable repository pins (what the agent has checked out).
23614
23663
  repositories: external_exports.array(
23615
23664
  external_exports.object({
@@ -25889,7 +25938,7 @@ var CreateLinearTicketsRequestSchema = external_exports.object({
25889
25938
  findingIds: external_exports.array(external_exports.string().min(1).max(64)).min(1).max(50),
25890
25939
  /** Single-finding requests only — a title with >1 finding is a 400. */
25891
25940
  title: external_exports.string().min(1).max(255).optional(),
25892
- /** Destination overrides — ADMIN ONLY (MANAGE_ORGANIZATION); a non-admin sending any is a 403. */
25941
+ /** Destination overrides need MANAGE_INTEGRATIONS; anyone else sending one gets a 403. */
25893
25942
  teamId: linearEntityId.optional(),
25894
25943
  projectId: linearEntityId.nullable().optional(),
25895
25944
  labelIds: external_exports.array(linearEntityId).max(10).optional()
@@ -25947,9 +25996,9 @@ var LinearTicketContextResponseSchema = external_exports.object({
25947
25996
  labelIds: external_exports.array(external_exports.string()),
25948
25997
  labelNames: external_exports.array(external_exports.string())
25949
25998
  }).nullable(),
25950
- /** True only for MANAGE_ORGANIZATION callers — gates the destination picker. */
25999
+ /** True only for MANAGE_INTEGRATIONS callers; gates the destination picker. */
25951
26000
  canOverrideDestination: external_exports.boolean(),
25952
- /** Populated only for admins (a non-admin gets the resolved defaults, not a workspace inventory). */
26001
+ /** Populated only when canOverrideDestination; anyone else gets the resolved defaults, not a workspace inventory. */
25953
26002
  teams: external_exports.array(TicketContextTeam),
25954
26003
  projects: external_exports.array(TicketContextProject),
25955
26004
  labels: external_exports.array(TicketContextLabel)
@@ -28898,13 +28947,13 @@ var StorageStateSchema = external_exports.object({
28898
28947
  } catch {
28899
28948
  return;
28900
28949
  }
28901
- s.cookies.forEach((c84, i2) => {
28902
- const d = c84.domain.replace(/^\./, "").toLowerCase();
28950
+ s.cookies.forEach((c86, i2) => {
28951
+ const d = c86.domain.replace(/^\./, "").toLowerCase();
28903
28952
  if (d !== host && !host.endsWith(`.${d}`)) {
28904
28953
  ctx.addIssue({
28905
28954
  code: "custom",
28906
28955
  path: ["cookies", i2, "domain"],
28907
- message: `cookie domain "${c84.domain}" is not the capture origin host "${host}" or a parent domain of it`
28956
+ message: `cookie domain "${c86.domain}" is not the capture origin host "${host}" or a parent domain of it`
28908
28957
  });
28909
28958
  }
28910
28959
  });
@@ -29510,7 +29559,7 @@ var AgentSessionGitSourceGrantSchema = external_exports.object({
29510
29559
  ref: external_exports.string().min(1).max(255),
29511
29560
  /** Immutable pin — the host checks out exactly this commit. */
29512
29561
  commitSha: external_exports.string().regex(/^[a-f0-9]{40}$/i),
29513
- /** Bare clone URL (no credentials — the host injects via URL userinfo). */
29562
+ /** Bare clone URL (no credentials — the host supplies the token via GIT_ASKPASS). */
29514
29563
  cloneUrl: external_exports.url(),
29515
29564
  /**
29516
29565
  * Short-lived scoped read token. Never logged, never placed in any environ;
@@ -29519,9 +29568,9 @@ var AgentSessionGitSourceGrantSchema = external_exports.object({
29519
29568
  */
29520
29569
  cloneToken: external_exports.string().min(1),
29521
29570
  /**
29522
- * Git credential username for the clone. GitHub (`x-access-token`) rides URL
29523
- * userinfo; Bitbucket (`x-token-auth`) and GitLab (`oauth2`) ride GIT_ASKPASS
29524
- * (never the URL). The default keeps a pre-Bitbucket host safe — but the host
29571
+ * Git credential username for the clone: `x-access-token` (GitHub),
29572
+ * `x-token-auth` (Bitbucket) or `oauth2` (GitLab). The token always rides
29573
+ * GIT_ASKPASS, never the URL. The default keeps a pre-Bitbucket host safe — but the host
29525
29574
  * raw-casts this response, so the load-bearing fallback is the host's
29526
29575
  * use-site default.
29527
29576
  */
@@ -30469,7 +30518,12 @@ var SessionCredentialsResponseSchema = external_exports.object({
30469
30518
  browserAllowedBaseUrls: external_exports.array(external_exports.string()),
30470
30519
  browserExclusions: external_exports.array(external_exports.string()),
30471
30520
  /** API_COVERAGE only; null otherwise. Range checks stay with the host's rate parser. */
30472
- requestRate: external_exports.object({ perSec: external_exports.number(), burst: external_exports.number() }).nullable()
30521
+ requestRate: external_exports.object({ perSec: external_exports.number(), burst: external_exports.number() }).nullable(),
30522
+ /**
30523
+ * Labels of credentials the resolver could not include this time (a failed decrypt). A host
30524
+ * refreshing mid-run keeps its previous entries for these instead of reading them as deleted.
30525
+ */
30526
+ skippedLabels: external_exports.array(external_exports.string()).default([])
30473
30527
  });
30474
30528
  var ConvexReconRequestSchema = external_exports.object({
30475
30529
  runVersion: external_exports.number().int().nonnegative()
@@ -41057,7 +41111,12 @@ var CoverageGridResponseSchema = external_exports.object({
41057
41111
  orphanFeatures: external_exports.array(CoverageOrphanFeatureSchema).default([]),
41058
41112
  unplaced: external_exports.array(CoverageUnplacedRowSchema).default([]),
41059
41113
  /** When the engagement started: a feature retired before it is not part of this engagement. */
41060
- pentestStartedAt: external_exports.coerce.date().nullable().default(null)
41114
+ pentestStartedAt: external_exports.coerce.date().nullable().default(null),
41115
+ /**
41116
+ * When a closed engagement ended; null while it is open. A feature first recorded after it
41117
+ * was never part of this engagement.
41118
+ */
41119
+ pentestClosedAt: external_exports.coerce.date().nullable().default(null)
41061
41120
  });
41062
41121
 
41063
41122
  // ../../packages/api-contracts/src/contracts/v1/pentest-coverage.ts
@@ -43657,6 +43716,26 @@ var SetStaffOrganizationPentestCustomerVisibilityRequestSchema = external_export
43657
43716
  var RenameStaffOrganizationPentestRequestSchema = external_exports.object({
43658
43717
  title: external_exports.string().trim().min(1, "Title is required").max(500, "Title must be 500 characters or fewer")
43659
43718
  }).strict();
43719
+ var SetStaffOrganizationPentestStatusRequestSchema = external_exports.object({
43720
+ status: PentestStatus,
43721
+ reason: external_exports.string().trim().min(1, "Reason cannot be blank").max(2e3, "Reason must be 2000 characters or fewer").optional()
43722
+ }).strict();
43723
+ var CreateStaffPocDraftRequestSchema = external_exports.object({
43724
+ homepageUrl: external_exports.url({ protocol: /^https?$/ }).max(2048).optional()
43725
+ }).strict();
43726
+ var LaunchStaffPocSetupRequestSchema = external_exports.object({
43727
+ notes: external_exports.string().trim().min(1).max(MAX_SETUP_NOTES_CHARS).optional()
43728
+ }).strict();
43729
+ var LaunchStaffPocSetupResponseSchema = external_exports.object({
43730
+ agentSessionId: external_exports.uuid(),
43731
+ /** Null when Slack is not configured in this environment. */
43732
+ slack: external_exports.object({
43733
+ channelId: external_exports.string(),
43734
+ /** Null when Slack did not return the channel's name. */
43735
+ channelName: external_exports.string().nullable(),
43736
+ url: external_exports.url()
43737
+ }).strict().nullable()
43738
+ }).strict();
43660
43739
 
43661
43740
  // ../../packages/api-contracts/src/contracts/v1/staff-pentests.ts
43662
43741
  var c58 = initContract();
@@ -43717,6 +43796,161 @@ var staffPentestsContract = c58.router({
43717
43796
  500: ErrorResponseSchema
43718
43797
  },
43719
43798
  summary: "Hide a pentest from the customer or show it again (Trace staff only)"
43799
+ },
43800
+ setStaffOrganizationPentestStatus: {
43801
+ method: "POST",
43802
+ path: "/organizations/:organizationId/staff/pentests/:pentestId/status",
43803
+ pathParams: StaffOrganizationPentestParamsSchema,
43804
+ body: SetStaffOrganizationPentestStatusRequestSchema,
43805
+ responses: {
43806
+ 200: StaffOrganizationPentestSummarySchema,
43807
+ 400: ErrorResponseSchema,
43808
+ 401: ErrorResponseSchema,
43809
+ 403: ErrorResponseSchema,
43810
+ 404: ErrorResponseSchema,
43811
+ // A lifecycle rule refused the move; the rules and their codes live in
43812
+ // `PentestService.update`.
43813
+ 409: ErrorResponseSchema,
43814
+ 500: ErrorResponseSchema
43815
+ },
43816
+ summary: "Set a pentest\u2019s lifecycle status from the admin console (Trace staff only)"
43817
+ },
43818
+ createStaffPocDraft: {
43819
+ method: "POST",
43820
+ path: "/organizations/:organizationId/staff/pentests/poc",
43821
+ pathParams: OrgIdParamsSchema,
43822
+ body: CreateStaffPocDraftRequestSchema,
43823
+ // Error codes: StaffPocErrorCodes (staff-pentests.api.ts).
43824
+ responses: {
43825
+ 201: StaffOrganizationPentestSummarySchema,
43826
+ 400: ErrorResponseSchema,
43827
+ 401: ErrorResponseSchema,
43828
+ 403: ErrorResponseSchema,
43829
+ 404: ErrorResponseSchema,
43830
+ 409: ErrorResponseSchema,
43831
+ 500: ErrorResponseSchema
43832
+ },
43833
+ summary: "Create a hidden PoC draft engagement (Trace staff only)"
43834
+ },
43835
+ launchStaffPocSetup: {
43836
+ method: "POST",
43837
+ path: "/organizations/:organizationId/staff/pentests/:pentestId/setup-session",
43838
+ pathParams: StaffOrganizationPentestParamsSchema,
43839
+ body: LaunchStaffPocSetupRequestSchema,
43840
+ // Error codes: StaffPocErrorCodes (staff-pentests.api.ts), plus the SETUP launch refusals
43841
+ // (SETUP_REQUIRES_SCOPING, SETUP_AFTER_TESTING_STARTED) and a 429 at the session cap.
43842
+ responses: {
43843
+ 201: LaunchStaffPocSetupResponseSchema,
43844
+ 400: ErrorResponseSchema,
43845
+ 401: ErrorResponseSchema,
43846
+ 403: ErrorResponseSchema,
43847
+ 404: ErrorResponseSchema,
43848
+ 409: ErrorResponseSchema,
43849
+ 429: ErrorResponseSchema,
43850
+ 500: ErrorResponseSchema,
43851
+ 503: ErrorResponseSchema
43852
+ },
43853
+ summary: "Bind a PoC engagement's Slack and launch its SETUP session (Trace staff only)"
43854
+ }
43855
+ });
43856
+
43857
+ // ../../packages/api-contracts/src/schemas/api/v1/staff-products.api.ts
43858
+ var StaffProductParamsSchema = OrgIdParamsSchema.extend({
43859
+ productGroupId: external_exports.uuid()
43860
+ });
43861
+ var StaffProductApplicationParamsSchema = OrgIdParamsSchema.extend({
43862
+ applicationId: external_exports.uuid()
43863
+ });
43864
+ var PRODUCT_NAME_MAX_CHARS = 200;
43865
+ var ProductNameSchema = external_exports.string().trim().min(1).max(PRODUCT_NAME_MAX_CHARS);
43866
+ var StaffProductApplicationSchema = external_exports.object({
43867
+ applicationId: external_exports.uuid(),
43868
+ name: external_exports.string(),
43869
+ type: external_exports.enum(ApplicationTypeValues),
43870
+ /** Tells same-named applications apart; null for types without a URL. */
43871
+ applicationUrl: external_exports.string().nullable(),
43872
+ /** Applications this one uses, sorted by their name. */
43873
+ uses: external_exports.array(external_exports.uuid())
43874
+ }).strict();
43875
+ var StaffProductSchema = external_exports.object({
43876
+ productGroupId: external_exports.uuid(),
43877
+ name: external_exports.string(),
43878
+ applications: external_exports.array(StaffProductApplicationSchema)
43879
+ }).strict();
43880
+ var StaffProductsResponseSchema = external_exports.object({
43881
+ products: external_exports.array(StaffProductSchema)
43882
+ }).strict();
43883
+ var RenameStaffProductRequestSchema = external_exports.object({ name: ProductNameSchema }).strict();
43884
+ var MoveStaffApplicationRequestSchema = external_exports.union([
43885
+ external_exports.object({ productGroupId: external_exports.uuid() }).strict(),
43886
+ external_exports.object({ newProductName: ProductNameSchema }).strict()
43887
+ ]);
43888
+ var SetStaffApplicationDependenciesRequestSchema = external_exports.object({
43889
+ toApplicationIds: external_exports.array(external_exports.uuid()).max(100).refine((ids) => new Set(ids).size === ids.length, {
43890
+ message: "Application ids must be unique"
43891
+ })
43892
+ }).strict();
43893
+
43894
+ // ../../packages/api-contracts/src/contracts/v1/staff-products.ts
43895
+ var c59 = initContract();
43896
+ var staffProductsContract = c59.router({
43897
+ listStaffProducts: {
43898
+ method: "GET",
43899
+ path: "/organizations/:organizationId/staff/products",
43900
+ pathParams: OrgIdParamsSchema,
43901
+ responses: {
43902
+ 200: StaffProductsResponseSchema,
43903
+ 401: ErrorResponseSchema,
43904
+ 403: ErrorResponseSchema,
43905
+ 404: ErrorResponseSchema,
43906
+ 500: ErrorResponseSchema
43907
+ },
43908
+ summary: "List an organization\u2019s products and their applications (Trace staff only)"
43909
+ },
43910
+ renameStaffProduct: {
43911
+ method: "PATCH",
43912
+ path: "/organizations/:organizationId/staff/products/:productGroupId",
43913
+ pathParams: StaffProductParamsSchema,
43914
+ body: RenameStaffProductRequestSchema,
43915
+ responses: {
43916
+ 200: StaffProductsResponseSchema,
43917
+ 400: ErrorResponseSchema,
43918
+ 401: ErrorResponseSchema,
43919
+ 403: ErrorResponseSchema,
43920
+ 404: ErrorResponseSchema,
43921
+ 500: ErrorResponseSchema
43922
+ },
43923
+ summary: "Rename a product (Trace staff only)"
43924
+ },
43925
+ moveStaffApplication: {
43926
+ method: "PUT",
43927
+ path: "/organizations/:organizationId/staff/applications/:applicationId/product",
43928
+ pathParams: StaffProductApplicationParamsSchema,
43929
+ body: MoveStaffApplicationRequestSchema,
43930
+ responses: {
43931
+ 200: StaffProductsResponseSchema,
43932
+ 400: ErrorResponseSchema,
43933
+ 401: ErrorResponseSchema,
43934
+ 403: ErrorResponseSchema,
43935
+ 404: ErrorResponseSchema,
43936
+ 500: ErrorResponseSchema
43937
+ },
43938
+ summary: "Move an application into another or a new product (Trace staff only)"
43939
+ },
43940
+ setStaffApplicationDependencies: {
43941
+ method: "PUT",
43942
+ path: "/organizations/:organizationId/staff/applications/:applicationId/dependencies",
43943
+ pathParams: StaffProductApplicationParamsSchema,
43944
+ body: SetStaffApplicationDependenciesRequestSchema,
43945
+ responses: {
43946
+ 200: StaffProductsResponseSchema,
43947
+ 400: ErrorResponseSchema,
43948
+ 401: ErrorResponseSchema,
43949
+ 403: ErrorResponseSchema,
43950
+ 404: ErrorResponseSchema,
43951
+ 500: ErrorResponseSchema
43952
+ },
43953
+ summary: "Replace the applications an application uses (Trace staff only)"
43720
43954
  }
43721
43955
  });
43722
43956
 
@@ -43827,8 +44061,8 @@ var StaffQueueResponseSchema = external_exports.object({
43827
44061
  }).strict();
43828
44062
 
43829
44063
  // ../../packages/api-contracts/src/contracts/v1/staff-queue.ts
43830
- var c59 = initContract();
43831
- var staffQueueContract = c59.router({
44064
+ var c60 = initContract();
44065
+ var staffQueueContract = c60.router({
43832
44066
  getStaffQueue: {
43833
44067
  method: "GET",
43834
44068
  path: "/staff/queue",
@@ -43892,8 +44126,8 @@ var UpdateTestIntegrationRequestSchema = external_exports.object({
43892
44126
  }).strict();
43893
44127
 
43894
44128
  // ../../packages/api-contracts/src/contracts/v1/test-integration.ts
43895
- var c60 = initContract();
43896
- var testIntegrationContract = c60.router({
44129
+ var c61 = initContract();
44130
+ var testIntegrationContract = c61.router({
43897
44131
  // -- Fixture CRUD (org-less, staff-only) ----------------------------------
43898
44132
  listTestIntegrations: {
43899
44133
  method: "GET",
@@ -43973,7 +44207,7 @@ var testIntegrationContract = c60.router({
43973
44207
  method: "POST",
43974
44208
  path: "/staff/test-integrations/:testIntegrationId/mfa/code",
43975
44209
  pathParams: TestIntegrationIdParamsSchema,
43976
- body: c60.noBody(),
44210
+ body: c61.noBody(),
43977
44211
  responses: {
43978
44212
  200: CredentialMfaCodeResponseSchema,
43979
44213
  401: ErrorResponseSchema,
@@ -44084,8 +44318,8 @@ var MyContextResponseSchema = external_exports.object({
44084
44318
  });
44085
44319
 
44086
44320
  // ../../packages/api-contracts/src/contracts/v1/user.ts
44087
- var c61 = initContract();
44088
- var userContract = c61.router({
44321
+ var c62 = initContract();
44322
+ var userContract = c62.router({
44089
44323
  getStaffProfile: {
44090
44324
  method: "GET",
44091
44325
  path: "/staff/profile",
@@ -44200,8 +44434,8 @@ var VantaIntegrationResponseSchema = external_exports.object({
44200
44434
  });
44201
44435
 
44202
44436
  // ../../packages/api-contracts/src/contracts/v1/vanta-integration.ts
44203
- var c62 = initContract();
44204
- var vantaIntegrationContract = c62.router({
44437
+ var c63 = initContract();
44438
+ var vantaIntegrationContract = c63.router({
44205
44439
  createVantaIntegration: {
44206
44440
  method: "POST",
44207
44441
  path: "/organizations/:organizationId/vanta-integration",
@@ -44562,8 +44796,8 @@ var VerifySharedVulnerabilityEmailCodeResponseSchema = external_exports.object({
44562
44796
  });
44563
44797
 
44564
44798
  // ../../packages/api-contracts/src/contracts/v1/vulnerability.ts
44565
- var c63 = initContract();
44566
- var vulnerabilityContract = c63.router({
44799
+ var c64 = initContract();
44800
+ var vulnerabilityContract = c64.router({
44567
44801
  filterVulnerabilities: {
44568
44802
  method: "POST",
44569
44803
  path: "/organizations/:organizationId/vulnerabilities/filter",
@@ -44788,8 +45022,8 @@ var UpdateVulnerabilityNoteRequestSchema = external_exports.object({
44788
45022
  });
44789
45023
 
44790
45024
  // ../../packages/api-contracts/src/contracts/v1/vulnerability-note.ts
44791
- var c64 = initContract();
44792
- var vulnerabilityNoteContract = c64.router({
45025
+ var c65 = initContract();
45026
+ var vulnerabilityNoteContract = c65.router({
44793
45027
  listNotes: {
44794
45028
  method: "GET",
44795
45029
  path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/notes",
@@ -44970,8 +45204,8 @@ var ListWebhookDeliveriesResponseSchema = external_exports.object({
44970
45204
  });
44971
45205
 
44972
45206
  // ../../packages/api-contracts/src/contracts/v1/webhook-settings.ts
44973
- var c65 = initContract();
44974
- var webhookSettingsContract = c65.router({
45207
+ var c66 = initContract();
45208
+ var webhookSettingsContract = c66.router({
44975
45209
  listWebhookEndpoints: {
44976
45210
  method: "GET",
44977
45211
  path: "/organizations/:organizationId/webhook-settings/endpoints",
@@ -45108,9 +45342,31 @@ var webhookSettingsContract = c65.router({
45108
45342
  }
45109
45343
  });
45110
45344
 
45345
+ // ../../packages/api-contracts/src/contracts/v1/ws.ts
45346
+ var c67 = initContract();
45347
+ var WsTicketResponseSchema = external_exports.object({
45348
+ /** Opaque, single-use, bound to the caller and the request's organization. */
45349
+ ticket: external_exports.string(),
45350
+ expiresInSeconds: external_exports.number().int().positive()
45351
+ });
45352
+ var wsContract = c67.router({
45353
+ createTicket: {
45354
+ method: "POST",
45355
+ path: "/ws/ticket",
45356
+ body: c67.noBody(),
45357
+ responses: {
45358
+ 200: WsTicketResponseSchema,
45359
+ 401: ErrorResponseSchema,
45360
+ 403: ErrorResponseSchema,
45361
+ 503: ErrorResponseSchema
45362
+ },
45363
+ summary: "Mint a short-lived, single-use ticket that opens the scan-updates WebSocket"
45364
+ }
45365
+ });
45366
+
45111
45367
  // ../../packages/api-contracts/src/contracts/v1/index.ts
45112
- var c66 = initContract();
45113
- var v1Contract = c66.router(
45368
+ var c68 = initContract();
45369
+ var v1Contract = c68.router(
45114
45370
  {
45115
45371
  admin: adminContract,
45116
45372
  cloudIntegration: cloudIntegrationContract,
@@ -45120,6 +45376,7 @@ var v1Contract = c66.router(
45120
45376
  organization: organizationContract,
45121
45377
  oobListener: oobListenerContract,
45122
45378
  user: userContract,
45379
+ ws: wsContract,
45123
45380
  repository: repositoryContract,
45124
45381
  github: githubContract,
45125
45382
  staffGithub: staffGithubContract,
@@ -45175,6 +45432,7 @@ var v1Contract = c66.router(
45175
45432
  staffPentestStats: staffPentestStatsContract,
45176
45433
  staffKnowledgeFacts: staffKnowledgeFactsContract,
45177
45434
  staffPentests: staffPentestsContract,
45435
+ staffProducts: staffProductsContract,
45178
45436
  staffQueue: staffQueueContract,
45179
45437
  organizationDisposal: organizationDisposalContract
45180
45438
  },
@@ -45184,13 +45442,13 @@ var v1Contract = c66.router(
45184
45442
  );
45185
45443
 
45186
45444
  // ../../packages/api-contracts/src/contracts/index.ts
45187
- var c67 = initContract();
45188
- var contract = c67.router({
45445
+ var c69 = initContract();
45446
+ var contract = c69.router({
45189
45447
  v1: v1Contract
45190
45448
  });
45191
45449
 
45192
45450
  // ../../packages/api-contracts/src/contracts/v1/desktop-host-internal.ts
45193
- var c68 = initContract();
45451
+ var c70 = initContract();
45194
45452
  var MAX_VMS_PER_SYNC = 16;
45195
45453
  var DesktopHostSyncRequestSchema = external_exports.object({
45196
45454
  /** Integer protocol the runner speaks. Below the api's minimum, the host gets
@@ -45215,7 +45473,7 @@ var DesktopHostSyncResponseSchema = external_exports.object({
45215
45473
  * id not listed here is deleted. */
45216
45474
  targets: external_exports.array(DesktopHostSyncTargetSchema).max(MAX_VMS_PER_SYNC)
45217
45475
  });
45218
- var desktopHostInternalContract = c68.router({
45476
+ var desktopHostInternalContract = c70.router({
45219
45477
  sync: {
45220
45478
  method: "POST",
45221
45479
  path: "/internal/v1/desktop-hosts/sync",
@@ -45240,7 +45498,8 @@ var OPENAI_SESSION_TYPES = [
45240
45498
  "RECON",
45241
45499
  "API_COVERAGE",
45242
45500
  "PRODUCT_RECON",
45243
- "CODE_REVIEW"
45501
+ "CODE_REVIEW",
45502
+ "REMEDIATION"
45244
45503
  ];
45245
45504
  var AGENT_SESSION_MODELS = [
45246
45505
  {
@@ -45314,8 +45573,8 @@ var GitHubWebhookResponseSchema = external_exports.object({
45314
45573
  });
45315
45574
 
45316
45575
  // ../../packages/api-contracts/src/contracts/webhooks/github.ts
45317
- var c69 = initContract();
45318
- var githubWebhookContract = c69.router(
45576
+ var c71 = initContract();
45577
+ var githubWebhookContract = c71.router(
45319
45578
  {
45320
45579
  handleWebhook: {
45321
45580
  method: "POST",
@@ -45333,7 +45592,7 @@ var githubWebhookContract = c69.router(
45333
45592
  pathPrefix: "/webhooks"
45334
45593
  }
45335
45594
  );
45336
- var githubReadonlyWebhookContract = c69.router(
45595
+ var githubReadonlyWebhookContract = c71.router(
45337
45596
  {
45338
45597
  handleWebhook: {
45339
45598
  method: "POST",
@@ -45353,9 +45612,9 @@ var githubReadonlyWebhookContract = c69.router(
45353
45612
  );
45354
45613
 
45355
45614
  // ../../packages/api-contracts/src/contracts/webhooks/linear.ts
45356
- var c70 = initContract();
45615
+ var c72 = initContract();
45357
45616
  var LinearWebhookResponseSchema = external_exports.object({ ok: external_exports.boolean() });
45358
- var linearWebhookContract = c70.router(
45617
+ var linearWebhookContract = c72.router(
45359
45618
  {
45360
45619
  handleWebhook: {
45361
45620
  method: "POST",
@@ -45375,7 +45634,7 @@ var linearWebhookContract = c70.router(
45375
45634
  );
45376
45635
 
45377
45636
  // ../../packages/api-contracts/src/contracts/forge/bitbucket.ts
45378
- var c71 = initContract();
45637
+ var c73 = initContract();
45379
45638
  var InstallEventSchema = external_exports.object({
45380
45639
  eventType: external_exports.enum(["avi:forge:installed:app", "avi:forge:upgraded:app"]),
45381
45640
  context: external_exports.object({ cloudId: external_exports.string().min(1) }).loose(),
@@ -45404,7 +45663,7 @@ var ForgePairingCodeResponseSchema = external_exports.discriminatedUnion("state"
45404
45663
  expiresInSeconds: external_exports.number().int()
45405
45664
  })
45406
45665
  ]);
45407
- var forgeBitbucketContract = c71.router(
45666
+ var forgeBitbucketContract = c73.router(
45408
45667
  {
45409
45668
  lifecycle: {
45410
45669
  method: "POST",
@@ -45451,8 +45710,8 @@ var HealthResponseSchema = external_exports.object({
45451
45710
  });
45452
45711
 
45453
45712
  // ../../packages/api-contracts/src/contracts/health.ts
45454
- var c72 = initContract();
45455
- var healthContract = c72.router({
45713
+ var c74 = initContract();
45714
+ var healthContract = c74.router({
45456
45715
  getHealth: {
45457
45716
  method: "GET",
45458
45717
  path: "/health",
@@ -45464,8 +45723,8 @@ var healthContract = c72.router({
45464
45723
  });
45465
45724
 
45466
45725
  // ../../packages/api-contracts/src/contracts/v1/vulnerability-share.ts
45467
- var c73 = initContract();
45468
- var vulnerabilityShareContract = c73.router(
45726
+ var c75 = initContract();
45727
+ var vulnerabilityShareContract = c75.router(
45469
45728
  {
45470
45729
  resolveShareLink: {
45471
45730
  method: "GET",
@@ -45491,7 +45750,8 @@ var vulnerabilityShareContract = c73.router(
45491
45750
  401: ErrorResponseSchema,
45492
45751
  403: ErrorResponseSchema,
45493
45752
  404: ErrorResponseSchema,
45494
- 500: ErrorResponseSchema
45753
+ 500: ErrorResponseSchema,
45754
+ 503: ErrorResponseSchema
45495
45755
  }
45496
45756
  },
45497
45757
  verifyShareEmailCode: {
@@ -45515,8 +45775,8 @@ var vulnerabilityShareContract = c73.router(
45515
45775
  );
45516
45776
 
45517
45777
  // ../../packages/api-contracts/src/contracts/v1/attestation-verify.ts
45518
- var c74 = initContract();
45519
- var attestationVerifyContract = c74.router(
45778
+ var c76 = initContract();
45779
+ var attestationVerifyContract = c76.router(
45520
45780
  {
45521
45781
  verifyAttestation: {
45522
45782
  method: "GET",
@@ -45572,8 +45832,8 @@ var UpdatePrVulnerabilityRequestSchema = external_exports.object({
45572
45832
  });
45573
45833
 
45574
45834
  // ../../packages/api-contracts/src/contracts/v1/pr-vulnerability.ts
45575
- var c75 = initContract();
45576
- var prVulnerabilityContract = c75.router(
45835
+ var c77 = initContract();
45836
+ var prVulnerabilityContract = c77.router(
45577
45837
  {
45578
45838
  listPrVulnerabilities: {
45579
45839
  method: "GET",
@@ -45737,8 +45997,8 @@ var CoordinatorSessionSearchResponseSchema = external_exports.strictObject({
45737
45997
  });
45738
45998
 
45739
45999
  // ../../packages/api-contracts/src/contracts/v1/coordinator-inspection.ts
45740
- var c76 = initContract();
45741
- var coordinatorInspectionContract = c76.router({
46000
+ var c78 = initContract();
46001
+ var coordinatorInspectionContract = c78.router({
45742
46002
  sessionWindow: {
45743
46003
  method: "POST",
45744
46004
  path: "/internal/v1/agent-sessions/:agentSessionId/coordinator/session-window",
@@ -45780,7 +46040,7 @@ var coordinatorInspectionContract = c76.router({
45780
46040
  });
45781
46041
 
45782
46042
  // ../../packages/api-contracts/src/contracts/v1/pentest-coordinator-internal.ts
45783
- var c77 = initContract();
46043
+ var c79 = initContract();
45784
46044
  var params2 = external_exports.strictObject({ agentSessionId: external_exports.uuid() });
45785
46045
  var errors3 = {
45786
46046
  400: ErrorResponseSchema,
@@ -45793,7 +46053,7 @@ var errors3 = {
45793
46053
  500: ErrorResponseSchema,
45794
46054
  503: ErrorResponseSchema
45795
46055
  };
45796
- var pentestCoordinatorInternalContract = c77.router({
46056
+ var pentestCoordinatorInternalContract = c79.router({
45797
46057
  state: {
45798
46058
  method: "POST",
45799
46059
  path: "/internal/v1/agent-sessions/:agentSessionId/coordinator/state",
@@ -46040,8 +46300,8 @@ var CoordinatorCoverageResponseSchema = external_exports.strictObject({
46040
46300
  );
46041
46301
 
46042
46302
  // ../../packages/api-contracts/src/contracts/v1/coordinator-domain-read.ts
46043
- var c78 = initContract();
46044
- var coordinatorDomainReadContract = c78.router({
46303
+ var c80 = initContract();
46304
+ var coordinatorDomainReadContract = c80.router({
46045
46305
  coverage: {
46046
46306
  method: "POST",
46047
46307
  path: "/internal/v1/agent-sessions/:agentSessionId/coordinator/coverage",
@@ -46246,7 +46506,7 @@ var CoordinatorPublicDocumentationResponseSchema = CoordinatorContextTextReadRes
46246
46506
  var CoordinatorCustomerDocumentResponseSchema = CoordinatorContextTextReadResponseSchema;
46247
46507
 
46248
46508
  // ../../packages/api-contracts/src/contracts/v1/coordinator-context-read.ts
46249
- var c79 = initContract();
46509
+ var c81 = initContract();
46250
46510
  var errors4 = {
46251
46511
  400: ErrorResponseSchema,
46252
46512
  401: ErrorResponseSchema,
@@ -46258,7 +46518,7 @@ var errors4 = {
46258
46518
  500: ErrorResponseSchema,
46259
46519
  503: ErrorResponseSchema
46260
46520
  };
46261
- var coordinatorContextReadContract = c79.router({
46521
+ var coordinatorContextReadContract = c81.router({
46262
46522
  contextSources: {
46263
46523
  method: "POST",
46264
46524
  path: "/internal/v1/agent-sessions/:agentSessionId/coordinator/context-sources",
@@ -46492,19 +46752,19 @@ var COVERAGE_CLASSES = [
46492
46752
  },
46493
46753
  { taxonomy: "RECON", id: "RECON-15", name: "Deployment-platform config", shortLabel: "Deploy" }
46494
46754
  ];
46495
- var BY_ID = new Map(COVERAGE_CLASSES.map((c84) => [c84.id, c84]));
46755
+ var BY_ID = new Map(COVERAGE_CLASSES.map((c86) => [c86.id, c86]));
46496
46756
  function idsWhere(keep) {
46497
- return [OTHER_CLASS_ID, ...COVERAGE_CLASSES.filter(keep).map((c84) => c84.id)];
46757
+ return [OTHER_CLASS_ID, ...COVERAGE_CLASSES.filter(keep).map((c86) => c86.id)];
46498
46758
  }
46499
- var HUNTING_CLASS_IDS = idsWhere((c84) => c84.taxonomy !== "RECON");
46500
- var RECON_CLASS_IDS = idsWhere((c84) => c84.taxonomy === "RECON");
46759
+ var HUNTING_CLASS_IDS = idsWhere((c86) => c86.taxonomy !== "RECON");
46760
+ var RECON_CLASS_IDS = idsWhere((c86) => c86.taxonomy === "RECON");
46501
46761
  var HUNTING_ID_SET = new Set(HUNTING_CLASS_IDS);
46502
46762
  var RECON_ID_SET = new Set(RECON_CLASS_IDS);
46503
46763
  var TAXONOMY_ORDER = new Map(CoverageTaxonomyValues.map((t2, i2) => [t2, i2]));
46504
- var CLASS_ORDER = new Map(COVERAGE_CLASSES.map((c84, i2) => [c84.id, i2]));
46764
+ var CLASS_ORDER = new Map(COVERAGE_CLASSES.map((c86, i2) => [c86.id, i2]));
46505
46765
 
46506
46766
  // ../../packages/api-contracts/src/contracts/v1/api-coverage-internal.ts
46507
- var c80 = initContract();
46767
+ var c82 = initContract();
46508
46768
  var pathParams = external_exports.strictObject({ agentSessionId: external_exports.uuid() });
46509
46769
  var errors5 = {
46510
46770
  400: ErrorResponseSchema,
@@ -46514,7 +46774,7 @@ var errors5 = {
46514
46774
  500: ErrorResponseSchema
46515
46775
  };
46516
46776
  var base = "/internal/v1/agent-sessions/:agentSessionId/api-coverage";
46517
- var apiCoverageInternalContract = c80.router({
46777
+ var apiCoverageInternalContract = c82.router({
46518
46778
  upsertApiOperations: {
46519
46779
  method: "POST",
46520
46780
  path: `${base}/operations`,
@@ -46653,7 +46913,7 @@ var SetupNotesRequestSchema = external_exports.object({ runVersion: RunVersionSc
46653
46913
  var SetupNotesResponseSchema = external_exports.object({ notes: external_exports.string().nullable() });
46654
46914
 
46655
46915
  // ../../packages/api-contracts/src/contracts/v1/setup-session-internal.ts
46656
- var c81 = initContract();
46916
+ var c83 = initContract();
46657
46917
  var pathParams2 = external_exports.strictObject({ agentSessionId: external_exports.uuid() });
46658
46918
  var errors6 = {
46659
46919
  400: ErrorResponseSchema,
@@ -46665,7 +46925,7 @@ var errors6 = {
46665
46925
  503: ErrorResponseSchema
46666
46926
  };
46667
46927
  var base2 = "/internal/v1/agent-sessions/:agentSessionId/setup";
46668
- var setupSessionInternalContract = c81.router({
46928
+ var setupSessionInternalContract = c83.router({
46669
46929
  addSetupTarget: {
46670
46930
  method: "POST",
46671
46931
  path: `${base2}/target`,
@@ -46792,8 +47052,8 @@ var ListReviewPremiseChecksResponseSchema = external_exports.object({
46792
47052
  });
46793
47053
 
46794
47054
  // ../../packages/api-contracts/src/contracts/v1/premise-check-internal.ts
46795
- var c82 = initContract();
46796
- var premiseCheckInternalContract = c82.router({
47055
+ var c84 = initContract();
47056
+ var premiseCheckInternalContract = c84.router({
46797
47057
  listReviewPremiseChecks: {
46798
47058
  method: "POST",
46799
47059
  path: "/internal/v1/agent-sessions/:agentSessionId/premise-checks/list",
@@ -47617,6 +47877,7 @@ var PRODUCTION_API_URL = "https://api.securewithtrace.com";
47617
47877
  var UNAUTHORIZED_STATUS = 401;
47618
47878
  var REFRESH_AUTH_FAILURE_STATUS_CODES = /* @__PURE__ */ new Set([400, 401]);
47619
47879
  var MAX_REFRESH_ROTATION_RETRIES = 3;
47880
+ var TRACE_API_HOST_SUFFIX = ".securewithtrace.com";
47620
47881
  function getApiBaseUrl() {
47621
47882
  const raw = process.env["TRACE_API_URL"];
47622
47883
  if (!raw) {
@@ -47635,16 +47896,15 @@ function getApiBaseUrl() {
47635
47896
  console.error(colorWarning("Invalid TRACE_API_URL: only https:// is allowed. Using default."));
47636
47897
  return PRODUCTION_API_URL;
47637
47898
  }
47638
- const hostname3 = parsed.hostname;
47639
- if (hostname3 === "localhost" || hostname3 === "127.0.0.1" || hostname3 === "0.0.0.0" || hostname3 === "::1" || hostname3.startsWith("10.") || hostname3.startsWith("192.168.") || /^172\.(1[6-9]|2[0-9]|3[01])\./.test(hostname3)) {
47899
+ if (!parsed.hostname.endsWith(TRACE_API_HOST_SUFFIX)) {
47640
47900
  console.error(
47641
47901
  colorWarning(
47642
- "Invalid TRACE_API_URL: private/reserved hostnames are not allowed. Using default."
47902
+ `Ignoring TRACE_API_URL: '${parsed.hostname}' is not a Trace API host (*${TRACE_API_HOST_SUFFIX}). Using default.`
47643
47903
  )
47644
47904
  );
47645
47905
  return PRODUCTION_API_URL;
47646
47906
  }
47647
- return raw.replace(/\/+$/, "");
47907
+ return `${parsed.origin}${parsed.pathname}`.replace(/\/+$/, "");
47648
47908
  }
47649
47909
  function requireAuth() {
47650
47910
  const credential = loadCredentialOrExit();
@@ -47728,6 +47988,60 @@ function exitHumanPrincipalRequired() {
47728
47988
  console.error(colorError("This command requires a human login; run `tracecli auth login`."));
47729
47989
  process.exit(1);
47730
47990
  }
47991
+ function transportErrorCode(error48) {
47992
+ if (!(error48 instanceof Error)) {
47993
+ return null;
47994
+ }
47995
+ const codeOf = (value) => {
47996
+ if (typeof value !== "object" || value === null || !("code" in value)) {
47997
+ return null;
47998
+ }
47999
+ return typeof value.code === "string" && value.code.length > 0 ? value.code : null;
48000
+ };
48001
+ const code = codeOf(error48) ?? codeOf(error48.cause);
48002
+ if (code !== null) {
48003
+ return code;
48004
+ }
48005
+ return error48.name === "TypeError" && /^fetch failed/i.test(error48.message) ? "FETCH_FAILED" : null;
48006
+ }
48007
+ var TRANSPORT_ERROR_HINTS = {
48008
+ ENOTFOUND: "DNS lookup failed",
48009
+ EAI_AGAIN: "DNS lookup timed out",
48010
+ ECONNREFUSED: "connection refused",
48011
+ ECONNRESET: "connection reset",
48012
+ ETIMEDOUT: "connection timed out",
48013
+ ConnectionRefused: "connection refused",
48014
+ ConnectionClosed: "connection closed before a response arrived",
48015
+ FailedToOpenSocket: "could not open a socket",
48016
+ CERT_HAS_EXPIRED: "the server certificate has expired",
48017
+ UNABLE_TO_VERIFY_LEAF_SIGNATURE: "the server certificate could not be verified",
48018
+ DEPTH_ZERO_SELF_SIGNED_CERT: "the server presented a self-signed certificate",
48019
+ FETCH_FAILED: "the request never received a response"
48020
+ };
48021
+ function unreachableApiMessage(baseUrl, code) {
48022
+ const host = new URL(baseUrl).host;
48023
+ const detail = TRANSPORT_ERROR_HINTS[code] ?? "the request failed";
48024
+ return [
48025
+ `Couldn't reach the Trace API at ${host}: ${detail} (${code}).`,
48026
+ "Check that this machine can reach the internet. Sandboxed agents and CI runners often block",
48027
+ `outbound network access; allow ${host} and retry.`
48028
+ ].join("\n");
48029
+ }
48030
+ function exitUnreachableApi(code) {
48031
+ console.error(colorError(unreachableApiMessage(getApiBaseUrl(), code)));
48032
+ process.exit(1);
48033
+ }
48034
+ async function requestOrExit(request, token) {
48035
+ try {
48036
+ return await request(createClient(token));
48037
+ } catch (error48) {
48038
+ const code = transportErrorCode(error48);
48039
+ if (code !== null) {
48040
+ exitUnreachableApi(code);
48041
+ }
48042
+ throw error48;
48043
+ }
48044
+ }
47731
48045
  function createClient(token) {
47732
48046
  return initClient(v1Contract, {
47733
48047
  baseUrl: getApiBaseUrl(),
@@ -47855,7 +48169,7 @@ async function refreshStoredAccessTokenForOrganization(workosOrganizationId) {
47855
48169
  }
47856
48170
  async function authenticatedRequest(request) {
47857
48171
  const credential = loadCredentialOrExit();
47858
- const firstResult = await request(createClient(credential.token));
48172
+ const firstResult = await requestOrExit(request, credential.token);
47859
48173
  if (credential.kind === "api_key") {
47860
48174
  if (firstResult.status === UNAUTHORIZED_STATUS) {
47861
48175
  exitApiKeyUnauthorized();
@@ -47872,7 +48186,7 @@ async function authenticatedRequest(request) {
47872
48186
  if (!refreshedToken) {
47873
48187
  return firstResult;
47874
48188
  }
47875
- return request(createClient(refreshedToken));
48189
+ return requestOrExit(request, refreshedToken);
47876
48190
  }
47877
48191
  async function authenticatedRequestSafe(request) {
47878
48192
  let credential;
@@ -49616,6 +49930,62 @@ function resolveClearableUrl(value, clear, flag) {
49616
49930
  }
49617
49931
  return { value };
49618
49932
  }
49933
+ function normalizeRepositoryRole(input) {
49934
+ const candidate = input.trim().toUpperCase().replace(/-/g, "_");
49935
+ return ApplicationRepositoryRoleValues.find((role) => role === candidate) ?? null;
49936
+ }
49937
+ var REPOSITORY_ROLE_INPUTS = ApplicationRepositoryRoleValues.map(
49938
+ (role) => role.toLowerCase().replace(/_/g, "-")
49939
+ );
49940
+ function parseRepositoryRoles(inputs) {
49941
+ const picked = /* @__PURE__ */ new Set();
49942
+ for (const input of inputs) {
49943
+ const role = normalizeRepositoryRole(input);
49944
+ if (role === null) {
49945
+ return {
49946
+ error: `Invalid --role '${input}'. Use one of: ${REPOSITORY_ROLE_INPUTS.join(", ")}.`
49947
+ };
49948
+ }
49949
+ picked.add(role);
49950
+ }
49951
+ return { roles: ApplicationRepositoryRoleValues.filter((role) => picked.has(role)) };
49952
+ }
49953
+ function buildLinkRepositoryBody(input) {
49954
+ return {
49955
+ repositoryId: input.repositoryId,
49956
+ ...input.roles !== void 0 && input.roles.length > 0 ? { roles: [...input.roles] } : {},
49957
+ ...input.roleLabel !== void 0 ? { roleLabel: input.roleLabel } : {},
49958
+ ...input.repositoryPath !== void 0 ? { repositoryPath: input.repositoryPath } : {},
49959
+ ...input.scanEnabled !== void 0 ? { scanEnabled: input.scanEnabled } : {}
49960
+ };
49961
+ }
49962
+ function buildUpdateLinkBody(input) {
49963
+ return {
49964
+ ...input.roles !== void 0 ? { roles: [...input.roles] } : {},
49965
+ ...input.roleLabel !== void 0 ? { roleLabel: input.roleLabel } : {},
49966
+ ...input.repositoryPath !== void 0 ? { repositoryPath: input.repositoryPath } : {},
49967
+ ...input.scanEnabled !== void 0 ? { scanEnabled: input.scanEnabled } : {}
49968
+ };
49969
+ }
49970
+ function isEmptyLinkUpdate(body) {
49971
+ return Object.keys(body).length === 0;
49972
+ }
49973
+ function validateRoleLabel(roles, roleLabel) {
49974
+ if (roles === void 0 || roleLabel === void 0 || roleLabel === null) {
49975
+ return null;
49976
+ }
49977
+ return roles.includes("OTHER") ? null : "--role-label requires --role other.";
49978
+ }
49979
+ function findLinkForRepo(links, input) {
49980
+ if (isUuid(input)) {
49981
+ const id = input.toLowerCase();
49982
+ return links.find(
49983
+ (link) => link.applicationRepositoryId?.toLowerCase() === id || link.repositoryId.toLowerCase() === id
49984
+ ) ?? null;
49985
+ }
49986
+ const target = normalizeRepoUrlForMatch(resolveRepoUrl(input));
49987
+ return links.find((link) => normalizeRepoUrlForMatch(link.repositoryUrl) === target) ?? null;
49988
+ }
49619
49989
  function failWriteOp(action, status, body, notFoundLabel) {
49620
49990
  const { message, errorCode } = readErrorFields(body);
49621
49991
  if (status === UNAUTHORIZED_STATUS2) {
@@ -49656,6 +50026,28 @@ function failWriteOp(action, status, body, notFoundLabel) {
49656
50026
  );
49657
50027
  process.exit(1);
49658
50028
  }
50029
+ function failLinkOp(action, status, body) {
50030
+ const { message } = readErrorFields(body);
50031
+ if (status === UNAUTHORIZED_STATUS2) {
50032
+ exitAuthFailed();
50033
+ }
50034
+ if (status === 403) {
50035
+ console.error(
50036
+ colorError(
50037
+ "Repository links require an organization admin or Trace staff on a pentest-enabled organization, signed in with a browser session (API keys are rejected)."
50038
+ )
50039
+ );
50040
+ process.exit(1);
50041
+ }
50042
+ if (status === 404 || status === 409 || status === 400) {
50043
+ console.error(colorError(message ?? `Failed to ${action} (status ${status}).`));
50044
+ process.exit(1);
50045
+ }
50046
+ console.error(
50047
+ colorError(`Failed to ${action} repository (status ${status})${message ? `: ${message}` : "."}`)
50048
+ );
50049
+ process.exit(1);
50050
+ }
49659
50051
  function failReadOp(action, status, body, notFoundLabel) {
49660
50052
  const { message } = readErrorFields(body);
49661
50053
  if (status === UNAUTHORIZED_STATUS2) {
@@ -49717,12 +50109,12 @@ function buildApplicationsTable(apps) {
49717
50109
  repos: String(a2.repositories.length),
49718
50110
  url: a2.applicationUrl ? sanitizeDisplay(a2.applicationUrl) : "\u2014"
49719
50111
  }));
49720
- const idWidth = Math.max(2, ...cells.map((c84) => c84.id.length));
49721
- const nameWidth = Math.max(4, ...cells.map((c84) => c84.name.length));
49722
- const typeWidth = Math.max(4, ...cells.map((c84) => c84.type.length));
50112
+ const idWidth = Math.max(2, ...cells.map((c86) => c86.id.length));
50113
+ const nameWidth = Math.max(4, ...cells.map((c86) => c86.name.length));
50114
+ const typeWidth = Math.max(4, ...cells.map((c86) => c86.type.length));
49723
50115
  const header = `${"ID".padEnd(idWidth)} ${"NAME".padEnd(nameWidth)} ${"TYPE".padEnd(typeWidth)} REPOS URL`;
49724
50116
  const rows = cells.map(
49725
- (c84) => `${c84.id.padEnd(idWidth)} ${c84.name.padEnd(nameWidth)} ${c84.type.padEnd(typeWidth)} ${c84.repos.padStart(5)} ${c84.url}`
50117
+ (c86) => `${c86.id.padEnd(idWidth)} ${c86.name.padEnd(nameWidth)} ${c86.type.padEnd(typeWidth)} ${c86.repos.padStart(5)} ${c86.url}`
49726
50118
  );
49727
50119
  return { header, rows };
49728
50120
  }
@@ -49742,12 +50134,12 @@ function buildApplicationRepositoriesTable(links) {
49742
50134
  path: l2.repositoryPath ? sanitizeDisplay(l2.repositoryPath) : "\u2014",
49743
50135
  status: formatStatus(l2.repositoryStatus)
49744
50136
  }));
49745
- const nameWidth = Math.max(10, ...cells.map((c84) => c84.name.length));
49746
- const roleWidth = Math.max(4, ...cells.map((c84) => c84.role.length));
49747
- const pathWidth = Math.max(4, ...cells.map((c84) => c84.path.length));
50137
+ const nameWidth = Math.max(10, ...cells.map((c86) => c86.name.length));
50138
+ const roleWidth = Math.max(4, ...cells.map((c86) => c86.role.length));
50139
+ const pathWidth = Math.max(4, ...cells.map((c86) => c86.path.length));
49748
50140
  const header = `${"REPOSITORY".padEnd(nameWidth)} SCAN ${"ROLE".padEnd(roleWidth)} ${"PATH".padEnd(pathWidth)} STATUS`;
49749
50141
  const rows = cells.map(
49750
- (c84) => `${c84.name.padEnd(nameWidth)} ${c84.scan.padEnd(4)} ${c84.role.padEnd(roleWidth)} ${c84.path.padEnd(pathWidth)} ${c84.status}`
50142
+ (c86) => `${c86.name.padEnd(nameWidth)} ${c86.scan.padEnd(4)} ${c86.role.padEnd(roleWidth)} ${c86.path.padEnd(pathWidth)} ${c86.status}`
49751
50143
  );
49752
50144
  return { header, rows };
49753
50145
  }
@@ -50010,6 +50402,205 @@ async function runDelete(applicationId, options) {
50010
50402
  }
50011
50403
  console.log(colorSuccess(`Deleted application ${applicationId}`));
50012
50404
  }
50405
+ function renderLinkDetail(link) {
50406
+ const pad = 11;
50407
+ return [
50408
+ `${"Link ID:".padEnd(pad)} ${link.applicationRepositoryId ?? "\u2014"}`,
50409
+ `${"Repository:".padEnd(pad)} ${sanitizeDisplay(link.repositoryName)} (${link.repositoryId})`,
50410
+ `${"URL:".padEnd(pad)} ${sanitizeDisplay(link.repositoryUrl)}`,
50411
+ `${"Scan:".padEnd(pad)} ${link.scanEnabled ? "yes" : "no"}`,
50412
+ `${"Role:".padEnd(pad)} ${sanitizeDisplay(formatLinkRole(link.role, link.roleLabel, link.roles))}`,
50413
+ `${"Path:".padEnd(pad)} ${link.repositoryPath ? sanitizeDisplay(link.repositoryPath) : "\u2014"}`,
50414
+ `${"Status:".padEnd(pad)} ${formatStatus(link.repositoryStatus)}`
50415
+ ].join("\n");
50416
+ }
50417
+ function outputLink(link, output) {
50418
+ if (output === "json") {
50419
+ printJson(link);
50420
+ return;
50421
+ }
50422
+ if (output === "tsv") {
50423
+ printApplicationRepositoriesTsv([link]);
50424
+ return;
50425
+ }
50426
+ console.log(renderLinkDetail(link));
50427
+ }
50428
+ function exitInvalidApplicationId(applicationId) {
50429
+ console.error(colorError(`Invalid application id '${applicationId}'. Expected a UUID.`));
50430
+ process.exit(1);
50431
+ }
50432
+ async function resolveExistingLink(organizationId, applicationId, repoInput) {
50433
+ const result = await authenticatedRequest(
50434
+ (client) => client.application.listApplicationRepositories({ params: { organizationId, applicationId } })
50435
+ );
50436
+ if (result.status !== SUCCESS_STATUS) {
50437
+ failReadOp("list application repositories", result.status, result.body, applicationId);
50438
+ }
50439
+ const link = findLinkForRepo(result.body, repoInput);
50440
+ if (!link) {
50441
+ console.error(
50442
+ colorError(
50443
+ `Repository ${repoInput} is not linked to application ${applicationId}. Run \`tracecli application repos ${applicationId}\` to see its links.`
50444
+ )
50445
+ );
50446
+ process.exit(1);
50447
+ }
50448
+ if (link.applicationRepositoryId === null) {
50449
+ console.error(
50450
+ colorError(
50451
+ `Repository ${repoInput} is linked without a link id, so it can't be changed from the CLI. Edit it in the dashboard.`
50452
+ )
50453
+ );
50454
+ process.exit(1);
50455
+ }
50456
+ return { ...link, applicationRepositoryId: link.applicationRepositoryId };
50457
+ }
50458
+ async function runLink(applicationId, options) {
50459
+ const output = parseOutput(options.output);
50460
+ if (!isUuid(applicationId)) {
50461
+ exitInvalidApplicationId(applicationId);
50462
+ }
50463
+ const parsedRoles = parseRepositoryRoles(options.role ?? []);
50464
+ if ("error" in parsedRoles) {
50465
+ console.error(colorError(parsedRoles.error));
50466
+ process.exit(1);
50467
+ }
50468
+ const roles = options.role !== void 0 ? parsedRoles.roles : void 0;
50469
+ const labelError = validateRoleLabel(roles ?? [], options.roleLabel);
50470
+ if (labelError) {
50471
+ console.error(colorError(labelError));
50472
+ process.exit(1);
50473
+ }
50474
+ const organizationId = await resolveOrganizationId();
50475
+ const repositoryId = await resolveRepositoryId(organizationId, options.repo);
50476
+ const body = buildLinkRepositoryBody({
50477
+ repositoryId,
50478
+ roles,
50479
+ roleLabel: options.roleLabel,
50480
+ repositoryPath: options.repoPath,
50481
+ // Commander defaults a lone `--no-scan` to true; only an explicit opt-out
50482
+ // goes on the wire so the API's own default applies otherwise.
50483
+ scanEnabled: options.scan === false ? false : void 0
50484
+ });
50485
+ const result = await authenticatedRequest(
50486
+ (client) => client.application.createApplicationRepository({
50487
+ params: { organizationId, applicationId },
50488
+ body
50489
+ })
50490
+ );
50491
+ if (result.status !== CREATED_STATUS) {
50492
+ failLinkOp("link", result.status, result.body);
50493
+ }
50494
+ if (output === "table") {
50495
+ console.log(
50496
+ colorSuccess(
50497
+ `Linked ${sanitizeDisplay(result.body.repositoryName)} to application ${applicationId}`
50498
+ )
50499
+ );
50500
+ }
50501
+ outputLink(result.body, output);
50502
+ }
50503
+ var UPDATE_LINK_FLAGS = "--role, --clear-roles, --role-label, --clear-role-label, --repo-path, --clear-repo-path, --scan, --no-scan";
50504
+ async function runUpdateLink(applicationId, options) {
50505
+ const output = parseOutput(options.output);
50506
+ if (!isUuid(applicationId)) {
50507
+ exitInvalidApplicationId(applicationId);
50508
+ }
50509
+ if (options.role !== void 0 && options.clearRoles) {
50510
+ console.error(colorError("Pass only one of --role / --clear-roles."));
50511
+ process.exit(1);
50512
+ }
50513
+ const parsedRoles = parseRepositoryRoles(options.role ?? []);
50514
+ if ("error" in parsedRoles) {
50515
+ console.error(colorError(parsedRoles.error));
50516
+ process.exit(1);
50517
+ }
50518
+ const roles = options.clearRoles ? [] : options.role !== void 0 ? parsedRoles.roles : void 0;
50519
+ const roleLabel = resolveClearableOption(options.roleLabel, options.clearRoleLabel, "role-label");
50520
+ if ("error" in roleLabel) {
50521
+ console.error(colorError(roleLabel.error));
50522
+ process.exit(1);
50523
+ }
50524
+ const repositoryPath = resolveClearableOption(
50525
+ options.repoPath,
50526
+ options.clearRepoPath,
50527
+ "repo-path"
50528
+ );
50529
+ if ("error" in repositoryPath) {
50530
+ console.error(colorError(repositoryPath.error));
50531
+ process.exit(1);
50532
+ }
50533
+ const labelError = validateRoleLabel(roles, roleLabel.value);
50534
+ if (labelError) {
50535
+ console.error(colorError(labelError));
50536
+ process.exit(1);
50537
+ }
50538
+ const body = buildUpdateLinkBody({
50539
+ roles,
50540
+ roleLabel: roleLabel.value,
50541
+ repositoryPath: repositoryPath.value,
50542
+ scanEnabled: options.scan
50543
+ });
50544
+ if (isEmptyLinkUpdate(body)) {
50545
+ console.error(colorError(`Nothing to update. Pass at least one of ${UPDATE_LINK_FLAGS}.`));
50546
+ process.exit(1);
50547
+ }
50548
+ const organizationId = await resolveOrganizationId();
50549
+ const existing = await resolveExistingLink(organizationId, applicationId, options.repo);
50550
+ const result = await authenticatedRequest(
50551
+ (client) => client.application.updateApplicationRepository({
50552
+ params: {
50553
+ organizationId,
50554
+ applicationId,
50555
+ applicationRepositoryId: existing.applicationRepositoryId
50556
+ },
50557
+ body
50558
+ })
50559
+ );
50560
+ if (result.status !== SUCCESS_STATUS) {
50561
+ failLinkOp("update link", result.status, result.body);
50562
+ }
50563
+ if (output === "table") {
50564
+ console.log(
50565
+ colorSuccess(
50566
+ `Updated link for ${sanitizeDisplay(result.body.repositoryName)} on application ${applicationId}`
50567
+ )
50568
+ );
50569
+ }
50570
+ outputLink(result.body, output);
50571
+ }
50572
+ async function runUnlink(applicationId, options) {
50573
+ if (!isUuid(applicationId)) {
50574
+ exitInvalidApplicationId(applicationId);
50575
+ }
50576
+ const organizationId = await resolveOrganizationId();
50577
+ const existing = await resolveExistingLink(organizationId, applicationId, options.repo);
50578
+ const confirmed = await confirmAction(
50579
+ `Unlink ${sanitizeDisplay(existing.repositoryName)} from application ${applicationId}?`,
50580
+ { skip: options.yes === true, verb: "unlink" }
50581
+ );
50582
+ if (!confirmed) {
50583
+ console.log("Aborted.");
50584
+ return;
50585
+ }
50586
+ const result = await authenticatedRequest(
50587
+ (client) => client.application.deleteApplicationRepository({
50588
+ params: {
50589
+ organizationId,
50590
+ applicationId,
50591
+ applicationRepositoryId: existing.applicationRepositoryId
50592
+ }
50593
+ })
50594
+ );
50595
+ if (result.status !== NO_CONTENT_STATUS) {
50596
+ failLinkOp("unlink", result.status, result.body);
50597
+ }
50598
+ console.log(
50599
+ colorSuccess(
50600
+ `Unlinked ${sanitizeDisplay(existing.repositoryName)} from application ${applicationId}`
50601
+ )
50602
+ );
50603
+ }
50013
50604
  function createCreateCommand() {
50014
50605
  return new Command("create").description("Create a new application").argument("<name>", "Application name").option("--type <type>", "Application type: web, cli, mobile, desktop, api-service", "web").option("--url <url>", "Application URL (required for web/api-service)").option("--repo <id-or-url>", "Link a repository at creation (UUID, URL, or owner/repo)").option("--repo-path <path>", "Path within the linked repository").option("--help-center-url <url>", "Help center URL").option("--docs-url <url>", "Documentation URL").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
50015
50606
  "after",
@@ -50061,6 +50652,59 @@ Examples:
50061
50652
  await runUpdate(applicationId, options);
50062
50653
  });
50063
50654
  }
50655
+ var ROLE_FLAG_HELP = `Repository role (repeatable): ${REPOSITORY_ROLE_INPUTS.join(", ")}`;
50656
+ function createLinkCommand() {
50657
+ return new Command("link").description("Link a repository to an application").argument("<applicationId>", "Application UUID").requiredOption("--repo <id-or-url>", "Repository to link (UUID, URL, or owner/repo)").option("--role <role>", ROLE_FLAG_HELP, collectRepeatable).option("--role-label <label>", 'Custom label for the "other" role').option("--repo-path <path>", "Path within the repository").option("--no-scan", "Link without including the repository in scans").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
50658
+ "after",
50659
+ `
50660
+ A link is scan-enabled unless --no-scan is passed. Scan-disabled links are
50661
+ skipped by scans and do not satisfy the repository precondition for starting a
50662
+ pentest.
50663
+
50664
+ Examples:
50665
+ tracecli application link <appId> --repo acme/store
50666
+ tracecli application link <appId> --repo acme/store --role frontend --role backend-api
50667
+ tracecli application link <appId> --repo acme/tools --role other --role-label "Design system"
50668
+ tracecli application link <appId> --repo acme/monorepo --repo-path apps/web --no-scan`
50669
+ ).action(async (applicationId, options) => {
50670
+ await runLink(applicationId, options);
50671
+ });
50672
+ }
50673
+ function createUpdateLinkCommand() {
50674
+ return new Command("update-link").description("Change an existing repository link's roles, label, path, or scan state").argument("<applicationId>", "Application UUID").requiredOption(
50675
+ "--repo <id-or-url>",
50676
+ "Linked repository to change (repository UUID, link UUID, URL, or owner/repo)"
50677
+ ).option("--role <role>", `${ROLE_FLAG_HELP}; replaces the current roles`, collectRepeatable).option("--clear-roles", "Remove every role from the link").option("--role-label <label>", 'Custom label for the "other" role').option("--clear-role-label", "Remove the custom role label").option("--repo-path <path>", "Path within the repository").option("--clear-repo-path", "Remove the repository path").option("--scan", "Include the repository in scans").option("--no-scan", "Exclude the repository from scans (the link stays)").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
50678
+ "after",
50679
+ `
50680
+ The update is partial: only the flags you pass change. --role replaces the
50681
+ whole role set, so pass every role the link should keep.
50682
+
50683
+ Examples:
50684
+ tracecli application update-link <appId> --repo acme/store --role frontend --role backend-api
50685
+ tracecli application update-link <appId> --repo acme/store --repo-path apps/web
50686
+ tracecli application update-link <appId> --repo acme/store --no-scan
50687
+ tracecli application update-link <appId> --repo <repositoryId> --scan -o json`
50688
+ ).action(async (applicationId, options) => {
50689
+ await runUpdateLink(applicationId, options);
50690
+ });
50691
+ }
50692
+ function createUnlinkCommand() {
50693
+ return new Command("unlink").description("Remove a repository link from an application").argument("<applicationId>", "Application UUID").requiredOption(
50694
+ "--repo <id-or-url>",
50695
+ "Linked repository to remove (repository UUID, link UUID, URL, or owner/repo)"
50696
+ ).option("-y, --yes", "Skip the confirmation prompt (required in non-interactive shells)").addHelpText(
50697
+ "after",
50698
+ `
50699
+ Only the link is removed; the repository stays connected to the organization.
50700
+
50701
+ Examples:
50702
+ tracecli application unlink <appId> --repo acme/store
50703
+ tracecli application unlink <appId> --repo <repositoryId> --yes`
50704
+ ).action(async (applicationId, options) => {
50705
+ await runUnlink(applicationId, options);
50706
+ });
50707
+ }
50064
50708
  function createDeleteCommand() {
50065
50709
  return new Command("delete").description("Delete an application").argument("<applicationId>", "Application UUID").option("-y, --yes", "Skip the confirmation prompt (required in non-interactive shells)").action(async (applicationId, options) => {
50066
50710
  await runDelete(applicationId, options);
@@ -50072,6 +50716,9 @@ function createApplicationCommand() {
50072
50716
  application.addCommand(createListCommand2());
50073
50717
  application.addCommand(createGetCommand());
50074
50718
  application.addCommand(createReposCommand());
50719
+ application.addCommand(createLinkCommand());
50720
+ application.addCommand(createUpdateLinkCommand());
50721
+ application.addCommand(createUnlinkCommand());
50075
50722
  application.addCommand(createUpdateCommand());
50076
50723
  application.addCommand(createDeleteCommand());
50077
50724
  return application;
@@ -50532,8 +51179,8 @@ function wrapTextWithPrefix(e, r2, o2, t2 = o2, s = o2, n3) {
50532
51179
  hard: true,
50533
51180
  trim: false
50534
51181
  }).split(`
50535
- `).map((c84, i2, m2) => {
50536
- const d = n3 ? n3(c84, i2) : c84;
51182
+ `).map((c86, i2, m2) => {
51183
+ const d = n3 ? n3(c86, i2) : c86;
50537
51184
  return i2 === 0 ? `${t2}${d}` : i2 === m2.length - 1 ? `${s}${d}` : `${o2}${d}`;
50538
51185
  }).join(`
50539
51186
  `);
@@ -51031,14 +51678,14 @@ var limitOptions = ({
51031
51678
  Math.min(l2 - a2 + 3, e.length - a2),
51032
51679
  0
51033
51680
  ));
51034
- let d = a2 < e.length && f > 0, c84 = a2 < e.length && f + a2 < e.length;
51681
+ let d = a2 < e.length && f > 0, c86 = a2 < e.length && f + a2 < e.length;
51035
51682
  const W = Math.min(
51036
51683
  f + a2,
51037
51684
  e.length
51038
51685
  ), s = [];
51039
51686
  let g = 0;
51040
- d && g++, c84 && g++;
51041
- const T = f + (d ? 1 : 0), y = W - (c84 ? 1 : 0);
51687
+ d && g++, c86 && g++;
51688
+ const T = f + (d ? 1 : 0), y = W - (c86 ? 1 : 0);
51042
51689
  for (let t2 = T; t2 < y; t2++) {
51043
51690
  const n3 = e[t2], o2 = n3 ? w(n3, t2 === l2) : "", h2 = wrapAnsi(o2, i2, {
51044
51691
  hard: true,
@@ -51059,14 +51706,14 @@ var limitOptions = ({
51059
51706
  u4,
51060
51707
  true
51061
51708
  );
51062
- d ? ({ lineCount: o2, removals: t2 } = L(), o2 > u4 && (c84 || (u4 -= 1), { lineCount: o2, removals: n3 } = E())) : (c84 || (u4 -= 1), { lineCount: o2, removals: n3 } = E(), o2 > u4 && (u4 -= 1, { lineCount: o2, removals: t2 } = L())), t2 > 0 && (d = true, s.splice(0, t2)), n3 > 0 && (c84 = true, s.splice(s.length - n3, n3));
51709
+ d ? ({ lineCount: o2, removals: t2 } = L(), o2 > u4 && (c86 || (u4 -= 1), { lineCount: o2, removals: n3 } = E())) : (c86 || (u4 -= 1), { lineCount: o2, removals: n3 } = E(), o2 > u4 && (u4 -= 1, { lineCount: o2, removals: t2 } = L())), t2 > 0 && (d = true, s.splice(0, t2)), n3 > 0 && (c86 = true, s.splice(s.length - n3, n3));
51063
51710
  }
51064
51711
  const x = [];
51065
51712
  d && x.push(M);
51066
51713
  for (const t2 of s)
51067
51714
  for (const n3 of t2)
51068
51715
  x.push(n3);
51069
- return c84 && x.push(M), x;
51716
+ return c86 && x.push(M), x;
51070
51717
  };
51071
51718
  var confirm = (i2) => {
51072
51719
  const a2 = i2.active ?? "Yes", s = i2.inactive ?? "No";
@@ -51085,15 +51732,15 @@ var confirm = (i2) => {
51085
51732
  u4
51086
51733
  ), o2 = `${e ? `${styleText2("gray", S_BAR)}
51087
51734
  ` : ""}${f}
51088
- `, c84 = this.value ? a2 : s;
51735
+ `, c86 = this.value ? a2 : s;
51089
51736
  switch (this.state) {
51090
51737
  case "submit": {
51091
51738
  const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
51092
- return `${o2}${r2}${styleText2("dim", c84)}`;
51739
+ return `${o2}${r2}${styleText2("dim", c86)}`;
51093
51740
  }
51094
51741
  case "cancel": {
51095
51742
  const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
51096
- return `${o2}${r2}${styleText2(["strikethrough", "dim"], c84)}${e ? `
51743
+ return `${o2}${r2}${styleText2(["strikethrough", "dim"], c86)}${e ? `
51097
51744
  ${styleText2("gray", S_BAR)}` : ""}`;
51098
51745
  }
51099
51746
  default: {
@@ -51241,13 +51888,13 @@ var multiline = (e) => new h({
51241
51888
  `, m2 = e.placeholder && e.placeholder.length > 0 ? (
51242
51889
  // biome-ignore lint/style/noNonNullAssertion: guarded by placeholder.length > 0
51243
51890
  styleText2("inverse", e.placeholder[0]) + styleText2("dim", e.placeholder.slice(1))
51244
- ) : styleText2(["inverse", "hidden"], "_"), a2 = this.userInput ? this.userInputWithCursor : m2, l2 = this.value ?? "", c84 = e.showSubmit ? `
51891
+ ) : styleText2(["inverse", "hidden"], "_"), a2 = this.userInput ? this.userInputWithCursor : m2, l2 = this.value ?? "", c86 = e.showSubmit ? `
51245
51892
  ${styleText2(this.focused === "submit" ? "cyan" : "dim", "[ submit ]")}` : "";
51246
51893
  switch (this.state) {
51247
51894
  case "error": {
51248
51895
  const n3 = `${styleText2("yellow", S_BAR)} `, r2 = i2 ? wrapTextWithPrefix(e.output, a2, n3, void 0) : a2, u4 = styleText2("yellow", S_BAR_END);
51249
51896
  return `${o2}${r2}
51250
- ${u4} ${styleText2("yellow", this.error)}${c84}
51897
+ ${u4} ${styleText2("yellow", this.error)}${c86}
51251
51898
  `;
51252
51899
  }
51253
51900
  case "submit": {
@@ -51275,7 +51922,7 @@ ${u4} ${styleText2("yellow", this.error)}${c84}
51275
51922
  default: {
51276
51923
  const n3 = i2 ? `${styleText2("cyan", S_BAR)} ` : "", r2 = i2 ? styleText2("cyan", S_BAR_END) : "", u4 = i2 ? wrapTextWithPrefix(e.output, a2, n3) : a2;
51277
51924
  return `${o2}${u4}
51278
- ${r2}${c84}
51925
+ ${r2}${c86}
51279
51926
  `;
51280
51927
  }
51281
51928
  }
@@ -51290,7 +51937,7 @@ var password = (r2) => new u$1({
51290
51937
  render() {
51291
51938
  const e = r2.withGuide ?? settings.withGuide, o2 = `${e ? `${styleText2("gray", S_BAR)}
51292
51939
  ` : ""}${symbol2(this.state)} ${r2.message}
51293
- `, c84 = this.userInputWithCursor, i2 = this.masked;
51940
+ `, c86 = this.userInputWithCursor, i2 = this.masked;
51294
51941
  switch (this.state) {
51295
51942
  case "error": {
51296
51943
  const s = e ? `${styleText2("yellow", S_BAR)} ` : "", n3 = e ? `${styleText2("yellow", S_BAR_END)} ` : "", l2 = i2 ?? "";
@@ -51310,7 +51957,7 @@ ${styleText2("gray", S_BAR)}` : ""}`;
51310
51957
  }
51311
51958
  default: {
51312
51959
  const s = e ? `${styleText2("cyan", S_BAR)} ` : "", n3 = e ? styleText2("cyan", S_BAR_END) : "";
51313
- return `${o2}${s}${c84}
51960
+ return `${o2}${s}${c86}
51314
51961
  ${n3}
51315
51962
  `;
51316
51963
  }
@@ -51326,7 +51973,7 @@ var SELECT_INSTRUCTIONS = [
51326
51973
  `${styleText2("dim", "\u2191/\u2193")} to navigate`,
51327
51974
  `${styleText2("dim", "Enter:")} confirm`
51328
51975
  ];
51329
- var c83 = (t2, o2) => t2.includes(`
51976
+ var c85 = (t2, o2) => t2.includes(`
51330
51977
  `) ? t2.split(`
51331
51978
  `).map((d) => o2(d)).join(`
51332
51979
  `) : o2(t2);
@@ -51337,15 +51984,15 @@ var select = (t2) => {
51337
51984
  const s = n3.label ?? String(n3.value);
51338
51985
  switch (m2) {
51339
51986
  case "disabled":
51340
- return `${styleText2("gray", S_RADIO_INACTIVE)} ${c83(s, (i2) => styleText2("gray", i2))}${n3.hint ? ` ${styleText2("dim", `(${n3.hint ?? "disabled"})`)}` : ""}`;
51987
+ return `${styleText2("gray", S_RADIO_INACTIVE)} ${c85(s, (i2) => styleText2("gray", i2))}${n3.hint ? ` ${styleText2("dim", `(${n3.hint ?? "disabled"})`)}` : ""}`;
51341
51988
  case "selected":
51342
- return `${c83(s, (i2) => styleText2("dim", i2))}`;
51989
+ return `${c85(s, (i2) => styleText2("dim", i2))}`;
51343
51990
  case "active":
51344
51991
  return `${styleText2("green", S_RADIO_ACTIVE)} ${s}${n3.hint ? ` ${styleText2("dim", `(${n3.hint})`)}` : ""}`;
51345
51992
  case "cancelled":
51346
- return `${c83(s, (i2) => styleText2(["strikethrough", "dim"], i2))}`;
51993
+ return `${c85(s, (i2) => styleText2(["strikethrough", "dim"], i2))}`;
51347
51994
  default:
51348
- return `${styleText2("dim", S_RADIO_INACTIVE)} ${c83(s, (i2) => styleText2("dim", i2))}`;
51995
+ return `${styleText2("dim", S_RADIO_INACTIVE)} ${c85(s, (i2) => styleText2("dim", i2))}`;
51349
51996
  }
51350
51997
  }, d = t2.showInstructions ?? true;
51351
51998
  return new n$1({
@@ -51406,6 +52053,18 @@ var i = `${styleText2("gray", S_BAR)} `;
51406
52053
 
51407
52054
  // src/org/invite.ts
51408
52055
  var MEMBER_ROLE_SLUGS = MemberRoleSlugSchema.options;
52056
+ var ROLE_NAMES = {
52057
+ admin: "admin",
52058
+ analyst: "manager",
52059
+ developer: "developer"
52060
+ };
52061
+ var ROLE_BY_NAME = {
52062
+ admin: "admin",
52063
+ manager: "analyst",
52064
+ analyst: "analyst",
52065
+ developer: "developer"
52066
+ };
52067
+ var ROLE_CHOICES = MEMBER_ROLE_SLUGS.map((slug) => ROLE_NAMES[slug]).join(", ");
51409
52068
  var DEFAULT_INVITE_ROLE = CreateMemberInvitationRequestSchema.shape.roleSlug.parse(void 0);
51410
52069
  var InviteEmailSchema = CreateMemberInvitationRequestSchema.shape.email;
51411
52070
  function planInvite(emailArg, options) {
@@ -51416,14 +52075,13 @@ function planInvite(emailArg, options) {
51416
52075
  if (!InviteEmailSchema.safeParse(email3).success) {
51417
52076
  return { error: `'${sanitizeDisplay(email3)}' is not a valid email address.` };
51418
52077
  }
51419
- const role = options.role.trim().toLowerCase();
51420
- const parsedRole = MemberRoleSlugSchema.safeParse(role);
51421
- if (!parsedRole.success) {
52078
+ const roleSlug = ROLE_BY_NAME[options.role.trim().toLowerCase()];
52079
+ if (roleSlug === void 0) {
51422
52080
  return {
51423
- error: `Invalid --role '${sanitizeDisplay(options.role)}'. Use one of: ${MEMBER_ROLE_SLUGS.join(", ")}.`
52081
+ error: `Invalid --role '${sanitizeDisplay(options.role)}'. Use one of: ${ROLE_CHOICES}.`
51424
52082
  };
51425
52083
  }
51426
- return { plan: { email: email3, roleSlug: parsedRole.data } };
52084
+ return { plan: { email: email3, roleSlug } };
51427
52085
  }
51428
52086
  function failInvite(status, body) {
51429
52087
  const { message } = readErrorFields(body);
@@ -51431,7 +52089,7 @@ function failInvite(status, body) {
51431
52089
  exitAuthFailed();
51432
52090
  }
51433
52091
  if (status === 403) {
51434
- const hint = "Inviting members requires an organization admin or analyst signed in with `tracecli auth login` (API keys are rejected).";
52092
+ const hint = "Inviting members requires an organization admin signed in with `tracecli auth login` (API keys are rejected).";
51435
52093
  console.error(
51436
52094
  colorError(message === void 0 || message === "Insufficient permissions" ? hint : message)
51437
52095
  );
@@ -51476,7 +52134,7 @@ function outputInvitation(invitation, output) {
51476
52134
  }
51477
52135
  console.log(
51478
52136
  colorSuccess(
51479
- `Invitation sent to ${sanitizeDisplay(invitation.email)} as ${sanitizeDisplay(invitation.roleSlug)}`
52137
+ `Invitation sent to ${sanitizeDisplay(invitation.email)} as ${ROLE_NAMES[invitation.roleSlug]}`
51480
52138
  )
51481
52139
  );
51482
52140
  console.log(` Invitation ID: ${sanitizeDisplay(invitation.invitationId)}`);
@@ -51502,20 +52160,16 @@ async function runInvite(emailArg, options) {
51502
52160
  outputInvitation(result.body, output);
51503
52161
  }
51504
52162
  function createOrgInviteCommand() {
51505
- return new Command("invite").description("Invite someone to the active organization by email").argument("<email>", "Email address to invite").option(
51506
- "-r, --role <role>",
51507
- `Role to grant: ${MEMBER_ROLE_SLUGS.join(", ")}`,
51508
- DEFAULT_INVITE_ROLE
51509
- ).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
52163
+ return new Command("invite").description("Invite someone to the active organization by email").argument("<email>", "Email address to invite").option("-r, --role <role>", `Role to grant: ${ROLE_CHOICES}`, DEFAULT_INVITE_ROLE).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
51510
52164
  "after",
51511
52165
  `
51512
52166
  Sends the same invitation email as the dashboard's Settings > Members page.
51513
- Requires an organization admin or analyst signed in with \`tracecli auth login\`;
51514
- API keys are rejected. Only admins can invite someone as an admin.
52167
+ Requires an organization admin signed in with \`tracecli auth login\`;
52168
+ API keys are rejected.
51515
52169
 
51516
52170
  Examples:
51517
52171
  tracecli org invite dev@acme.com
51518
- tracecli org invite sec@acme.com --role analyst
52172
+ tracecli org invite sec@acme.com --role manager
51519
52173
  tracecli org invite cto@acme.com --role admin --output json`
51520
52174
  ).action(async (email3, options) => {
51521
52175
  await runInvite(email3, options);
@@ -52842,7 +53496,7 @@ function extractCommandTree(cmd) {
52842
53496
  description: o2.description,
52843
53497
  takesValue: o2.required || o2.optional
52844
53498
  }));
52845
- const subcommands = cmd.commands.filter((c84) => !c84._hidden).map((c84) => extractCommandTree(c84));
53499
+ const subcommands = cmd.commands.filter((c86) => !c86._hidden).map((c86) => extractCommandTree(c86));
52846
53500
  return {
52847
53501
  name: cmd.name(),
52848
53502
  description: cmd.description(),
@@ -52908,7 +53562,7 @@ function generateBashCompletion(tree, binName) {
52908
53562
  }
52909
53563
  function collectBashCases(tree, prefix) {
52910
53564
  const cases = /* @__PURE__ */ new Map();
52911
- const subcommandNames = tree.subcommands.map((c84) => c84.name);
53565
+ const subcommandNames = tree.subcommands.map((c86) => c86.name);
52912
53566
  const optionNames = tree.options.flatMap((o2) => o2.short ? [o2.long, o2.short] : [o2.long]);
52913
53567
  const extraOptions = prefix === "" ? ["--help", "--version"] : ["--help"];
52914
53568
  const allOptions = [.../* @__PURE__ */ new Set([...optionNames, ...extraOptions])];
@@ -53214,17 +53868,17 @@ function validateInboxLabel(label) {
53214
53868
  function buildCreateInboxBody(label) {
53215
53869
  return { label };
53216
53870
  }
53871
+ function forbiddenMessage(verb, needsEntitlement) {
53872
+ const where = needsEntitlement ? " on a pentest-enabled organization" : "";
53873
+ return `Only an organization admin or Manager (or Trace staff)${where} can ${verb}.`;
53874
+ }
53217
53875
  function failWriteOp2(action, status, body, notFoundLabel) {
53218
53876
  const { message, errorCode } = readErrorFields(body);
53219
53877
  if (status === UNAUTHORIZED_STATUS2) {
53220
53878
  exitAuthFailed();
53221
53879
  }
53222
53880
  if (status === 403) {
53223
- console.error(
53224
- colorError(
53225
- `Only an organization admin (or Trace staff) on a pentest-enabled organization can ${action} inboxes.`
53226
- )
53227
- );
53881
+ console.error(colorError(forbiddenMessage(`${action} inboxes`, true)));
53228
53882
  process.exit(1);
53229
53883
  }
53230
53884
  if (status === 404) {
@@ -53276,7 +53930,7 @@ function failReadOp2(action, status, body, notFoundLabel) {
53276
53930
  exitAuthFailed();
53277
53931
  }
53278
53932
  if (status === 403) {
53279
- console.error(colorError("You don't have access to view inboxes in this organization."));
53933
+ console.error(colorError(forbiddenMessage(action, action !== "list inboxes")));
53280
53934
  process.exit(1);
53281
53935
  }
53282
53936
  if (status === 404) {
@@ -53323,9 +53977,9 @@ function buildInboxesTable(inboxes) {
53323
53977
  address: sanitizeDisplay(inbox.address),
53324
53978
  label: sanitizeDisplay(inbox.label)
53325
53979
  }));
53326
- const addressWidth = Math.max(7, ...cells.map((c84) => c84.address.length));
53980
+ const addressWidth = Math.max(7, ...cells.map((c86) => c86.address.length));
53327
53981
  const header = `${"ADDRESS".padEnd(addressWidth)} LABEL`;
53328
- const rows = cells.map((c84) => `${c84.address.padEnd(addressWidth)} ${c84.label}`);
53982
+ const rows = cells.map((c86) => `${c86.address.padEnd(addressWidth)} ${c86.label}`);
53329
53983
  return { header, rows };
53330
53984
  }
53331
53985
  function formatInboxQuota(quota) {
@@ -53349,14 +54003,14 @@ function buildInboxEmailsTable(messages) {
53349
54003
  subject: sanitizeDisplay(message.subject ?? ""),
53350
54004
  unread: message.unread ? "yes" : "no"
53351
54005
  }));
53352
- const idWidth = Math.max(2, ...cells.map((c84) => c84.id.length));
53353
- const receivedWidth = Math.max(8, ...cells.map((c84) => c84.received.length));
53354
- const fromWidth = Math.max(4, ...cells.map((c84) => c84.from.length));
53355
- const toWidth = Math.max(2, ...cells.map((c84) => c84.to.length));
53356
- const subjectWidth = Math.max(7, ...cells.map((c84) => c84.subject.length));
54006
+ const idWidth = Math.max(2, ...cells.map((c86) => c86.id.length));
54007
+ const receivedWidth = Math.max(8, ...cells.map((c86) => c86.received.length));
54008
+ const fromWidth = Math.max(4, ...cells.map((c86) => c86.from.length));
54009
+ const toWidth = Math.max(2, ...cells.map((c86) => c86.to.length));
54010
+ const subjectWidth = Math.max(7, ...cells.map((c86) => c86.subject.length));
53357
54011
  const header = `${"ID".padEnd(idWidth)} ${"RECEIVED".padEnd(receivedWidth)} ${"FROM".padEnd(fromWidth)} ${"TO".padEnd(toWidth)} ${"SUBJECT".padEnd(subjectWidth)} UNREAD`;
53358
54012
  const rows = cells.map(
53359
- (c84) => `${c84.id.padEnd(idWidth)} ${c84.received.padEnd(receivedWidth)} ${c84.from.padEnd(fromWidth)} ${c84.to.padEnd(toWidth)} ${c84.subject.padEnd(subjectWidth)} ${c84.unread}`
54013
+ (c86) => `${c86.id.padEnd(idWidth)} ${c86.received.padEnd(receivedWidth)} ${c86.from.padEnd(fromWidth)} ${c86.to.padEnd(toWidth)} ${c86.subject.padEnd(subjectWidth)} ${c86.unread}`
53360
54014
  );
53361
54015
  return { header, rows };
53362
54016
  }
@@ -54183,16 +54837,16 @@ function printCredentialsTsv(creds) {
54183
54837
  }
54184
54838
  }
54185
54839
  function buildCredentialsTable(creds) {
54186
- const cells = creds.map((c84) => ({
54187
- id: c84.credentialId,
54188
- label: sanitizeDisplay(c84.label),
54189
- type: c84.credentialType
54840
+ const cells = creds.map((c86) => ({
54841
+ id: c86.credentialId,
54842
+ label: sanitizeDisplay(c86.label),
54843
+ type: c86.credentialType
54190
54844
  }));
54191
- const idWidth = Math.max(2, ...cells.map((c84) => c84.id.length));
54192
- const labelWidth = Math.max(5, ...cells.map((c84) => c84.label.length));
54845
+ const idWidth = Math.max(2, ...cells.map((c86) => c86.id.length));
54846
+ const labelWidth = Math.max(5, ...cells.map((c86) => c86.label.length));
54193
54847
  const header = `${"ID".padEnd(idWidth)} ${"LABEL".padEnd(labelWidth)} TYPE`;
54194
54848
  const rows = cells.map(
54195
- (c84) => `${c84.id.padEnd(idWidth)} ${c84.label.padEnd(labelWidth)} ${c84.type}`
54849
+ (c86) => `${c86.id.padEnd(idWidth)} ${c86.label.padEnd(labelWidth)} ${c86.type}`
54196
54850
  );
54197
54851
  return { header, rows };
54198
54852
  }
@@ -54695,7 +55349,7 @@ async function runDelete3(credentialId, options) {
54695
55349
  }
54696
55350
  console.log(colorSuccess(`Deleted credential ${credentialId}`));
54697
55351
  }
54698
- function failLinkOp(op, status, body, notFoundLabel) {
55352
+ function failLinkOp2(op, status, body, notFoundLabel) {
54699
55353
  const { message, errorCode } = readErrorFields(body);
54700
55354
  if (status === UNAUTHORIZED_STATUS2) {
54701
55355
  exitAuthFailed();
@@ -54802,13 +55456,13 @@ function buildCredentialLinksTable(links) {
54802
55456
  source: sourceDisplay(link.source),
54803
55457
  via: link.environmentCredentialSourceId ? "link-all" : ""
54804
55458
  }));
54805
- const idWidth = Math.max("LINK ID".length, ...cells.map((c84) => c84.id.length));
54806
- const labelWidth = Math.max("LABEL".length, ...cells.map((c84) => c84.label.length));
54807
- const typeWidth = Math.max("TYPE".length, ...cells.map((c84) => c84.type.length));
54808
- const sourceWidth = Math.max("SOURCE".length, ...cells.map((c84) => c84.source.length));
55459
+ const idWidth = Math.max("LINK ID".length, ...cells.map((c86) => c86.id.length));
55460
+ const labelWidth = Math.max("LABEL".length, ...cells.map((c86) => c86.label.length));
55461
+ const typeWidth = Math.max("TYPE".length, ...cells.map((c86) => c86.type.length));
55462
+ const sourceWidth = Math.max("SOURCE".length, ...cells.map((c86) => c86.source.length));
54809
55463
  const header = `${"LINK ID".padEnd(idWidth)} ${"LABEL".padEnd(labelWidth)} ${"TYPE".padEnd(typeWidth)} ${"SOURCE".padEnd(sourceWidth)} VIA`;
54810
55464
  const rows = cells.map(
54811
- (c84) => `${c84.id.padEnd(idWidth)} ${c84.label.padEnd(labelWidth)} ${c84.type.padEnd(typeWidth)} ${c84.source.padEnd(sourceWidth)} ${c84.via}`.trimEnd()
55465
+ (c86) => `${c86.id.padEnd(idWidth)} ${c86.label.padEnd(labelWidth)} ${c86.type.padEnd(typeWidth)} ${c86.source.padEnd(sourceWidth)} ${c86.via}`.trimEnd()
54812
55466
  );
54813
55467
  return { header, rows };
54814
55468
  }
@@ -54862,17 +55516,17 @@ function buildLinkableCredentialsTable(creds) {
54862
55516
  }),
54863
55517
  linked: cred.alreadyLinked ? "linked" : ""
54864
55518
  }));
54865
- const idWidth = Math.max("ID".length, ...cells.map((c84) => c84.id.length));
54866
- const labelWidth = Math.max("LABEL".length, ...cells.map((c84) => c84.label.length));
54867
- const typeWidth = Math.max("TYPE".length, ...cells.map((c84) => c84.type.length));
54868
- const sourceWidth = Math.max("SOURCE".length, ...cells.map((c84) => c84.source.length));
55519
+ const idWidth = Math.max("ID".length, ...cells.map((c86) => c86.id.length));
55520
+ const labelWidth = Math.max("LABEL".length, ...cells.map((c86) => c86.label.length));
55521
+ const typeWidth = Math.max("TYPE".length, ...cells.map((c86) => c86.type.length));
55522
+ const sourceWidth = Math.max("SOURCE".length, ...cells.map((c86) => c86.source.length));
54869
55523
  const header = `${"ID".padEnd(idWidth)} ${"LABEL".padEnd(labelWidth)} ${"TYPE".padEnd(typeWidth)} ${"SOURCE".padEnd(sourceWidth)} STATUS`;
54870
55524
  const rows = cells.map(
54871
- (c84) => `${c84.id.padEnd(idWidth)} ${c84.label.padEnd(labelWidth)} ${c84.type.padEnd(typeWidth)} ${c84.source.padEnd(sourceWidth)} ${c84.linked}`.trimEnd()
55525
+ (c86) => `${c86.id.padEnd(idWidth)} ${c86.label.padEnd(labelWidth)} ${c86.type.padEnd(typeWidth)} ${c86.source.padEnd(sourceWidth)} ${c86.linked}`.trimEnd()
54872
55526
  );
54873
55527
  return { header, rows };
54874
55528
  }
54875
- async function runLink(credentialId, options) {
55529
+ async function runLink2(credentialId, options) {
54876
55530
  const output = parseOutput(options.output);
54877
55531
  requireEnvId(options.env);
54878
55532
  requireCredId(credentialId);
@@ -54884,7 +55538,7 @@ async function runLink(credentialId, options) {
54884
55538
  })
54885
55539
  );
54886
55540
  if (result.status !== CREATED_STATUS) {
54887
- failLinkOp("link", result.status, result.body, credentialId);
55541
+ failLinkOp2("link", result.status, result.body, credentialId);
54888
55542
  }
54889
55543
  if (output === "table") {
54890
55544
  console.log(
@@ -54895,7 +55549,7 @@ async function runLink(credentialId, options) {
54895
55549
  }
54896
55550
  outputCredentialLink(result.body, output);
54897
55551
  }
54898
- async function runUnlink(credentialLinkId, options) {
55552
+ async function runUnlink2(credentialLinkId, options) {
54899
55553
  requireEnvId(options.env);
54900
55554
  requireLinkId(credentialLinkId);
54901
55555
  const confirmed = await confirmAction(
@@ -54916,7 +55570,7 @@ async function runUnlink(credentialLinkId, options) {
54916
55570
  if (result.status === 409 && readErrorFields(result.body).errorCode === "CREDENTIAL_LINKED_BY_RULE") {
54917
55571
  await failLinkedByRule(organizationId, options.env, result.body);
54918
55572
  }
54919
- failLinkOp("unlink", result.status, result.body, credentialLinkId);
55573
+ failLinkOp2("unlink", result.status, result.body, credentialLinkId);
54920
55574
  }
54921
55575
  console.log(colorSuccess(`Unlinked credential link ${credentialLinkId}`));
54922
55576
  }
@@ -55064,12 +55718,12 @@ function buildLinkableEnvironmentsTable(envs) {
55064
55718
  count: String(env2.credentialCount),
55065
55719
  linked: env2.alreadyLinked ? "linked" : ""
55066
55720
  }));
55067
- const idWidth = Math.max("ENVIRONMENT ID".length, ...cells.map((c84) => c84.id.length));
55068
- const nameWidth = Math.max("ENVIRONMENT".length, ...cells.map((c84) => c84.name.length));
55721
+ const idWidth = Math.max("ENVIRONMENT ID".length, ...cells.map((c86) => c86.id.length));
55722
+ const nameWidth = Math.max("ENVIRONMENT".length, ...cells.map((c86) => c86.name.length));
55069
55723
  const countWidth = "CREDENTIALS".length;
55070
55724
  const header = `${"ENVIRONMENT ID".padEnd(idWidth)} ${"ENVIRONMENT".padEnd(nameWidth)} ${"CREDENTIALS".padEnd(countWidth)} STATUS`;
55071
55725
  const rows = cells.map(
55072
- (c84) => `${c84.id.padEnd(idWidth)} ${c84.name.padEnd(nameWidth)} ${c84.count.padEnd(countWidth)} ${c84.linked}`.trimEnd()
55726
+ (c86) => `${c86.id.padEnd(idWidth)} ${c86.name.padEnd(nameWidth)} ${c86.count.padEnd(countWidth)} ${c86.linked}`.trimEnd()
55073
55727
  );
55074
55728
  return { header, rows };
55075
55729
  }
@@ -55128,7 +55782,7 @@ async function runLinkAll(sourceEnvironmentId, options) {
55128
55782
  })
55129
55783
  );
55130
55784
  if (result.status !== CREATED_STATUS) {
55131
- failLinkOp("link all", result.status, result.body, sourceEnvironmentId);
55785
+ failLinkOp2("link all", result.status, result.body, sourceEnvironmentId);
55132
55786
  }
55133
55787
  const rule = result.body;
55134
55788
  if (output === "json") {
@@ -55193,7 +55847,7 @@ async function runUnlinkAll(sourceEnvironmentId, options) {
55193
55847
  })
55194
55848
  );
55195
55849
  if (result.status !== NO_CONTENT_STATUS) {
55196
- failLinkOp("unlink all", result.status, result.body, rule.environmentCredentialSourceId);
55850
+ failLinkOp2("unlink all", result.status, result.body, rule.environmentCredentialSourceId);
55197
55851
  }
55198
55852
  console.log(
55199
55853
  colorSuccess(
@@ -55315,7 +55969,7 @@ left \u2014 if the current window is nearly over, the API waits for the next one
55315
55969
  await runMfaCode(credentialId, options);
55316
55970
  });
55317
55971
  }
55318
- function createLinkCommand() {
55972
+ function createLinkCommand2() {
55319
55973
  return new Command("link").description("Link another application's credential into an environment").argument("<credentialId>", "UUID of the credential to link (owned by another environment)").requiredOption("--env <environmentId>", "Environment UUID to link it into").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
55320
55974
  "after",
55321
55975
  `
@@ -55332,10 +55986,10 @@ Examples:
55332
55986
  tracecli credential linkable --env <envId>
55333
55987
  tracecli credential link <credentialId> --env <envId>`
55334
55988
  ).action(async (credentialId, options) => {
55335
- await runLink(credentialId, options);
55989
+ await runLink2(credentialId, options);
55336
55990
  });
55337
55991
  }
55338
- function createUnlinkCommand() {
55992
+ function createUnlinkCommand2() {
55339
55993
  return new Command("unlink").description("Remove a credential link from an environment (the source credential is kept)").argument("<credentialLinkId>", "Credential link UUID (the LINK ID from `credential links`)").requiredOption("--env <environmentId>", "Environment UUID the credential is linked into").option("-y, --yes", "Skip the confirmation prompt (required in non-interactive shells)").addHelpText(
55340
55994
  "after",
55341
55995
  `
@@ -55344,7 +55998,7 @@ the environment's own credentials. A credential whose whole environment is
55344
55998
  linked here (VIA link-all in \`credential links\`) stays until that is removed
55345
55999
  with \`credential unlink-all\`.`
55346
56000
  ).action(async (credentialLinkId, options) => {
55347
- await runUnlink(credentialLinkId, options);
56001
+ await runUnlink2(credentialLinkId, options);
55348
56002
  });
55349
56003
  }
55350
56004
  function createLinksCommand() {
@@ -55408,8 +56062,8 @@ function createCredentialCommand() {
55408
56062
  credential.addCommand(createSetMfaCommand());
55409
56063
  credential.addCommand(createClearMfaCommand());
55410
56064
  credential.addCommand(createMfaCodeCommand());
55411
- credential.addCommand(createLinkCommand());
55412
- credential.addCommand(createUnlinkCommand());
56065
+ credential.addCommand(createLinkCommand2());
56066
+ credential.addCommand(createUnlinkCommand2());
55413
56067
  credential.addCommand(createLinkAllCommand());
55414
56068
  credential.addCommand(createUnlinkAllCommand());
55415
56069
  credential.addCommand(createLinksCommand());
@@ -55629,14 +56283,14 @@ function buildEnvironmentTable(envs, leading) {
55629
56283
  url: e.primaryUrl != null ? sanitizeDisplay(e.primaryUrl) : "\u2014"
55630
56284
  }));
55631
56285
  const leadingWidths = leading.map(
55632
- (column, i2) => Math.max(column.header.length, ...cells.map((c84) => c84.leading[i2]?.length ?? 0))
56286
+ (column, i2) => Math.max(column.header.length, ...cells.map((c86) => c86.leading[i2]?.length ?? 0))
55633
56287
  );
55634
- const nameWidth = Math.max(4, ...cells.map((c84) => c84.name.length));
56288
+ const nameWidth = Math.max(4, ...cells.map((c86) => c86.name.length));
55635
56289
  const padLeading = (values) => values.map((v, i2) => v.padEnd(leadingWidths[i2] ?? 0)).join(" ");
55636
56290
  return {
55637
- header: `${padLeading(leading.map((c84) => c84.header))} ${"NAME".padEnd(nameWidth)} PROD URL`,
56291
+ header: `${padLeading(leading.map((c86) => c86.header))} ${"NAME".padEnd(nameWidth)} PROD URL`,
55638
56292
  rows: cells.map(
55639
- (c84) => `${padLeading(c84.leading)} ${c84.name.padEnd(nameWidth)} ${c84.prod.padEnd(4)} ${c84.url}`
56293
+ (c86) => `${padLeading(c86.leading)} ${c86.name.padEnd(nameWidth)} ${c86.prod.padEnd(4)} ${c86.url}`
55640
56294
  )
55641
56295
  };
55642
56296
  }
@@ -59655,7 +60309,7 @@ function resolveQuestionnaireMode(options) {
59655
60309
  ];
59656
60310
  const chosen = exclusive.filter((entry) => entry.set);
59657
60311
  if (chosen.length > 1) {
59658
- console.error(colorError(`Pass only one of ${chosen.map((c84) => c84.flag).join(" / ")}.`));
60312
+ console.error(colorError(`Pass only one of ${chosen.map((c86) => c86.flag).join(" / ")}.`));
59659
60313
  process.exit(1);
59660
60314
  }
59661
60315
  const only = chosen[0];
@@ -60889,13 +61543,13 @@ function buildUploadsTable(uploads) {
60889
61543
  size: formatArchiveBytes(upload.sizeBytes),
60890
61544
  id: upload.codeUploadId
60891
61545
  }));
60892
- const nameWidth = Math.max(4, ...cells.map((c84) => c84.name.length));
60893
- const kindWidth = Math.max(4, ...cells.map((c84) => c84.kind.length));
60894
- const statusWidth = Math.max(6, ...cells.map((c84) => c84.status.length));
60895
- const sizeWidth = Math.max(4, ...cells.map((c84) => c84.size.length));
61546
+ const nameWidth = Math.max(4, ...cells.map((c86) => c86.name.length));
61547
+ const kindWidth = Math.max(4, ...cells.map((c86) => c86.kind.length));
61548
+ const statusWidth = Math.max(6, ...cells.map((c86) => c86.status.length));
61549
+ const sizeWidth = Math.max(4, ...cells.map((c86) => c86.size.length));
60896
61550
  const header = `${"NAME".padEnd(nameWidth)} ${"KIND".padEnd(kindWidth)} ${"STATUS".padEnd(statusWidth)} ${"SIZE".padEnd(sizeWidth)} ID`;
60897
61551
  const rows = cells.map(
60898
- (c84) => `${c84.name.padEnd(nameWidth)} ${c84.kind.padEnd(kindWidth)} ${c84.status.padEnd(statusWidth)} ${c84.size.padEnd(sizeWidth)} ${c84.id}`
61552
+ (c86) => `${c86.name.padEnd(nameWidth)} ${c86.kind.padEnd(kindWidth)} ${c86.status.padEnd(statusWidth)} ${c86.size.padEnd(sizeWidth)} ${c86.id}`
60899
61553
  );
60900
61554
  return { header, rows };
60901
61555
  }
@@ -61382,7 +62036,7 @@ async function runDelete5(codeUploadIdArg, options) {
61382
62036
  }
61383
62037
  console.log(colorSuccess(`Deleted upload ${codeUploadId}`));
61384
62038
  }
61385
- async function runLink2(options) {
62039
+ async function runLink3(options) {
61386
62040
  const output = parseOutput(options.output);
61387
62041
  const applicationId = requireUuid(options.app, "--app");
61388
62042
  const codeUploadId = requireUuid(options.upload, "--upload");
@@ -61514,7 +62168,7 @@ function createDeleteCommand5() {
61514
62168
  await runDelete5(codeUploadId, options);
61515
62169
  });
61516
62170
  }
61517
- function createLinkCommand2() {
62171
+ function createLinkCommand3() {
61518
62172
  return new Command("link").description("Link a ready source upload to an application").requiredOption("--app <applicationId>", "Application UUID").requiredOption("--upload <codeUploadId>", "Upload UUID (must be a ready source ZIP)").option("--path <repositoryPath>", "Path within the archive").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
61519
62173
  "after",
61520
62174
  `
@@ -61524,7 +62178,7 @@ APK and IPA builds attach to an application with \`upload build --app\`.
61524
62178
  Examples:
61525
62179
  tracecli upload link --app <applicationId> --upload <codeUploadId>`
61526
62180
  ).action(async (options) => {
61527
- await runLink2(options);
62181
+ await runLink3(options);
61528
62182
  });
61529
62183
  }
61530
62184
  function createUploadCommand(runtime = {}) {
@@ -61538,7 +62192,7 @@ function createUploadCommand(runtime = {}) {
61538
62192
  upload.addCommand(createResumeCommand(resolved));
61539
62193
  upload.addCommand(createWaitCommand(resolved));
61540
62194
  upload.addCommand(createDeleteCommand5());
61541
- upload.addCommand(createLinkCommand2());
62195
+ upload.addCommand(createLinkCommand3());
61542
62196
  return upload;
61543
62197
  }
61544
62198