@go-hare/claude-agent-sdk 0.3.177

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.
@@ -0,0 +1 @@
1
+ export function extractFromBunfs(embeddedPath: string): string
@@ -0,0 +1,156 @@
1
+ /* eslint-disable custom-rules/no-sync-fs */
2
+ // Extracts a file from Bun's $bunfs virtual filesystem to a real temp directory
3
+ // so it can be spawned as a subprocess (child processes cannot access $bunfs).
4
+ //
5
+ // Ships verbatim (unbundled) as the @anthropic-ai/claude-agent-sdk `./extract`
6
+ // export — keep it standalone and Node-importable (no Bun globals, no
7
+ // local-relative imports).
8
+
9
+ import { createHash } from 'crypto'
10
+ import {
11
+ chmodSync,
12
+ existsSync,
13
+ lstatSync,
14
+ mkdirSync,
15
+ readFileSync,
16
+ renameSync,
17
+ unlinkSync,
18
+ writeFileSync,
19
+ } from 'fs'
20
+ import { tmpdir as osTmpdir } from 'os'
21
+ import { basename, join } from 'path'
22
+
23
+ // Inlined from src/utils/tempfile.ts — this file ships verbatim (unbundled) as
24
+ // the @anthropic-ai/claude-agent-sdk/extract export, so it must have zero
25
+ // local-relative imports. Keep behavior in sync with tempfile.ts#tmpdir.
26
+ function tmpdir() {
27
+ if (process.env.CLAUDE_CODE_TMPDIR) {
28
+ return process.env.CLAUDE_CODE_TMPDIR
29
+ }
30
+ if (process.platform === 'darwin') {
31
+ // eslint-disable-next-line custom-rules/no-hardcoded-tmp -- mirrors tempfile.ts: macOS /tmp works fine; os.tmpdir() below is for Android-on-Linux where /tmp isn't writable.
32
+ return '/tmp'
33
+ }
34
+ return osTmpdir()
35
+ }
36
+
37
+ // Inlined from src/utils/tempfile.ts#claudeTempDir + verifyTempDirOwnership —
38
+ // keep behavior in sync. Per-UID Claude temp directory: `{tmpdir()}/claude-{uid}`
39
+ // on Unix, `{tmpdir()}/claude` on Windows (where %TEMP% is already per-user).
40
+ //
41
+ // Defense-in-depth against a local attacker pre-creating the extraction dir
42
+ // before the victim's first run: the content-hash dir name is fully predictable
43
+ // (sha256 of a public npm binary) under shared `/tmp`, and
44
+ // `mkdirSync({recursive:true})` is a silent no-op on a pre-existing dir without
45
+ // enforcing owner or mode. Without this check an attacker-owned directory would
46
+ // be used as-is, letting them swap the binary the SDK later spawns.
47
+ function safeTempBase() {
48
+ const dir = join(
49
+ tmpdir(),
50
+ process.platform === 'win32'
51
+ ? 'claude'
52
+ : `claude-${process.getuid?.() ?? 0}`,
53
+ )
54
+ // Gate on getuid (POSIX-only) rather than process.platform: getuid presence
55
+ // reflects the real OS. No-op on Windows where %TEMP% is already per-user.
56
+ if (typeof process.getuid === 'function') {
57
+ mkdirSync(dir, { recursive: true, mode: 0o700 })
58
+ const uid = process.getuid()
59
+ const st = lstatSync(dir)
60
+ if (!st.isDirectory()) {
61
+ throw new Error(
62
+ `Temp directory ${dir} is not a directory (may be an attacker-planted symlink). Refusing to use it.`,
63
+ )
64
+ }
65
+ if (st.uid !== uid) {
66
+ throw new Error(
67
+ `Temp directory ${dir} is owned by uid ${st.uid}, expected ${uid}. Refusing to use it — another user may have pre-created it.`,
68
+ )
69
+ }
70
+ if ((st.mode & 0o777) !== 0o700) {
71
+ // Owner matches, so this is our own dir from a prior run with a looser
72
+ // umask rather than an attacker pre-create. Tighten it.
73
+ chmodSync(dir, 0o700)
74
+ }
75
+ } else {
76
+ // Windows: best-effort create; verification is skipped (%TEMP% is per-user).
77
+ try {
78
+ mkdirSync(dir, { recursive: true, mode: 0o700 })
79
+ } catch {
80
+ // best-effort; see comment above
81
+ }
82
+ }
83
+ return dir
84
+ }
85
+
86
+ /**
87
+ * If `embeddedPath` is inside Bun's $bunfs virtual filesystem, extract it to a
88
+ * temp directory and return the real path. Otherwise return the path unchanged.
89
+ *
90
+ * Uses a content hash for the directory name so that:
91
+ * - Same binary version reuses the same extracted file (no accumulation)
92
+ * - Different versions get separate directories (no collision)
93
+ * - Concurrent instances are safe (atomic write via temp file + rename)
94
+ *
95
+ * @param {string} embeddedPath — path returned by `import ... with { type: 'file' }`
96
+ * @returns {string} — a real filesystem path that can be spawned as a subprocess
97
+ */
98
+ export function extractFromBunfs(embeddedPath) {
99
+ // Bun single-file embed: `/$bunfs/root/...` (POSIX) or `B:\~BUN\root\...`
100
+ // (Windows — Bun's StandaloneModuleGraph uses `~BUN`, not `$bunfs`, on Windows).
101
+ if (!embeddedPath.includes('$bunfs') && !embeddedPath.includes('~BUN')) {
102
+ return embeddedPath
103
+ }
104
+
105
+ try {
106
+ const content = readFileSync(embeddedPath)
107
+ const hash = createHash('sha256').update(content).digest('hex').slice(0, 16)
108
+ const tmpDir = join(safeTempBase(), `claude-agent-sdk-${hash}`)
109
+ // Preserve the embedded file's basename — ProcessTransport.isNativeBinary()
110
+ // decides whether to spawn directly or via node/bun based on extension, so
111
+ // a native binary must not come out named cli.js.
112
+ const fileName = basename(embeddedPath)
113
+ const tmpPath = join(tmpDir, fileName)
114
+ mkdirSync(tmpDir, { recursive: true, mode: 0o700 })
115
+ // The directory is content-hash-keyed, so an existing tmpPath is byte-
116
+ // identical to what we would write — short-circuit. This is a write
117
+ // idempotency check on a content-addressed path, not a read TOCTOU
118
+ // (the existence IS the contract). Without it, a second call (or a
119
+ // concurrent app instance) on Windows would hit EPERM/EBUSY renaming over
120
+ // the memory-mapped running .exe and fall back to the unspawnable $bunfs
121
+ // path. It also skips a redundant write+chmod on every call.
122
+ if (existsSync(tmpPath)) {
123
+ return tmpPath
124
+ }
125
+ // Write to a temp file and atomically rename to avoid truncation races —
126
+ // concurrent readers always see either the old complete file or the new one.
127
+ const tmpFile = join(tmpDir, `${fileName}.tmp.${process.pid}`)
128
+ writeFileSync(tmpFile, content)
129
+ chmodSync(tmpFile, 0o755)
130
+ try {
131
+ renameSync(tmpFile, tmpPath)
132
+ } catch (e) {
133
+ if ((e.code === 'EPERM' || e.code === 'EBUSY') && existsSync(tmpPath)) {
134
+ // Lost a concurrent first-time-extraction race on Windows: the winner's
135
+ // child holds tmpPath memory-mapped, so the loser's rename over it fails.
136
+ // The content-hash dir guarantees byte-identity, so the winner's file is
137
+ // exactly what we'd have written — use it.
138
+ try {
139
+ unlinkSync(tmpFile)
140
+ } catch {
141
+ // best-effort cleanup of our orphaned .tmp.{pid} file
142
+ }
143
+ return tmpPath
144
+ }
145
+ throw e
146
+ }
147
+ return tmpPath
148
+ } catch (err) {
149
+ // biome-ignore lint/suspicious/noConsole: intentional user-facing warning in standalone SDK helper
150
+ console.warn(
151
+ `[claude-agent-sdk] Failed to extract CLI from $bunfs: ${err.message}. ` +
152
+ `Child processes cannot access $bunfs paths — the CLI will likely fail to start.`,
153
+ )
154
+ return embeddedPath
155
+ }
156
+ }
package/manifest.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "version": "2.6.18",
3
+ "commit": "eec00c07b60b0f00eaf036a3591e95678c9613cb",
4
+ "buildDate": "2026-06-15T13:05:07+08:00",
5
+ "platforms": {
6
+ "darwin-arm64": {
7
+ "binary": "claude",
8
+ "checksum": "d13734597665d432b445f5d2ac7c9bb5542370cd87f006887a02fd763f07148a",
9
+ "size": 93877730
10
+ },
11
+ "darwin-x64": {
12
+ "binary": "claude",
13
+ "checksum": "1f46784a95c5fe8e20fb8b12584bfe6bc2181c1e1b6e7bb71f8afd2fdd9bf262",
14
+ "size": 99369040
15
+ },
16
+ "linux-arm64": {
17
+ "binary": "claude",
18
+ "checksum": "ab376eefb73644d4b306d6d6cff11a815455d67f15cf0ae90b581fae73c572e4",
19
+ "size": 123971728
20
+ },
21
+ "linux-x64": {
22
+ "binary": "claude",
23
+ "checksum": "e2978613ff829432af41f29a682facb6c585ff0a0346aa0bc244da9505a1b384",
24
+ "size": 124921984
25
+ },
26
+ "linux-arm64-musl": {
27
+ "binary": "claude",
28
+ "checksum": "59412e85de373ea625a3eb561bf2a1ee813df5b723203f9195ac3bac50b77b1d",
29
+ "size": 123971728
30
+ },
31
+ "linux-x64-musl": {
32
+ "binary": "claude",
33
+ "checksum": "290eaeb86f36a9cdd1f683c6db0d4f3d9b3cce99c0736f2a22983872d4a3ea52",
34
+ "size": 124921984
35
+ },
36
+ "win32-x64": {
37
+ "binary": "claude.exe",
38
+ "checksum": "2132b711a49b0c618e7aca08f131fd5595504f370e4a806b44454feff660a301",
39
+ "size": 128822272
40
+ },
41
+ "win32-arm64": {
42
+ "binary": "claude.exe",
43
+ "checksum": "66c2c3b31ba56dda41243a83c03511d408fea759122f43231a88f6d20faa2a39",
44
+ "size": 124925952
45
+ }
46
+ }
47
+ }
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "@go-hare/claude-agent-sdk",
3
+ "version": "0.3.177",
4
+ "main": "sdk.mjs",
5
+ "types": "sdk.d.ts",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./sdk.d.ts",
9
+ "default": "./sdk.mjs"
10
+ },
11
+ "./extract": {
12
+ "types": "./extractFromBunfs.d.ts",
13
+ "default": "./extractFromBunfs.js"
14
+ },
15
+ "./browser": {
16
+ "types": "./browser-sdk.d.ts",
17
+ "default": "./browser-sdk.js"
18
+ },
19
+ "./bridge": {
20
+ "types": "./bridge.d.ts",
21
+ "default": "./bridge.mjs"
22
+ },
23
+ "./assistant": {
24
+ "types": "./assistant.d.ts",
25
+ "default": "./assistant.mjs"
26
+ },
27
+ "./sdk-tools": {
28
+ "types": "./sdk-tools.d.ts"
29
+ },
30
+ "./sdk-tools.js": {
31
+ "types": "./sdk-tools.d.ts"
32
+ }
33
+ },
34
+ "engines": {
35
+ "node": ">=18.0.0"
36
+ },
37
+ "type": "module",
38
+ "author": "DeQiang",
39
+ "license": "SEE LICENSE IN README.md",
40
+ "description": "SDK for building AI agents with Claude Code's capabilities. Programmatically interact with Claude to build autonomous agents that can understand codebases, edit files, and execute workflows.",
41
+ "homepage": "https://github.com/go-hare/claude-agent-sdk-typescript",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/go-hare/claude-agent-sdk-typescript.git"
45
+ },
46
+ "bugs": {
47
+ "url": "https://github.com/go-hare/claude-agent-sdk-typescript/issues"
48
+ },
49
+ "keywords": [
50
+ "ai",
51
+ "agent",
52
+ "sdk",
53
+ "claude",
54
+ "anthropic",
55
+ "automation",
56
+ "code-generation"
57
+ ],
58
+ "peerDependencies": {
59
+ "@anthropic-ai/sdk": ">=0.93.0",
60
+ "@modelcontextprotocol/sdk": "^1.29.0",
61
+ "zod": "^4.0.0"
62
+ },
63
+ "optionalDependencies": {
64
+ "@go-hare/claude-code-linux-x64": "2.6.18",
65
+ "@go-hare/claude-code-linux-arm64": "2.6.18",
66
+ "@go-hare/claude-code-linux-x64-musl": "2.6.18",
67
+ "@go-hare/claude-code-linux-arm64-musl": "2.6.18",
68
+ "@go-hare/claude-code-darwin-x64": "2.6.18",
69
+ "@go-hare/claude-code-darwin-arm64": "2.6.18",
70
+ "@go-hare/claude-code-win32-x64": "2.6.18",
71
+ "@go-hare/claude-code-win32-arm64": "2.6.18"
72
+ },
73
+ "files": [
74
+ "sdk.mjs",
75
+ "sdk.d.ts",
76
+ "sdk-tools.d.ts",
77
+ "agentSdkTypes.d.ts",
78
+ "bridge.mjs",
79
+ "bridge.d.ts",
80
+ "assistant.mjs",
81
+ "assistant.d.ts",
82
+ "browser-sdk.js",
83
+ "browser-sdk.d.ts",
84
+ "extractFromBunfs.js",
85
+ "extractFromBunfs.d.ts",
86
+ "manifest.json"
87
+ ],
88
+ "claudeCodeVersion": "2.6.18"
89
+ }