@kinosec/cli 0.3.3 → 0.4.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/cli.js CHANGED
@@ -7750,6 +7750,27 @@ function parseApiError(body, status) {
7750
7750
  requestId: typeof b.request_id === "string" ? b.request_id : "unknown"
7751
7751
  });
7752
7752
  }
7753
+ var CredentialsResource = class {
7754
+ constructor(api) {
7755
+ this.api = api;
7756
+ }
7757
+ api;
7758
+ async set(assetId, params) {
7759
+ return this.api.put(`v1/assets/${assetId}/credentials`, { json: params }).json();
7760
+ }
7761
+ async get(assetId) {
7762
+ return this.api.get(`v1/assets/${assetId}/credentials`).json();
7763
+ }
7764
+ async remove(assetId) {
7765
+ return this.api.delete(`v1/assets/${assetId}/credentials`).json();
7766
+ }
7767
+ async setTarget(assetId, params) {
7768
+ return this.api.put(`v1/assets/${assetId}/credentials/target`, { json: params }).json();
7769
+ }
7770
+ async removeTarget(assetId) {
7771
+ return this.api.delete(`v1/assets/${assetId}/credentials/target`).json();
7772
+ }
7773
+ };
7753
7774
  var IDEMPOTENT_EXACT_PATHS = ["/v1/scans", "/v1/tokens"];
7754
7775
  var IDEMPOTENT_SUFFIXES = ["/cancel", "/retest"];
