juggernaut-bedrock 4.0.4 → 4.1.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/README.md +44 -7
- package/install.js +72 -25
- package/package.json +11 -4
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.
|
|
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/install.js
CHANGED
|
@@ -11,13 +11,47 @@ const { promisify } = require("util");
|
|
|
11
11
|
const execFileAsync = promisify(execFile);
|
|
12
12
|
|
|
13
13
|
const REPO = "jpvelasco/juggernaut";
|
|
14
|
-
const
|
|
14
|
+
const PACKAGE_DIR = __dirname;
|
|
15
|
+
const BIN_DIR = path.join(PACKAGE_DIR, "bin");
|
|
16
|
+
const TMP_PREFIX = path.join(os.tmpdir(), "juggernaut-install-");
|
|
17
|
+
const ARCHIVE_TAR = "archive.tar.gz";
|
|
18
|
+
const ARCHIVE_ZIP = "archive.zip";
|
|
19
|
+
const BIN_NAME = "juggernaut";
|
|
15
20
|
const ALLOWED_HOSTS = new Set([
|
|
16
21
|
"github.com",
|
|
17
22
|
"api.github.com",
|
|
18
23
|
"release-assets.githubusercontent.com"
|
|
19
24
|
]);
|
|
20
25
|
|
|
26
|
+
function joinUnder(base, ...segments) {
|
|
27
|
+
if (base.indexOf("\0") !== -1) {
|
|
28
|
+
throw new Error("Invalid base path");
|
|
29
|
+
}
|
|
30
|
+
for (const seg of segments) {
|
|
31
|
+
if (seg.indexOf("..") !== -1 || seg.indexOf("/") !== -1 || seg.indexOf("\\") !== -1) {
|
|
32
|
+
throw new Error(`Invalid path segment: ${seg}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const joined = path.join(base, ...segments);
|
|
36
|
+
const normalBase = path.normalize(base) + path.sep;
|
|
37
|
+
const normalJoined = path.normalize(joined);
|
|
38
|
+
const compare = process.platform === "win32"
|
|
39
|
+
? (a, b) => a.toLowerCase().startsWith(b.toLowerCase())
|
|
40
|
+
: (a, b) => a.startsWith(b);
|
|
41
|
+
if (!compare(normalJoined, normalBase)) {
|
|
42
|
+
const exactBase = process.platform === "win32"
|
|
43
|
+
? path.normalize(base).toLowerCase()
|
|
44
|
+
: path.normalize(base);
|
|
45
|
+
const exactJoined = process.platform === "win32"
|
|
46
|
+
? normalJoined.toLowerCase()
|
|
47
|
+
: normalJoined;
|
|
48
|
+
if (exactJoined !== exactBase) {
|
|
49
|
+
throw new Error(`Path traversal detected: ${joined} is outside ${base}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return normalJoined;
|
|
53
|
+
}
|
|
54
|
+
|
|
21
55
|
function getPlatform() {
|
|
22
56
|
const osMap = { darwin: "darwin", linux: "linux", win32: "windows" };
|
|
23
57
|
const archMap = { x64: "amd64", arm64: "arm64" };
|
|
@@ -64,9 +98,7 @@ async function getLatestVersion() {
|
|
|
64
98
|
|
|
65
99
|
function pickArchive(platform, checksumsText) {
|
|
66
100
|
const tarArchive = `juggernaut_${platform}.tar.gz`;
|
|
67
|
-
if (checksumsText.includes(tarArchive)) {
|
|
68
|
-
return { name: tarArchive, kind: "tar.gz" };
|
|
69
|
-
}
|
|
101
|
+
if (checksumsText.includes(tarArchive)) return { name: tarArchive, kind: "tar.gz" };
|
|
70
102
|
const zipArchive = `juggernaut_${platform}.zip`;
|
|
71
103
|
if (process.platform === "win32" && checksumsText.includes(zipArchive)) {
|
|
72
104
|
return { name: zipArchive, kind: "zip" };
|
|
@@ -75,11 +107,14 @@ function pickArchive(platform, checksumsText) {
|
|
|
75
107
|
}
|
|
76
108
|
|
|
77
109
|
function extractTarGz(archiveBuf) {
|
|
78
|
-
const tmpDir = fs.mkdtempSync(
|
|
79
|
-
const archivePath =
|
|
110
|
+
const tmpDir = fs.mkdtempSync(TMP_PREFIX);
|
|
111
|
+
const archivePath = joinUnder(tmpDir, ARCHIVE_TAR);
|
|
112
|
+
const prevCwd = process.cwd();
|
|
80
113
|
try {
|
|
81
|
-
|
|
82
|
-
fs.
|
|
114
|
+
process.chdir(tmpDir);
|
|
115
|
+
fs.writeFileSync(ARCHIVE_TAR, archiveBuf);
|
|
116
|
+
process.chdir(PACKAGE_DIR);
|
|
117
|
+
fs.mkdirSync("bin", { recursive: true });
|
|
83
118
|
try {
|
|
84
119
|
execFileSync("tar", ["-xzf", archivePath, "-C", BIN_DIR], { stdio: "pipe" });
|
|
85
120
|
} catch (err) {
|
|
@@ -92,32 +127,47 @@ function extractTarGz(archiveBuf) {
|
|
|
92
127
|
throw new Error(`tar extraction failed: ${detail}`);
|
|
93
128
|
}
|
|
94
129
|
if (process.platform !== "win32") {
|
|
95
|
-
|
|
96
|
-
if (fs.existsSync(
|
|
97
|
-
fs.chmodSync(
|
|
130
|
+
process.chdir(BIN_DIR);
|
|
131
|
+
if (fs.existsSync(BIN_NAME)) {
|
|
132
|
+
fs.chmodSync(BIN_NAME, 0o700);
|
|
98
133
|
}
|
|
99
134
|
}
|
|
100
135
|
} finally {
|
|
136
|
+
process.chdir(prevCwd);
|
|
101
137
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
102
138
|
}
|
|
103
139
|
}
|
|
104
140
|
|
|
105
141
|
async function extractZip(archiveBuf) {
|
|
106
|
-
const tmpDir = fs.mkdtempSync(
|
|
107
|
-
const archivePath =
|
|
142
|
+
const tmpDir = fs.mkdtempSync(TMP_PREFIX);
|
|
143
|
+
const archivePath = joinUnder(tmpDir, ARCHIVE_ZIP);
|
|
144
|
+
const prevCwd = process.cwd();
|
|
108
145
|
try {
|
|
109
|
-
|
|
110
|
-
fs.
|
|
146
|
+
process.chdir(tmpDir);
|
|
147
|
+
fs.writeFileSync(ARCHIVE_ZIP, archiveBuf);
|
|
148
|
+
process.chdir(PACKAGE_DIR);
|
|
149
|
+
fs.mkdirSync("bin", { recursive: true });
|
|
111
150
|
const script = [
|
|
112
151
|
"$ErrorActionPreference = 'Stop'",
|
|
113
152
|
`Expand-Archive -LiteralPath '${archivePath.replace(/'/g, "''")}' -DestinationPath '${BIN_DIR.replace(/'/g, "''")}' -Force`
|
|
114
153
|
].join("; ");
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
154
|
+
try {
|
|
155
|
+
await execFileAsync(
|
|
156
|
+
"powershell",
|
|
157
|
+
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
158
|
+
{ stdio: "pipe" }
|
|
159
|
+
);
|
|
160
|
+
} catch (err) {
|
|
161
|
+
if (err.code === "ENOENT") {
|
|
162
|
+
throw new Error(
|
|
163
|
+
"PowerShell not found. PowerShell 5.0+ is required to extract archives on Windows."
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
const detail = err.stderr ? err.stderr.toString().trim() : err.message;
|
|
167
|
+
throw new Error(`ZIP extraction failed: ${detail}`);
|
|
168
|
+
}
|
|
120
169
|
} finally {
|
|
170
|
+
process.chdir(prevCwd);
|
|
121
171
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
122
172
|
}
|
|
123
173
|
}
|
|
@@ -141,11 +191,8 @@ async function main() {
|
|
|
141
191
|
throw new Error(`Checksum mismatch for ${archive}\n expected: ${expected}\n got: ${actual}`);
|
|
142
192
|
}
|
|
143
193
|
|
|
144
|
-
if (kind === "zip")
|
|
145
|
-
|
|
146
|
-
} else {
|
|
147
|
-
extractTarGz(archiveBuf);
|
|
148
|
-
}
|
|
194
|
+
if (kind === "zip") await extractZip(archiveBuf);
|
|
195
|
+
else extractTarGz(archiveBuf);
|
|
149
196
|
|
|
150
197
|
console.log(`Juggernaut v${version} installed successfully.`);
|
|
151
198
|
console.log(`Run: juggernaut apply`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "juggernaut-bedrock",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.1.0",
|
|
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
6
|
"juggernaut": "./bin/juggernaut"
|
|
@@ -8,8 +8,15 @@
|
|
|
8
8
|
"scripts": {
|
|
9
9
|
"postinstall": "node install.js"
|
|
10
10
|
},
|
|
11
|
-
"os": [
|
|
12
|
-
|
|
11
|
+
"os": [
|
|
12
|
+
"darwin",
|
|
13
|
+
"linux",
|
|
14
|
+
"win32"
|
|
15
|
+
],
|
|
16
|
+
"cpu": [
|
|
17
|
+
"x64",
|
|
18
|
+
"arm64"
|
|
19
|
+
],
|
|
13
20
|
"keywords": [
|
|
14
21
|
"claude",
|
|
15
22
|
"claude-code",
|
|
@@ -35,4 +42,4 @@
|
|
|
35
42
|
"url": "https://github.com/jpvelasco/juggernaut/issues"
|
|
36
43
|
},
|
|
37
44
|
"homepage": "https://github.com/jpvelasco/juggernaut#readme"
|
|
38
|
-
}
|
|
45
|
+
}
|