@keygraph/shannon 1.1.0 → 1.2.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.
Files changed (2) hide show
  1. package/dist/index.mjs +60 -13
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -421,7 +421,9 @@ async function setup() {
421
421
  ]
422
422
  });
423
423
  if (p.isCancel(provider)) return cancelAndExit();
424
- saveConfig(await setupProvider(provider));
424
+ const config = await setupProvider(provider);
425
+ await maybePromptAdaptiveThinking(config);
426
+ saveConfig(config);
425
427
  const configPath = path.join(SHANNON_HOME$1, "config.toml");
426
428
  p.log.success(`Configuration saved to ${configPath}`);
427
429
  p.outro("Run `npx @keygraph/shannon start` to begin a scan.");
@@ -450,7 +452,7 @@ async function setupAnthropic() {
450
452
  if (authMethod === "oauth") config.anthropic = { oauth_token: await promptSecret("Enter your OAuth token") };
451
453
  else config.anthropic = { api_key: await promptSecret("Enter your Anthropic API key") };
452
454
  const customizeModels = await p.confirm({
453
- message: "Do you want to change the default models?\n Small - claude-haiku-4-5-20251001\n Medium - claude-sonnet-4-6\n Large - claude-opus-4-6",
455
+ message: "Do you want to change the default models?\n Small - claude-haiku-4-5-20251001\n Medium - claude-sonnet-4-6\n Large - claude-opus-4-7",
454
456
  initialValue: false
455
457
  });
456
458
  if (p.isCancel(customizeModels)) return cancelAndExit();
@@ -469,7 +471,7 @@ async function setupAnthropic() {
469
471
  if (p.isCancel(medium)) return cancelAndExit();
470
472
  const large = await p.text({
471
473
  message: "Large model ID",
472
- initialValue: "claude-opus-4-6",
474
+ initialValue: "claude-opus-4-7",
473
475
  validate: required("Large model ID is required")
474
476
  });
475
477
  if (p.isCancel(large)) return cancelAndExit();
@@ -500,7 +502,7 @@ async function setupCustomBaseUrl() {
500
502
  auth_token: await promptSecret("Enter the auth token for the custom endpoint")
501
503
  } };
502
504
  const customizeModels = await p.confirm({
503
- message: "Do you want to change the default models?\n Small - claude-haiku-4-5-20251001\n Medium - claude-sonnet-4-6\n Large - claude-opus-4-6",
505
+ message: "Do you want to change the default models?\n Small - claude-haiku-4-5-20251001\n Medium - claude-sonnet-4-6\n Large - claude-opus-4-7",
504
506
  initialValue: false
505
507
  });
506
508
  if (p.isCancel(customizeModels)) return cancelAndExit();
@@ -519,7 +521,7 @@ async function setupCustomBaseUrl() {
519
521
  if (p.isCancel(medium)) return cancelAndExit();
520
522
  const large = await p.text({
521
523
  message: "Large model ID",
522
- initialValue: "claude-opus-4-6",
524
+ initialValue: "claude-opus-4-7",
523
525
  validate: required("Large model ID is required")
524
526
  });
525
527
  if (p.isCancel(large)) return cancelAndExit();
@@ -553,7 +555,7 @@ async function setupBedrock() {
553
555
  if (p.isCancel(medium)) return cancelAndExit();
554
556
  const large = await p.text({
555
557
  message: "Large model ID",
556
- placeholder: "us.anthropic.claude-opus-4-6",
558
+ placeholder: "us.anthropic.claude-opus-4-7",
557
559
  validate: required("Large model ID is required")
558
560
  });
559
561
  if (p.isCancel(large)) return cancelAndExit();
@@ -610,7 +612,7 @@ async function setupVertex() {
610
612
  }),
611
613
  large: () => p.text({
612
614
  message: "Large model ID",
613
- placeholder: "claude-opus-4-6",
615
+ placeholder: "claude-opus-4-7",
614
616
  validate: required("Large model ID is required")
615
617
  })
616
618
  });
@@ -629,6 +631,23 @@ async function setupVertex() {
629
631
  }
630
632
  };
631
633
  }