7755
7776
  function needsIdempotencyKey(method, path) {
@@ -7831,8 +7852,10 @@ var KinoSecClient = class {
7831
7852
  var AssetsResource = class {
7832
7853
  constructor(api) {
7833
7854
  this.api = api;
7855
+ this.credentials = new CredentialsResource(api);
7834
7856
  }
7835
7857
  api;
7858
+ credentials;
7836
7859
  async list(params = {}) {
7837
7860
  return this.api.get("v1/assets", { searchParams: buildSearchParams(params) }).json();
7838
7861
  }
@@ -10912,10 +10935,15 @@ Examples:
10912
10935
  asset = await client.assets.lookup(domain);
10913
10936
  } catch (err) {
10914
10937
  if (err instanceof ApiError && err.status === 404) {
10915
- console.error(`No asset found for '${domain}'. Run kinosec asset list to see your assets.`);
10916
- process.exit(1);
10938
+ asset = await client.assets.create({
10939
+ asset_type: "domain",
10940
+ asset_value: domain,
10941
+ verification_method: "dns"
10942
+ });
10943
+ console.error(`Asset created for ${domain}.`);
10944
+ } else {
10945
+ throw err;
10917
10946
  }
10918
- throw err;
10919
10947
  }
10920
10948
  targetDisplay = domain;
10921
10949
  params = { asset_id: asset.id, scan_mode: options.mode };
@@ -11099,7 +11127,402 @@ Timeout: pentest still running after ${options.timeout}s.`);
11099
11127
  }
11100
11128
 
11101
11129
  // src/commands/asset.ts
11130
+ var import_picocolors7 = __toESM(require_picocolors(), 1);
11131
+
11132
+ // src/commands/asset-auth.ts
11102
11133
  var import_picocolors6 = __toESM(require_picocolors(), 1);
11134
+
11135
+ // src/lib/resolve-asset.ts
11136
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-/i;
11137
+ async function resolveAsset(client, identifier) {
11138
+ try {
11139
+ if (UUID_RE.test(identifier)) {
11140
+ return await client.assets.get(identifier);
11141
+ }
11142
+ return await client.assets.lookup(identifier);
11143
+ } catch (error) {
11144
+ if (error instanceof ApiError && error.status === 404) {
11145
+ throw new ApiError({
11146
+ status: 404,
11147
+ code: error.code,
11148
+ detail: `Asset "${identifier}" not found. Create it with:
11149
+ kinosec asset create --type domain --value ${identifier} --verify-method dns
11150
+ or use pentest which auto-creates the asset:
11151
+ kinosec pentest -t ${identifier}`,
11152
+ requestId: error.requestId
11153
+ });
11154
+ }
11155
+ throw error;
11156
+ }
11157
+ }
11158
+
11159
+ // src/lib/prompt.ts
11160
+ import { createInterface as createInterface2 } from "readline";
11161
+ async function promptMasked(label) {
11162
+ if (!isTTY() || !process.stdin.isTTY) {
11163
+ console.error(`Cannot prompt for ${label} in non-interactive mode. Use flags instead.`);
11164
+ process.exit(2);
11165
+ }
11166
+ process.stderr.write(`${label}: `);
11167
+ return new Promise((resolve, reject) => {
11168
+ const chars = [];
11169
+ process.stdin.setRawMode(true);
11170
+ process.stdin.resume();
11171
+ process.stdin.setEncoding("utf-8");
11172
+ const onData = (chunk) => {
11173
+ for (const ch of chunk) {
11174
+ if (ch === "\r" || ch === "\n") {
11175
+ process.stdin.setRawMode(false);
11176
+ process.stdin.pause();
11177
+ process.stdin.removeListener("data", onData);
11178
+ process.stderr.write("\n");
11179
+ resolve(chars.join(""));
11180
+ return;
11181
+ } else if (ch === "") {
11182
+ process.stdin.setRawMode(false);
11183
+ process.stdin.pause();
11184
+ process.stdin.removeListener("data", onData);
11185
+ process.stderr.write("\n");
11186
+ reject(new Error("Cancelled"));
11187
+ return;
11188
+ } else if (ch === "\x7F" || ch === "\b") {
11189
+ if (chars.length > 0) {
11190
+ chars.pop();
11191
+ process.stderr.write("\b \b");
11192
+ }
11193
+ } else if (ch >= " ") {
11194
+ chars.push(ch);
11195
+ process.stderr.write("*");
11196
+ }
11197
+ }
11198
+ };
11199
+ process.stdin.on("data", onData);
11200
+ });
11201
+ }
11202
+ async function promptText(label) {
11203
+ if (!isTTY() || !process.stdin.isTTY) {
11204
+ console.error(`Cannot prompt for ${label} in non-interactive mode. Use flags instead.`);
11205
+ process.exit(2);
11206
+ }
11207
+ const rl = createInterface2({ input: process.stdin, output: process.stderr });
11208
+ const answer = await new Promise((resolve) => {
11209
+ rl.question(`${label}: `, resolve);
11210
+ });
11211
+ rl.close();
11212
+ return answer;
11213
+ }
11214
+ async function promptSelect(message, options) {
11215
+ if (!isTTY() || !process.stdin.isTTY) {
11216
+ console.error("Cannot show interactive menu in non-interactive mode. Use flags instead.");
11217
+ process.exit(2);
11218
+ }
11219
+ console.error(`
11220
+ ${message}`);
11221
+ for (let i = 0; i < options.length; i++) {
11222
+ console.error(` ${i + 1}. ${options[i].label} \u2014 ${options[i].description}`);
11223
+ }
11224
+ const rl = createInterface2({ input: process.stdin, output: process.stderr });
11225
+ const answer = await new Promise((resolve) => {
11226
+ rl.question("> ", resolve);
11227
+ });
11228
+ rl.close();
11229
+ const index = parseInt(answer, 10) - 1;
11230
+ if (isNaN(index) || index < 0 || index >= options.length) {
11231
+ console.error("Invalid selection.");
11232
+ process.exit(2);
11233
+ }
11234
+ return options[index].value;
11235
+ }
11236
+
11237
+ // src/commands/asset-auth.ts
11238
+ var VALID_AUTH_TYPES = ["bearer", "basic", "apikey", "session", "cookie"];
11239
+ var AUTH_TYPE_OPTIONS = [
11240
+ { value: "bearer", label: "Bearer Token", description: "Authorization header with token" },
11241
+ { value: "apikey", label: "API Key", description: "Custom header (e.g. X-API-Key)" },
11242
+ { value: "basic", label: "Basic Auth", description: "Username + password" },
11243
+ { value: "session", label: "Session Login", description: "Replays login form POST" },
11244
+ { value: "cookie", label: "Cookie / Session", description: "Inject browser cookies" }
11245
+ ];
11246
+ async function collectCredentialsInteractive(authType) {
11247
+ const params = { auth_type: authType, credentials: {} };
11248
+ switch (authType) {
11249
+ case "bearer": {
11250
+ params.credentials = { token: await promptMasked("Bearer token") };
11251
+ break;
11252
+ }
11253
+ case "basic": {
11254
+ const username = await promptText("Username");
11255
+ const password = await promptMasked("Password");
11256
+ params.credentials = { username, password };
11257
+ break;
11258
+ }
11259
+ case "apikey": {
11260
+ const key = await promptMasked("API key");
11261
+ const headerName = await promptText("Header name (e.g. X-API-Key)");
11262
+ params.credentials = { key };
11263
+ params.auth_header_name = headerName;
11264
+ break;
11265
+ }
11266
+ case "session": {
11267
+ const username = await promptText("Username or email");
11268
+ const password = await promptMasked("Password");
11269
+ const endpoint = await promptText("Login endpoint URL");
11270
+ params.credentials = { email: username, password };
11271
+ params.auth_endpoint_url = endpoint;
11272
+ break;
11273
+ }
11274
+ case "cookie": {
11275
+ params.credentials = { cookie: await promptMasked("Cookie string") };
11276
+ break;
11277
+ }
11278
+ }
11279
+ return params;
11280
+ }
11281
+ function collectCredentialsFromFlags(options) {
11282
+ const authType = options.type;
11283
+ const params = { auth_type: authType, credentials: {} };
11284
+ switch (authType) {
11285
+ case "bearer": {
11286
+ if (!options.bearerToken) {
11287
+ console.error("--bearer-token is required for bearer auth type.");
11288
+ process.exit(2);
11289
+ }
11290
+ params.credentials = { token: options.bearerToken };
11291
+ break;
11292
+ }
11293
+ case "basic": {
11294
+ if (!options.username || !options.password) {
11295
+ console.error("--username and --password are required for basic auth type.");
11296
+ process.exit(2);
11297
+ }
11298
+ params.credentials = { username: options.username, password: options.password };
11299
+ break;
11300
+ }
11301
+ case "apikey": {
11302
+ if (!options.key || !options.headerName) {
11303
+ console.error("--key and --header-name are required for apikey auth type.");
11304
+ process.exit(2);
11305
+ }
11306
+ params.credentials = { key: options.key };
11307
+ params.auth_header_name = options.headerName;
11308
+ break;
11309
+ }
11310
+ case "session": {
11311
+ if (!options.username || !options.password || !options.authEndpoint) {
11312
+ console.error("--username, --password, and --auth-endpoint are required for session auth type.");
11313
+ process.exit(2);
11314
+ }
11315
+ params.credentials = { email: options.username, password: options.password };
11316
+ params.auth_endpoint_url = options.authEndpoint;
11317
+ break;
11318
+ }
11319
+ case "cookie": {
11320
+ if (!options.cookie) {
11321
+ console.error("--cookie is required for cookie auth type.");
11322
+ process.exit(2);
11323
+ }
11324
+ params.credentials = { cookie: options.cookie };
11325
+ break;
11326
+ }
11327
+ }
11328
+ if (options.context) {
11329
+ params.context_text = options.context;
11330
+ }
11331
+ return params;
11332
+ }
11333
+ function registerAssetAuthCommand(assetCmd) {
11334
+ const auth = assetCmd.command("auth").description("Manage asset authentication credentials");
11335
+ auth.command("set").description("Configure authentication credentials for an asset").argument("<asset>", "Asset domain name or UUID").option("--type <type>", "Auth type: bearer, basic, apikey, session, cookie").option("--bearer-token <value>", "Bearer token (bearer type)").option("--username <value>", "Username or email (basic, session types)").option("--password <value>", "Password (basic, session types)").option("--key <value>", "API key value (apikey type)").option("--header-name <name>", "Custom header name (apikey type, e.g. X-API-Key)").option("--cookie <value>", "Cookie string (cookie type)").option("--auth-endpoint <url>", "Login endpoint URL (session type)").option("--context <text>", "Optional notes about the auth configuration").addHelpText("after", `
11336
+ Examples:
11337
+ $ kinosec asset auth set example.com # interactive
11338
+ $ kinosec asset auth set example.com --type bearer --bearer-token "$TOKEN"
11339
+ $ kinosec asset auth set example.com --type basic --username admin --password "$PASS"
11340
+ $ kinosec asset auth set example.com --type apikey --key "$KEY" --header-name "X-API-Key"
11341
+ $ kinosec asset auth set example.com --type session --username admin@example.com --password "$PASS" --auth-endpoint "https://example.com/api/login"
11342
+ $ kinosec asset auth set example.com --type cookie --cookie "session_id=abc123"
11343
+
11344
+ Security: Pass credentials via environment variables to avoid shell history exposure.`).action(async (assetIdentifier, options) => {
11345
+ try {
11346
+ const opts = auth.parent.parent.opts();
11347
+ const { token, apiUrl } = resolveToken(opts);
11348
+ const client = new KinoSecClient({ apiUrl, token });
11349
+ const asset = await resolveAsset(client, assetIdentifier);
11350
+ let params;
11351
+ if (options.type) {
11352
+ if (!VALID_AUTH_TYPES.includes(options.type)) {
11353
+ console.error(`Invalid auth type "${options.type}". Must be: ${VALID_AUTH_TYPES.join(", ")}`);
11354
+ process.exit(2);
11355
+ }
11356
+ params = collectCredentialsFromFlags(options);
11357
+ } else {
11358
+ const authType = await promptSelect("Authentication type:", AUTH_TYPE_OPTIONS);
11359
+ params = await collectCredentialsInteractive(authType);
11360
+ if (options.context) {
11361
+ params.context_text = options.context;
11362
+ }
11363
+ }
11364
+ const result = await client.assets.credentials.set(asset.id, params);
11365
+ if (opts.json || opts.output === "json") {
11366
+ printJson({ ...result, asset: asset.asset_value });
11367
+ return;
11368
+ }
11369
+ printSuccess(`Credentials saved for ${asset.asset_value} (${result.auth_type})`);
11370
+ } catch (error) {
11371
+ handleError(error);
11372
+ }
11373
+ });
11374
+ auth.command("show").description("Show authentication configuration for an asset").argument("<asset>", "Asset domain name or UUID").addHelpText("after", `
11375
+ Examples:
11376
+ $ kinosec asset auth show example.com
11377
+ $ kinosec asset auth show example.com --json`).action(async (assetIdentifier) => {
11378
+ try {
11379
+ const opts = auth.parent.parent.opts();
11380
+ const { token, apiUrl } = resolveToken(opts);
11381
+ const client = new KinoSecClient({ apiUrl, token });
11382
+ const asset = await resolveAsset(client, assetIdentifier);
11383
+ const creds = await client.assets.credentials.get(asset.id);
11384
+ if (opts.json || opts.output === "json") {
11385
+ printJson({ asset: asset.asset_value, ...creds });
11386
+ return;
11387
+ }
11388
+ if (!creds.has_credentials) {
11389
+ console.log(`Asset: ${asset.asset_value}`);
11390
+ console.log(`Auth Type: ${import_picocolors6.default.dim("(none)")}`);
11391
+ console.log(`Has Credentials: no`);
11392
+ return;
11393
+ }
11394
+ console.log(`Asset: ${asset.asset_value}`);
11395
+ console.log(`Auth Type: ${creds.auth_type}`);
11396
+ console.log(`Has Credentials: yes`);
11397
+ if (creds.auth_header_name) {
11398
+ console.log(`Header Name: ${creds.auth_header_name}`);
11399
+ }
11400
+ if (creds.auth_endpoint_url) {
11401
+ console.log(`Auth Endpoint: ${creds.auth_endpoint_url}`);
11402
+ }
11403
+ if (creds.context_text) {
11404
+ console.log(`Notes: ${creds.context_text}`);
11405
+ }
11406
+ if (creds.target_account) {
11407
+ const ta = creds.target_account;
11408
+ const hasAny = ta.has_username || ta.has_cookie || ta.has_bearer_token || ta.has_apikey;
11409
+ if (hasAny) {
11410
+ const detail = ta.has_username ? "username" : ta.has_bearer_token ? "bearer token" : ta.has_cookie ? "cookie" : "API key";
11411
+ console.log(`Target Account: ${import_picocolors6.default.green("configured")} (${detail})`);
11412
+ } else {
11413
+ console.log(`Target Account: ${import_picocolors6.default.dim("not configured")}`);
11414
+ }
11415
+ }
11416
+ } catch (error) {
11417
+ handleError(error);
11418
+ }
11419
+ });
11420
+ auth.command("remove").description("Remove all credentials for an asset").argument("<asset>", "Asset domain name or UUID").option("-y, --yes", "Skip confirmation prompt").addHelpText("after", `
11421
+ Examples:
11422
+ $ kinosec asset auth remove example.com
11423
+ $ kinosec asset auth remove example.com --yes`).action(async (assetIdentifier, options) => {
11424
+ try {
11425
+ const opts = auth.parent.parent.opts();
11426
+ const { token, apiUrl } = resolveToken(opts);
11427
+ const client = new KinoSecClient({ apiUrl, token });
11428
+ const asset = await resolveAsset(client, assetIdentifier);
11429
+ await confirmDestructive(`Remove all credentials for ${asset.asset_value}?`, Boolean(options.yes));
11430
+ await client.assets.credentials.remove(asset.id);
11431
+ if (opts.json || opts.output === "json") {
11432
+ printJson({ deleted: true, asset: asset.asset_value });
11433
+ return;
11434
+ }
11435
+ printSuccess(`Credentials removed for ${asset.asset_value}`);
11436
+ } catch (error) {
11437
+ handleError(error);
11438
+ }
11439
+ });
11440
+ auth.command("set-target").description("Configure IDOR target account credentials").argument("<asset>", "Asset domain name or UUID").option("--target-username <value>", "Target account username or email").option("--target-password <value>", "Target account password").option("--target-totp-secret <value>", "Target account TOTP secret").option("--target-token <value>", "Target bearer token").option("--target-cookie <value>", "Target cookie string").option("--target-key <value>", "Target API key").addHelpText("after", `
11441
+ Examples:
11442
+ $ kinosec asset auth set-target example.com # interactive
11443
+ $ kinosec asset auth set-target example.com --target-username victim@example.com --target-password "$PASS"
11444
+ $ kinosec asset auth set-target example.com --target-token "$VICTIM_TOKEN"
11445
+ $ kinosec asset auth set-target example.com --target-cookie "session_id=victim_abc"`).action(async (assetIdentifier, options) => {
11446
+ try {
11447
+ const opts = auth.parent.parent.opts();
11448
+ const { token, apiUrl } = resolveToken(opts);
11449
+ const client = new KinoSecClient({ apiUrl, token });
11450
+ const asset = await resolveAsset(client, assetIdentifier);
11451
+ const creds = await client.assets.credentials.get(asset.id);
11452
+ if (!creds.has_credentials || !creds.auth_type) {
11453
+ console.error(`No primary credentials configured for ${asset.asset_value}. Run 'kinosec asset auth set' first.`);
11454
+ process.exit(2);
11455
+ }
11456
+ const isTokenBased = creds.auth_type === "bearer" || creds.auth_type === "apikey" || creds.auth_type === "cookie";
11457
+ const hasAnyFlag = options.targetUsername || options.targetPassword || options.targetTotpSecret || options.targetToken || options.targetCookie || options.targetKey;
11458
+ let targetParams;
11459
+ if (hasAnyFlag) {
11460
+ targetParams = {
11461
+ username: options.targetUsername,
11462
+ password: options.targetPassword,
11463
+ totp_secret: options.targetTotpSecret,
11464
+ bearer_token: options.targetToken,
11465
+ cookie: options.targetCookie,
11466
+ apikey: options.targetKey
11467
+ };
11468
+ } else {
11469
+ console.error(`
11470
+ Primary auth type: ${creds.auth_type}
11471
+ `);
11472
+ if (isTokenBased) {
11473
+ if (creds.auth_type === "bearer") {
11474
+ const targetToken = await promptMasked("Target bearer token");
11475
+ targetParams = { bearer_token: targetToken };
11476
+ } else if (creds.auth_type === "cookie") {
11477
+ const targetCookie = await promptMasked("Target cookie string");
11478
+ targetParams = { cookie: targetCookie };
11479
+ } else {
11480
+ const targetKey = await promptMasked("Target API key");
11481
+ targetParams = { apikey: targetKey };
11482
+ }
11483
+ } else {
11484
+ const username = await promptText("Target account username");
11485
+ const password = await promptMasked("Target account password");
11486
+ targetParams = { username, password };
11487
+ const totp = await promptText("Target TOTP secret (optional, Enter to skip)");
11488
+ if (totp) {
11489
+ targetParams.totp_secret = totp;
11490
+ }
11491
+ }
11492
+ }
11493
+ await client.assets.credentials.setTarget(asset.id, targetParams);
11494
+ if (opts.json || opts.output === "json") {
11495
+ printJson({ saved: true, asset: asset.asset_value });
11496
+ return;
11497
+ }
11498
+ printSuccess(`Target account saved for ${asset.asset_value} (IDOR testing)`);
11499
+ } catch (error) {
11500
+ handleError(error);
11501
+ }
11502
+ });
11503
+ auth.command("remove-target").description("Remove target account credentials (keeps primary credentials)").argument("<asset>", "Asset domain name or UUID").option("-y, --yes", "Skip confirmation prompt").addHelpText("after", `
11504
+ Examples:
11505
+ $ kinosec asset auth remove-target example.com
11506
+ $ kinosec asset auth remove-target example.com --yes`).action(async (assetIdentifier, options) => {
11507
+ try {
11508
+ const opts = auth.parent.parent.opts();
11509
+ const { token, apiUrl } = resolveToken(opts);
11510
+ const client = new KinoSecClient({ apiUrl, token });
11511
+ const asset = await resolveAsset(client, assetIdentifier);
11512
+ await confirmDestructive(`Remove target account for ${asset.asset_value}?`, Boolean(options.yes));
11513
+ await client.assets.credentials.removeTarget(asset.id);
11514
+ if (opts.json || opts.output === "json") {
11515
+ printJson({ deleted: true, asset: asset.asset_value });
11516
+ return;
11517
+ }
11518
+ printSuccess(`Target account removed for ${asset.asset_value}`);
11519
+ } catch (error) {
11520
+ handleError(error);
11521
+ }
11522
+ });
11523
+ }
11524
+
11525
+ // src/commands/asset.ts
11103
11526
  function registerAssetCommand(program3) {
11104
11527
  const asset = program3.command("asset").description("Manage assets");
11105
11528
  asset.command("list").description("List assets").option("--limit <n>", "Max results per page", "20").option("--cursor <cursor>", "Pagination cursor").option("--search <term>", "Filter by asset value (substring match)").option("--status <status>", "Filter by status (verified, unverified)").option("--type <type>", "Filter by type (domain, subdomain, ip)").addHelpText("after", `
@@ -11138,7 +11561,7 @@ Examples:
11138
11561
  ])
