juggernaut-bedrock 4.0.4 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +44 -7
  2. package/index.js +54 -0
  3. package/package.json +21 -7
  4. package/install.js +0 -157
package/README.md CHANGED
@@ -50,7 +50,7 @@ juggernaut apply --auth=iam
50
50
  That one command:
51
51
 
52
52
  1. **Writes** Bedrock config to `~/.claude/settings.json` (or project scope)
53
- 2. **Sets** model IDs, region, effort level, and `CLAUDE_CODE_USE_BEDROCK=1` — only after credentials check out
53
+ 2. **Sets** model IDs, region, effort level, permission mode, and `CLAUDE_CODE_USE_BEDROCK=1` — only after credentials check out
54
54
  3. **Installs** a `claude` launcher shim that reads your token from the keychain and execs the real binary
55
55
 
56
56
  No `.bashrc` edits. No copying API keys into env vars. No "why isn't Bedrock routing?" at 2am.
@@ -87,14 +87,51 @@ No `.bashrc` edits. No copying API keys into env vars. No "why isn't Bedrock rou
87
87
 
88
88
  ## Default models
89
89
 
90
- | Tier | Model |
91
- |------|-------|
92
- | **Primary** | Claude Sonnet 4.6 |
93
- | **Opus** | Claude Opus 4.7 |
94
- | **Fast** | Claude Haiku 4.5 |
90
+ | Tier | Model | Global inference profile |
91
+ |------|-------|--------------------------|
92
+ | **Primary** | Claude Sonnet 4.6 | `global.anthropic.claude-sonnet-4-6` |
93
+ | **Opus** | Claude Opus 4.8 | `global.anthropic.claude-opus-4-8` |
94
+ | **Fast** | Claude Haiku 4.5 | `global.anthropic.claude-haiku-4-5-20251001-v1:0` |
95
95
 
96
96
  Override any tier: `juggernaut apply --auth=iam --model=global.anthropic.claude-sonnet-4-6`
97
97
 
98
+ ## Effort levels
99
+
100
+ Controls adaptive thinking depth. Valid values: `low | medium | high | xhigh | max`
101
+
102
+ ```bash
103
+ juggernaut apply --auth=iam --effort=max
104
+ ```
105
+
106
+ Default: `xhigh`. On Opus 4.8/4.7, effort level controls adaptive thinking depth — manual thinking mode is not supported.
107
+
108
+ ## Permission modes
109
+
110
+ Controls how Claude Code handles tool-use approvals:
111
+
112
+ | Mode | Behavior |
113
+ |------|----------|
114
+ | `default` | Prompts for each action |
115
+ | `acceptEdits` | Auto-approves file edits |
116
+ | `plan` | Propose only, no execution |
117
+ | `auto` | Agentic safety classifier |
118
+ | `bypassPermissions` | Skip all prompts (containers/VMs only) |
119
+
120
+ ```bash
121
+ juggernaut apply --auth=iam --mode=auto
122
+ ```
123
+
124
+ Auto mode on Bedrock requires `CLAUDE_CODE_ENABLE_AUTO_MODE=1` — Juggernaut sets this automatically.
125
+
126
+ ## Other options
127
+
128
+ ```bash
129
+ --always-thinking # enable extended thinking by default (alwaysThinkingEnabled)
130
+ --service-tier=flex # Bedrock service tier: default | flex | priority
131
+ --opusplan # route /plan to Opus 4.8, execution to Sonnet 4.6
132
+ --scope=project # write to ./.claude/settings.json instead of ~/.claude/
133
+ ```
134
+
98
135
  ## Troubleshooting
99
136
 
100
137
  Stuck? Start here:
@@ -115,4 +152,4 @@ Full docs, IAM policy, migration guide, and platform notes:
115
152
 