634
+ async function maybePromptAdaptiveThinking(config) {
635
+ const m = config.models;
636
+ if (!(!m || [
637
+ m.small,
638
+ m.medium,
639
+ m.large
640
+ ].some((v) => v && /opus-4-[67]/.test(v)))) return;
641
+ const enable = await p.confirm({
642
+ message: "Enable adaptive thinking on Opus 4.6/4.7? Claude decides when and how deeply to reason.",
643
+ initialValue: true
644
+ });
645
+ if (p.isCancel(enable)) return cancelAndExit();
646
+ config.core = {
647
+ ...config.core,
648
+ adaptive_thinking: enable
649
+ };
650
+ }
632
651
  async function promptSecret(message) {
633
652
  const value = await p.password({
634
653
  message,
@@ -661,6 +680,12 @@ const CONFIG_MAP = [
661
680
  toml: "core.max_tokens",
662
681
  type: "number"
663
682
  },
683
+ {
684
+ env: "CLAUDE_ADAPTIVE_THINKING",
685
+ toml: "core.adaptive_thinking",
686
+ type: "boolean",
687
+ boolFormat: "literal"
688
+ },
664
689
  {
665
690
  env: "ANTHROPIC_API_KEY",
666
691
  toml: "anthropic.api_key",
@@ -732,15 +757,18 @@ const CONFIG_MAP = [
732
757
  type: "string"
733
758
  }
734
759
  ];
735
- /** Read a nested TOML value by dotted path (e.g. "anthropic.api_key"). */
736
- function getTomlValue(config, path) {
737
- const [section, key] = path.split(".");
760
+ /** Read a nested TOML value for a given mapping. */
761
+ function getTomlValue(config, mapping) {
762
+ const [section, key] = mapping.toml.split(".");
738
763
  if (!section || !key) return void 0;
739
764
  const sectionObj = config[section];
740
765
  if (!sectionObj || typeof sectionObj !== "object") return void 0;
741
766
  const value = sectionObj[key];
742
767
  if (value === void 0 || value === null) return void 0;
743
- if (typeof value === "boolean") return value ? "1" : "0";
768
+ if (typeof value === "boolean") {
769
+ if (mapping.boolFormat === "literal") return value ? "true" : "false";
770
+ return value ? "1" : "0";
771
+ }
744
772
  return String(value);
745
773
  }
746
774
  /** Parse the global TOML config file, returning null if it doesn't exist. */
@@ -897,7 +925,7 @@ function resolveConfig$1() {
897
925
  }
898
926
  for (const mapping of CONFIG_MAP) {
899
927
  if (process.env[mapping.env]) continue;
900
- const value = getTomlValue(toml, mapping.toml);
928
+ const value = getTomlValue(toml, mapping);
901
929
  if (value) process.env[mapping.env] = value;
902
930
  }
903
931
  }
@@ -925,7 +953,8 @@ const FORWARD_VARS = [
925
953
  "ANTHROPIC_SMALL_MODEL",
926
954
  "ANTHROPIC_MEDIUM_MODEL",
927
955
  "ANTHROPIC_LARGE_MODEL",
928
- "CLAUDE_CODE_MAX_OUTPUT_TOKENS"
956
+ "CLAUDE_CODE_MAX_OUTPUT_TOKENS",
957
+ "CLAUDE_ADAPTIVE_THINKING"
929
958
  ];
930
959
  /**
931
960
  * Load credentials into process.env.
@@ -1386,6 +1415,23 @@ function workspaces(version) {
1386
1415
  * in the current working directory.
1387
1416
  */
1388
1417
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
1418
+ function blockSudo() {
1419
+ const isSudo = !!process.env.SUDO_USER;
1420
+ const isRoot = process.geteuid?.() === 0;
1421
+ if (!isSudo && !isRoot) return;
1422
+ if (isSudo) {
1423
+ console.error("ERROR: Shannon must not be run with sudo.");
1424
+ console.error("Re-run this command as your normal user.");
1425
+ } else {
1426
+ console.error("ERROR: Shannon must not be run as the root user.");
1427
+ console.error("Switch to a regular user account and re-run this command.");
1428
+ }
1429
+ if (process.platform === "linux") {
1430
+ console.error("Configure Docker to run without sudo first:");
1431
+ console.error("https://docs.docker.com/engine/install/linux-postinstall");
1432
+ }
1433
+ process.exit(1);
1434
+ }
1389
1435
  function getVersion() {
1390
1436
  try {
1391
1437
  const pkgPath = path.join(__dirname, "..", "package.json");
@@ -1506,6 +1552,7 @@ function parseStartArgs(argv) {
1506
1552
  ...output && { output }
1507
1553
  };
1508
1554
  }
1555
+ blockSudo();
1509
1556
  const args = process.argv.slice(2);
1510
1557
  const command = args[0];
1511
1558
  switch (command) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keygraph/shannon",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Shannon - Autonomous white-box AI pentester for web applications and APIs by Keygraph",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",