11139
11562
  );
11140
11563
  if (result.next_cursor) {
11141
- console.log(import_picocolors6.default.dim(`
11564
+ console.log(import_picocolors7.default.dim(`
11142
11565
  More results available. Use --cursor ${result.next_cursor}`));
11143
11566
  }
11144
11567
  } catch (error) {
@@ -11246,10 +11669,11 @@ Examples:
11246
11669
  handleError(error);
11247
11670
  }
11248
11671
  });
11672
+ registerAssetAuthCommand(asset);
11249
11673
  }
11250
11674
 
11251
11675
  // src/commands/finding.ts
11252
- var import_picocolors7 = __toESM(require_picocolors(), 1);
11676
+ var import_picocolors8 = __toESM(require_picocolors(), 1);
11253
11677
  function formatPoc(poc) {
11254
11678
  if (poc == null) return null;
11255
11679
  if (typeof poc === "string") return poc.trim() || null;
@@ -11290,7 +11714,7 @@ Examples:
11290
11714
  ])
11291
11715
  );
11292
11716
  if (result.next_cursor) {
11293
- console.log(import_picocolors7.default.dim(`
11717
+ console.log(import_picocolors8.default.dim(`
11294
11718
  More results available. Use --cursor ${result.next_cursor}`));
11295
11719
  }
11296
11720
  } catch (error) {
@@ -11378,7 +11802,7 @@ Examples:
11378
11802
  }
11379
11803
 
11380
11804
  // src/commands/report.ts
11381
- var import_picocolors8 = __toESM(require_picocolors(), 1);
11805
+ var import_picocolors9 = __toESM(require_picocolors(), 1);
11382
11806
  function renderMarkdown(data) {
11383
11807
  const { scan, findings } = data;
11384
11808
  const lines = [];
@@ -11455,7 +11879,7 @@ Examples:
11455
11879
  ])