116
153
  MIT — see [LICENSE](https://github.com/jpvelasco/juggernaut/blob/main/LICENSE).
117
154
 
118
- Juggernaut is an independent tool, not affiliated with Anthropic or Amazon Web Services.
155
+ Juggernaut is an independent tool, not affiliated with Anthropic or Amazon Web Services.
package/index.js ADDED
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ const path = require("path");
4
+ const { spawnSync } = require("child_process");
5
+
6
+ const PACKAGES_DIR = path.join(__dirname, "packages");
7
+
8
+ const PLATFORM_MAP = {
9
+ "linux-x64": "juggernaut-bedrock-linux-x64",
10
+ "linux-arm64": "juggernaut-bedrock-linux-arm64",
11
+ "darwin-x64": "juggernaut-bedrock-darwin-x64",
12
+ "darwin-arm64": "juggernaut-bedrock-darwin-arm64",
13
+ "win32-x64": "juggernaut-bedrock-win32-x64",
14
+ };
15
+
16
+ function getPlatformPackage(platform, arch) {
17
+ return PLATFORM_MAP[`${platform}-${arch}`] || null;
18
+ }
19
+
20
+ function getBinaryPath(pkgName, platform) {
21
+ const binaryName = platform === "win32" ? "juggernaut.exe" : "juggernaut";
22
+ return path.join(PACKAGES_DIR, pkgName, "bin", binaryName);
23
+ }
24
+
25
+ if (require.main === module) {
26
+ const pkg = getPlatformPackage(process.platform, process.arch);
27
+ if (!pkg) {
28
+ process.stderr.write(
29
+ `juggernaut-bedrock: unsupported platform ${process.platform}/${process.arch}\n` +
30
+ `Please file an issue: https://github.com/jpvelasco/juggernaut/issues\n`
31
+ );
32
+ process.exit(1);
33
+ }
34
+
35
+ const bin = getBinaryPath(pkg, process.platform);
36
+ const fs = require("fs");
37
+ if (!fs.existsSync(bin)) {
38
+ process.stderr.write(
39
+ `juggernaut-bedrock: binary not found at ${bin}\n` +
40
+ `Try reinstalling: npm install -g juggernaut-bedrock\n` +
41
+ `If the problem persists, file an issue: https://github.com/jpvelasco/juggernaut/issues\n`
42
+ );
43
+ process.exit(1);
44
+ }
45
+
46
+ // nosemgrep: javascript.lang.security.detect-child-process
47
+ const result = spawnSync(bin, process.argv.slice(2), {
48
+ stdio: "inherit",
49
+ env: process.env,
50
+ });
51
+ process.exit(result.status ?? 1);
52
+ }
53
+
54
+ module.exports = { getPlatformPackage, getBinaryPath };
package/package.json CHANGED
@@ -1,15 +1,29 @@
1
1
  {
2
2
  "name": "juggernaut-bedrock",
3
- "version": "4.0.4",
3
+ "version": "4.2.1",
4
4
  "description": "Route Claude Code through Amazon Bedrock in one command — IAM, SSO, or API key. Cross-platform CLI for GenAI developers.",
5
5
  "bin": {
6
- "juggernaut": "./bin/juggernaut"
6
+ "juggernaut": "./index.js"
7
7
  },
8
8
  "scripts": {
9
- "postinstall": "node install.js"
9
+ "test": "node --test index.test.js"
10
10
  },
11
- "os": ["darwin", "linux", "win32"],
12
- "cpu": ["x64", "arm64"],
11
+ "optionalDependencies": {
12
+ "juggernaut-bedrock-linux-x64": "4.2.1",
13
+ "juggernaut-bedrock-linux-arm64": "4.2.1",
14
+ "juggernaut-bedrock-darwin-x64": "4.2.1",
15
+ "juggernaut-bedrock-darwin-arm64": "4.2.1",
16
+ "juggernaut-bedrock-win32-x64": "4.2.1"
17
+ },
18
+ "os": [
19
+ "darwin",
20
+ "linux",
21
+ "win32"
22
+ ],
23
+ "cpu": [
24
+ "x64",
25
+ "arm64"
26
+ ],
13
27
  "keywords": [
14
28
  "claude",
15
29
  "claude-code",
@@ -29,10 +43,10 @@
29
43
  "license": "MIT",
30
44
  "repository": {
31
45
  "type": "git",
32
- "url": "https://github.com/jpvelasco/juggernaut"
46
+ "url": "git+https://github.com/jpvelasco/juggernaut.git"
33
47
  },
34
48
  "bugs": {
35
49
  "url": "https://github.com/jpvelasco/juggernaut/issues"
36
50
  },
37
51
  "homepage": "https://github.com/jpvelasco/juggernaut#readme"
38
- }
52
+ }
package/install.js DELETED
@@ -1,157 +0,0 @@
1
- "use strict";
2
-
3
- const https = require("https");
4
- const fs = require("fs");
5
- const path = require("path");
6
- const os = require("os");
7
- const crypto = require("crypto");
8
- const { execFile, execFileSync } = require("child_process");
9
- const { promisify } = require("util");
10
-
11
- const execFileAsync = promisify(execFile);
12
-
13
- const REPO = "jpvelasco/juggernaut";
14
- const BIN_DIR = path.join(__dirname, "bin");
15
- const ALLOWED_HOSTS = new Set([
16
- "github.com",
17
- "api.github.com",
18
- "release-assets.githubusercontent.com"
19
- ]);
20
-
21
- function getPlatform() {
22
- const osMap = { darwin: "darwin", linux: "linux", win32: "windows" };
23
- const archMap = { x64: "amd64", arm64: "arm64" };
24
- const p = osMap[process.platform];
25
- const a = archMap[process.arch];
26
- if (!p || !a) {
27
- throw new Error(`Unsupported platform: ${process.platform}/${process.arch}`);
28
- }
29
- return { os: p, arch: a, platform: `${p}_${a}` };
30
- }
31
-
32
- function httpsGetBuffer(url) {
33
- const parsed = new URL(url);
34
- if (!ALLOWED_HOSTS.has(parsed.hostname)) {
35
- throw new Error(`URL host not allowed: ${parsed.hostname}`);
36
- }
37
- return new Promise((resolve, reject) => {
38
- https
39
- .get(url, { headers: { "User-Agent": "juggernaut-npm-installer/1.0" } }, (res) => {
40
- if (res.statusCode === 301 || res.statusCode === 302) {
41
- const location = res.headers.location;
42
- const redirectParsed = new URL(location);
43
- if (!ALLOWED_HOSTS.has(redirectParsed.hostname)) {
44
- reject(new Error(`Redirect host not allowed: ${redirectParsed.hostname}`));
45
- return;
46
- }
47
- httpsGetBuffer(location).then(resolve).catch(reject);
48
- return;
49
- }
50
- const chunks = [];
51
- res.on("data", (chunk) => chunks.push(chunk));
52
- res.on("end", () => resolve(Buffer.concat(chunks)));
53
- res.on("error", reject);
54
- })
55
- .on("error", reject);
56
- });
57
- }
58
-
59
- async function getLatestVersion() {
60
- const data = await httpsGetBuffer(`https://api.github.com/repos/${REPO}/releases/latest`);
61
- const release = JSON.parse(data.toString());
62
- return release.tag_name.replace(/^v/, "");
63
- }
64
-
65
- function pickArchive(platform, checksumsText) {
66
- const tarArchive = `juggernaut_${platform}.tar.gz`;
67
- if (checksumsText.includes(tarArchive)) {
68
- return { name: tarArchive, kind: "tar.gz" };
69
- }
70
- const zipArchive = `juggernaut_${platform}.zip`;
71
- if (process.platform === "win32" && checksumsText.includes(zipArchive)) {
72
- return { name: zipArchive, kind: "zip" };
73
- }
74
- throw new Error(`No supported archive found in release checksums for ${platform}`);
75
- }
76
-
77
- function extractTarGz(archiveBuf) {
78
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "juggernaut-install-"));
79
- const archivePath = path.join(tmpDir, "archive.tar.gz");
80
- try {
81
- fs.writeFileSync(archivePath, archiveBuf);
82
- fs.mkdirSync(BIN_DIR, { recursive: true });
83
- try {
84
- execFileSync("tar", ["-xzf", archivePath, "-C", BIN_DIR], { stdio: "pipe" });
85
- } catch (err) {
86
- if (err.code === "ENOENT") {
87
- throw new Error(
88
- "tar not found on PATH. On Windows, use Windows 10 version 1803 or later (includes tar.exe)."
89
- );
90
- }
91
- const detail = err.stderr ? err.stderr.toString().trim() : err.message;
92
- throw new Error(`tar extraction failed: ${detail}`);
93
- }
94
- if (process.platform !== "win32") {
95
- const binPath = path.join(BIN_DIR, "juggernaut");
96
- if (fs.existsSync(binPath)) {
97
- fs.chmodSync(binPath, 0o700);
98
- }
99
- }
100
- } finally {
101
- fs.rmSync(tmpDir, { recursive: true, force: true });
102
- }
103
- }
104
-
105
- async function extractZip(archiveBuf) {
106
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "juggernaut-install-"));
107
- const archivePath = path.join(tmpDir, "archive.zip");
108
- try {
109
- fs.writeFileSync(archivePath, archiveBuf);
110
- fs.mkdirSync(BIN_DIR, { recursive: true });
111
- const script = [
112
- "$ErrorActionPreference = 'Stop'",
113
- `Expand-Archive -LiteralPath '${archivePath.replace(/'/g, "''")}' -DestinationPath '${BIN_DIR.replace(/'/g, "''")}' -Force`
114
- ].join("; ");
115
- await execFileAsync(
116
- "powershell",
117
- ["-NoProfile", "-NonInteractive", "-Command", script],
118
- { stdio: "pipe" }
119
- );
120
- } finally {
121
- fs.rmSync(tmpDir, { recursive: true, force: true });
122
- }
123
- }
124
-
125
- async function main() {
126
- const { platform } = getPlatform();
127
- const version = await getLatestVersion();
128
- const baseUrl = `https://github.com/${REPO}/releases/download/v${version}`;
129
- const checksumsBuf = await httpsGetBuffer(`${baseUrl}/checksums.txt`);
130
- const checksums = checksumsBuf.toString("utf8");
131
- const { name: archive, kind } = pickArchive(platform, checksums);
132
-
133
- console.log(`Downloading Juggernaut v${version} (${platform})...`);
134
- const archiveBuf = await httpsGetBuffer(`${baseUrl}/${archive}`);
135
-
136
- const line = checksums.split("\n").find((l) => l.includes(archive));
137
- if (!line) throw new Error(`Checksum not found for ${archive}`);
138
- const expected = line.trim().split(/\s+/)[0].toLowerCase();
139
- const actual = crypto.createHash("sha256").update(archiveBuf).digest("hex").toLowerCase();
140
- if (actual !== expected) {
141
- throw new Error(`Checksum mismatch for ${archive}\n expected: ${expected}\n got: ${actual}`);
142
- }
143
-
144
- if (kind === "zip") {
145
- await extractZip(archiveBuf);
146
- } else {
147
- extractTarGz(archiveBuf);
148
- }
149
-
150
- console.log(`Juggernaut v${version} installed successfully.`);
151
- console.log(`Run: juggernaut apply`);
152
- }
153
-
154
- main().catch((err) => {
155
- console.error("Installation failed:", err.message);
156
- process.exit(1);
157
- });