@keygraph/shannon 1.1.0 → 1.3.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.mjs +64 -14
- package/infra/compose.yml +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -165,6 +165,7 @@ function spawnWorker(opts) {
|
|
|
165
165
|
args.push("-v", `${path.join(workspacePath, "deliverables")}:${opts.repo.containerPath}/.shannon/deliverables`);
|
|
166
166
|
args.push("-v", `${path.join(workspacePath, "scratchpad")}:${opts.repo.containerPath}/.shannon/scratchpad`);
|
|
167
167
|
args.push("-v", `${path.join(workspacePath, ".playwright-cli")}:${opts.repo.containerPath}/.shannon/.playwright-cli`);
|
|
168
|
+
args.push("-v", `${path.join(workspacePath, ".playwright")}:${opts.repo.containerPath}/.playwright`);
|
|
168
169
|
if (opts.promptsDir) args.push("-v", `${opts.promptsDir}:/app/apps/worker/prompts:ro`);
|
|
169
170
|
if (opts.config) args.push("-v", `${opts.config.hostPath}:${opts.config.containerPath}:ro`);
|
|
170
171
|
if (opts.outputDir) args.push("-v", `${opts.outputDir}:/app/output`);
|
|
@@ -421,7 +422,9 @@ async function setup() {
|
|
|
421
422
|
]
|
|
422
423
|
});
|
|
423
424
|
if (p.isCancel(provider)) return cancelAndExit();
|
|
424
|
-
|
|
425
|
+
const config = await setupProvider(provider);
|
|
426
|
+
await maybePromptAdaptiveThinking(config);
|
|
427
|
+
saveConfig(config);
|
|
425
428
|
const configPath = path.join(SHANNON_HOME$1, "config.toml");
|
|
426
429
|
p.log.success(`Configuration saved to ${configPath}`);
|
|
427
430
|
p.outro("Run `npx @keygraph/shannon start` to begin a scan.");
|
|
@@ -450,7 +453,7 @@ async function setupAnthropic() {
|
|
|
450
453
|
if (authMethod === "oauth") config.anthropic = { oauth_token: await promptSecret("Enter your OAuth token") };
|
|
451
454
|
else config.anthropic = { api_key: await promptSecret("Enter your Anthropic API key") };
|
|
452
455
|
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-
|
|
456
|
+
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
457
|
initialValue: false
|
|
455
458
|
});
|
|
456
459
|
if (p.isCancel(customizeModels)) return cancelAndExit();
|
|
@@ -469,7 +472,7 @@ async function setupAnthropic() {
|
|
|
469
472
|
if (p.isCancel(medium)) return cancelAndExit();
|
|
470
473
|
const large = await p.text({
|
|
471
474
|
message: "Large model ID",
|
|
472
|
-
initialValue: "claude-opus-4-
|
|
475
|
+
initialValue: "claude-opus-4-7",
|
|
473
476
|
validate: required("Large model ID is required")
|
|
474
477
|
});
|
|
475
478
|
if (p.isCancel(large)) return cancelAndExit();
|
|
@@ -500,7 +503,7 @@ async function setupCustomBaseUrl() {
|
|
|
500
503
|
auth_token: await promptSecret("Enter the auth token for the custom endpoint")
|
|
501
504
|
} };
|
|
502
505
|
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-
|
|
506
|
+
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
507
|
initialValue: false
|
|
505
508
|
});
|
|
506
509
|
if (p.isCancel(customizeModels)) return cancelAndExit();
|
|
@@ -519,7 +522,7 @@ async function setupCustomBaseUrl() {
|
|
|
519
522
|
if (p.isCancel(medium)) return cancelAndExit();
|
|
520
523
|
const large = await p.text({
|
|
521
524
|
message: "Large model ID",
|
|
522
|
-
initialValue: "claude-opus-4-
|
|
525
|
+
initialValue: "claude-opus-4-7",
|
|
523
526
|
validate: required("Large model ID is required")
|
|
524
527
|
});
|
|
525
528
|
if (p.isCancel(large)) return cancelAndExit();
|
|
@@ -553,7 +556,7 @@ async function setupBedrock() {
|
|
|
553
556
|
if (p.isCancel(medium)) return cancelAndExit();
|
|
554
557
|
const large = await p.text({
|
|
555
558
|
message: "Large model ID",
|
|
556
|
-
placeholder: "us.anthropic.claude-opus-4-
|
|
559
|
+
placeholder: "us.anthropic.claude-opus-4-7",
|
|
557
560
|
validate: required("Large model ID is required")
|
|
558
561
|
});
|
|
559
562
|
if (p.isCancel(large)) return cancelAndExit();
|
|
@@ -610,7 +613,7 @@ async function setupVertex() {
|
|
|
610
613
|
}),
|
|
611
614
|
large: () => p.text({
|
|
612
615
|
message: "Large model ID",
|
|
613
|
-
placeholder: "claude-opus-4-
|
|
616
|
+
placeholder: "claude-opus-4-7",
|
|
614
617
|
validate: required("Large model ID is required")
|
|
615
618
|
})
|
|
616
619
|
});
|
|
@@ -629,6 +632,23 @@ async function setupVertex() {
|
|
|
629
632
|
}
|
|
630
633
|
};
|
|
631
634
|
}
|
|
635
|
+
async function maybePromptAdaptiveThinking(config) {
|
|
636
|
+
const m = config.models;
|
|
637
|
+
if (!(!m || [
|
|
638
|
+
m.small,
|
|
639
|
+
m.medium,
|
|
640
|
+
m.large
|
|
641
|
+
].some((v) => v && /opus-4-[67]/.test(v)))) return;
|
|
642
|
+
const enable = await p.confirm({
|
|
643
|
+
message: "Enable adaptive thinking on Opus 4.6/4.7? Claude decides when and how deeply to reason.",
|
|
644
|
+
initialValue: true
|
|
645
|
+
});
|
|
646
|
+
if (p.isCancel(enable)) return cancelAndExit();
|
|
647
|
+
config.core = {
|
|
648
|
+
...config.core,
|
|
649
|
+
adaptive_thinking: enable
|
|
650
|
+
};
|
|
651
|
+
}
|
|
632
652
|
async function promptSecret(message) {
|
|
633
653
|
const value = await p.password({
|
|
634
654
|
message,
|
|
@@ -661,6 +681,12 @@ const CONFIG_MAP = [
|
|
|
661
681
|
toml: "core.max_tokens",
|
|
662
682
|
type: "number"
|
|
663
683
|
},
|
|
684
|
+
{
|
|
685
|
+
env: "CLAUDE_ADAPTIVE_THINKING",
|
|
686
|
+
toml: "core.adaptive_thinking",
|
|
687
|
+
type: "boolean",
|
|
688
|
+
boolFormat: "literal"
|
|
689
|
+
},
|
|
664
690
|
{
|
|
665
691
|
env: "ANTHROPIC_API_KEY",
|
|
666
692
|
toml: "anthropic.api_key",
|
|
@@ -732,15 +758,18 @@ const CONFIG_MAP = [
|
|
|
732
758
|
type: "string"
|
|
733
759
|
}
|
|
734
760
|
];
|
|
735
|
-
/** Read a nested TOML value
|
|
736
|
-
function getTomlValue(config,
|
|
737
|
-
const [section, key] =
|
|
761
|
+
/** Read a nested TOML value for a given mapping. */
|
|
762
|
+
function getTomlValue(config, mapping) {
|
|
763
|
+
const [section, key] = mapping.toml.split(".");
|
|
738
764
|
if (!section || !key) return void 0;
|
|
739
765
|
const sectionObj = config[section];
|
|
740
766
|
if (!sectionObj || typeof sectionObj !== "object") return void 0;
|
|
741
767
|
const value = sectionObj[key];
|
|
742
768
|
if (value === void 0 || value === null) return void 0;
|
|
743
|
-
if (typeof value === "boolean")
|
|
769
|
+
if (typeof value === "boolean") {
|
|
770
|
+
if (mapping.boolFormat === "literal") return value ? "true" : "false";
|
|
771
|
+
return value ? "1" : "0";
|
|
772
|
+
}
|
|
744
773
|
return String(value);
|
|
745
774
|
}
|
|
746
775
|
/** Parse the global TOML config file, returning null if it doesn't exist. */
|
|
@@ -897,7 +926,7 @@ function resolveConfig$1() {
|
|
|
897
926
|
}
|
|
898
927
|
for (const mapping of CONFIG_MAP) {
|
|
899
928
|
if (process.env[mapping.env]) continue;
|
|
900
|
-
const value = getTomlValue(toml, mapping
|
|
929
|
+
const value = getTomlValue(toml, mapping);
|
|
901
930
|
if (value) process.env[mapping.env] = value;
|
|
902
931
|
}
|
|
903
932
|
}
|
|
@@ -925,7 +954,8 @@ const FORWARD_VARS = [
|
|
|
925
954
|
"ANTHROPIC_SMALL_MODEL",
|
|
926
955
|
"ANTHROPIC_MEDIUM_MODEL",
|
|
927
956
|
"ANTHROPIC_LARGE_MODEL",
|
|
928
|
-
"CLAUDE_CODE_MAX_OUTPUT_TOKENS"
|
|
957
|
+
"CLAUDE_CODE_MAX_OUTPUT_TOKENS",
|
|
958
|
+
"CLAUDE_ADAPTIVE_THINKING"
|
|
929
959
|
];
|
|
930
960
|
/**
|
|
931
961
|
* Load credentials into process.env.
|
|
@@ -1162,7 +1192,8 @@ async function start(args) {
|
|
|
1162
1192
|
for (const dir of [
|
|
1163
1193
|
"deliverables",
|
|
1164
1194
|
"scratchpad",
|
|
1165
|
-
".playwright-cli"
|
|
1195
|
+
".playwright-cli",
|
|
1196
|
+
".playwright"
|
|
1166
1197
|
]) {
|
|
1167
1198
|
const dirPath = path.join(workspacePath, dir);
|
|
1168
1199
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
@@ -1174,6 +1205,7 @@ async function start(args) {
|
|
|
1174
1205
|
"scratchpad",
|
|
1175
1206
|
".playwright-cli"
|
|
1176
1207
|
]) fs.mkdirSync(path.join(shannonDir, dir), { recursive: true });
|
|
1208
|
+
fs.mkdirSync(path.join(repo.hostPath, ".playwright"), { recursive: true });
|
|
1177
1209
|
const credentialsPath = getCredentialsPath();
|
|
1178
1210
|
const hasCredentials = fs.existsSync(credentialsPath);
|
|
1179
1211
|
if (hasCredentials) process.env.GOOGLE_APPLICATION_CREDENTIALS = "/app/credentials/google-sa-key.json";
|
|
@@ -1386,6 +1418,23 @@ function workspaces(version) {
|
|
|
1386
1418
|
* in the current working directory.
|
|
1387
1419
|
*/
|
|
1388
1420
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
1421
|
+
function blockSudo() {
|
|
1422
|
+
const isSudo = !!process.env.SUDO_USER;
|
|
1423
|
+
const isRoot = process.geteuid?.() === 0;
|
|
1424
|
+
if (!isSudo && !isRoot) return;
|
|
1425
|
+
if (isSudo) {
|
|
1426
|
+
console.error("ERROR: Shannon must not be run with sudo.");
|
|
1427
|
+
console.error("Re-run this command as your normal user.");
|
|
1428
|
+
} else {
|
|
1429
|
+
console.error("ERROR: Shannon must not be run as the root user.");
|
|
1430
|
+
console.error("Switch to a regular user account and re-run this command.");
|
|
1431
|
+
}
|
|
1432
|
+
if (process.platform === "linux") {
|
|
1433
|
+
console.error("Configure Docker to run without sudo first:");
|
|
1434
|
+
console.error("https://docs.docker.com/engine/install/linux-postinstall");
|
|
1435
|
+
}
|
|
1436
|
+
process.exit(1);
|
|
1437
|
+
}
|
|
1389
1438
|
function getVersion() {
|
|
1390
1439
|
try {
|
|
1391
1440
|
const pkgPath = path.join(__dirname, "..", "package.json");
|
|
@@ -1506,6 +1555,7 @@ function parseStartArgs(argv) {
|
|
|
1506
1555
|
...output && { output }
|
|
1507
1556
|
};
|
|
1508
1557
|
}
|
|
1558
|
+
blockSudo();
|
|
1509
1559
|
const args = process.argv.slice(2);
|
|
1510
1560
|
const command = args[0];
|
|
1511
1561
|
switch (command) {
|
package/infra/compose.yml
CHANGED