11456
11880
  );
11457
11881
  if (result.next_cursor) {
11458
- console.log(import_picocolors8.default.dim(`
11882
+ console.log(import_picocolors9.default.dim(`
11459
11883
  More results available. Use --cursor ${result.next_cursor}`));
11460
11884
  }
11461
11885
  } catch (error) {
@@ -11526,7 +11950,7 @@ Examples:
11526
11950
  }
11527
11951
 
11528
11952
  // src/commands/token.ts
11529
- var import_picocolors9 = __toESM(require_picocolors(), 1);
11953
+ var import_picocolors10 = __toESM(require_picocolors(), 1);
11530
11954
  function registerTokenCommand(program3) {
11531
11955
  const token = program3.command("token").description("Manage API tokens");
11532
11956
  token.command("list").description("List API tokens").option("--limit <n>", "Max results per page", "20").option("--cursor <cursor>", "Pagination cursor").addHelpText("after", `
@@ -11561,7 +11985,7 @@ Examples:
11561
11985
  ])
11562
11986
  );
11563
11987
  if (result.next_cursor) {
11564
- console.log(import_picocolors9.default.dim(`
11988
+ console.log(import_picocolors10.default.dim(`
11565
11989
  More results available. Use --cursor ${result.next_cursor}`));
11566
11990
  }
11567
11991
  } catch (error) {
@@ -11588,7 +12012,7 @@ Examples:
11588
12012
  }
11589
12013
  printSuccess(`Token created: ${result.name}`);
11590
12014
  console.log("");
11591
- console.log(import_picocolors9.default.bold(" Token: ") + result.token);
12015
+ console.log(import_picocolors10.default.bold(" Token: ") + result.token);
11592
12016
  console.log("");
11593
12017
  printWarning("Save this token \u2014 it will not be shown again.");
11594
12018
  console.log(` ID: ${result.id}`);
@@ -11621,7 +12045,7 @@ Examples:
11621
12045
 
11622
12046
  // src/cli.ts
11623
12047
  var program2 = new Command();
11624
- program2.name("kinosec").description("KinoSec CLI \u2014 run pentests from your terminal").version("0.3.3", "-v, --version").option("--token <pat>", "API token (overrides KINOSEC_TOKEN and config)").option("--api-url <url>", "API base URL (overrides config)").option("--output <format>", "Output format: text or json", "text").option("--json", "Shorthand for --output json").option("--no-color", "Disable colors");
12048
+ program2.name("kinosec").description("KinoSec CLI \u2014 run pentests from your terminal").version("0.4.0", "-v, --version").option("--token <pat>", "API token (overrides KINOSEC_TOKEN and config)").option("--api-url <url>", "API base URL (overrides config)").option("--output <format>", "Output format: text or json", "text").option("--json", "Shorthand for --output json").option("--no-color", "Disable colors");
11625
12049
  registerAuthCommand(program2);
11626
12050
  registerConfigCommand(program2);
11627
12051
  registerMeCommand(program2);
@@ -11630,7 +12054,7 @@ registerAssetCommand(program2);
11630
12054
  registerFindingCommand(program2);
11631
12055
  registerReportCommand(program2);
11632
12056
  registerTokenCommand(program2);
11633
- program2.parseAsync(process.argv).then(() => checkForUpdate("0.3.3")).catch(handleError);
12057
+ program2.parseAsync(process.argv).then(() => checkForUpdate("0.4.0")).catch(handleError);
11634
12058
  /*! Bundled license information:
11635
12059
 
11636
12060
  ky/distribution/index.js: