@aspectlylabs/mikka 0.0.171 → 0.0.173

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/cli.js CHANGED
@@ -4480,7 +4480,7 @@ import { join as join4 } from "node:path";
4480
4480
  // package.json
4481
4481
  var package_default = {
4482
4482
  name: "@mikka/daemon",
4483
- version: "0.0.171",
4483
+ version: "0.0.173",
4484
4484
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
4485
4485
  type: "module",
4486
4486
  private: true,
@@ -4540,7 +4540,7 @@ var package_default = {
4540
4540
  engines: {
4541
4541
  node: ">=24"
4542
4542
  },
4543
- gitHead: "1c0688f38d0babb142a9bccb3ff0eb6a0b2f5ef6"
4543
+ gitHead: "f0f4857928d1cfc385e5087b443f6c740b47727d"
4544
4544
  };
4545
4545
 
4546
4546
  // src/paths.ts
package/client.js CHANGED
@@ -3741,7 +3741,7 @@ import { join } from "node:path";
3741
3741
  // package.json
3742
3742
  var package_default = {
3743
3743
  name: "@mikka/daemon",
3744
- version: "0.0.171",
3744
+ version: "0.0.173",
3745
3745
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
3746
3746
  type: "module",
3747
3747
  private: true,
@@ -3801,7 +3801,7 @@ var package_default = {
3801
3801
  engines: {
3802
3802
  node: ">=24"
3803
3803
  },
3804
- gitHead: "1c0688f38d0babb142a9bccb3ff0eb6a0b2f5ef6"
3804
+ gitHead: "f0f4857928d1cfc385e5087b443f6c740b47727d"
3805
3805
  };
3806
3806
 
3807
3807
  // src/paths.ts
package/http-link.js CHANGED
@@ -4175,7 +4175,7 @@ var InvalidIdError = class extends DaemonError {
4175
4175
  // package.json
4176
4176
  var package_default = {
4177
4177
  name: "@mikka/daemon",
4178
- version: "0.0.171",
4178
+ version: "0.0.173",
4179
4179
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
4180
4180
  type: "module",
4181
4181
  private: true,
@@ -4235,7 +4235,7 @@ var package_default = {
4235
4235
  engines: {
4236
4236
  node: ">=24"
4237
4237
  },
4238
- gitHead: "1c0688f38d0babb142a9bccb3ff0eb6a0b2f5ef6"
4238
+ gitHead: "f0f4857928d1cfc385e5087b443f6c740b47727d"
4239
4239
  };
4240
4240
 
4241
4241
  // src/paths.ts
package/login.js CHANGED
@@ -3748,7 +3748,7 @@ var ServerUnreachableError = class extends DaemonError {
3748
3748
  // package.json
3749
3749
  var package_default = {
3750
3750
  name: "@mikka/daemon",
3751
- version: "0.0.171",
3751
+ version: "0.0.173",
3752
3752
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
3753
3753
  type: "module",
3754
3754
  private: true,
@@ -3808,7 +3808,7 @@ var package_default = {
3808
3808
  engines: {
3809
3809
  node: ">=24"
3810
3810
  },
3811
- gitHead: "1c0688f38d0babb142a9bccb3ff0eb6a0b2f5ef6"
3811
+ gitHead: "f0f4857928d1cfc385e5087b443f6c740b47727d"
3812
3812
  };
3813
3813
 
3814
3814
  // src/paths.ts
package/main.js CHANGED
@@ -3785,7 +3785,7 @@ import { join as join5 } from "node:path";
3785
3785
  // package.json
3786
3786
  var package_default = {
3787
3787
  name: "@mikka/daemon",
3788
- version: "0.0.171",
3788
+ version: "0.0.173",
3789
3789
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
3790
3790
  type: "module",
3791
3791
  private: true,
@@ -3845,7 +3845,7 @@ var package_default = {
3845
3845
  engines: {
3846
3846
  node: ">=24"
3847
3847
  },
3848
- gitHead: "1c0688f38d0babb142a9bccb3ff0eb6a0b2f5ef6"
3848
+ gitHead: "f0f4857928d1cfc385e5087b443f6c740b47727d"
3849
3849
  };
3850
3850
 
3851
3851
  // src/paths.ts
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "version": 1,
3
- "sourceSha": "1c0688f38d0babb142a9bccb3ff0eb6a0b2f5ef6",
3
+ "sourceSha": "f0f4857928d1cfc385e5087b443f6c740b47727d",
4
4
  "repository": "alexj11324/Mikka",
5
- "buildRunId": "41307387816",
5
+ "buildRunId": "41308067207",
6
6
  "buildKind": "github-actions-main",
7
7
  "sourceLockSha256": "c99f1e4f641d8e004cfe807653478e10f91e53fcf47102add5f4c154cdc1cb57",
8
- "createdAt": "2026-11-01T12:56:16.291Z",
8
+ "createdAt": "2026-11-01T13:04:13.631Z",
9
9
  "sbom": "sbom.cdx.json",
10
10
  "files": [
11
11
  {
@@ -41,12 +41,12 @@
41
41
  {
42
42
  "path": "cli.js",
43
43
  "size": 650230,
44
- "sha256": "9c996c01515be09f396c9d14daa0a7d49e1cc2242b01ef1c9f43e257c06fd26f"
44
+ "sha256": "666643726eeb6514a80ab849b658f35199aaebd0d0967ea9a9aa341d5d57ec6e"
45
45
  },
46
46
  {
47
47
  "path": "client.js",
48
48
  "size": 141206,
49
- "sha256": "a4e646fb4fe5f65e7be9aedb4d8b3b917cb626c1639e647e4fb76ecd6f80c6fc"
49
+ "sha256": "32a6dcff6ecb0b1f2f3378db5ba1cc5b555168d484def492360ef7f9345ad298"
50
50
  },
51
51
  {
52
52
  "path": "computer/driver.mjs",
@@ -176,7 +176,7 @@
176
176
  {
177
177
  "path": "http-link.js",
178
178
  "size": 184199,
179
- "sha256": "3390bf6e0a298b88aed177633b2e8b1f445a4f5b4dc90caf463afdbe5fcae382"
179
+ "sha256": "6df0de0bd6a3afd4c5ab74d3f8d63830ce3c7b049675b7769cd2373d7df4adfc"
180
180
  },
181
181
  {
182
182
  "path": "log.js",
@@ -186,12 +186,12 @@
186
186
  {
187
187
  "path": "login.js",
188
188
  "size": 146084,
189
- "sha256": "9abb32cfccbac412207f95e288a37b35d07d9e7b7c0cd22ca0aa24d5ec3098a4"
189
+ "sha256": "d34c26ba6b9f0ad87edeebab91df1655c9d3b1dd32f729cc61382e52731518e2"
190
190
  },
191
191
  {
192
192
  "path": "main.js",
193
193
  "size": 595447,
194
- "sha256": "5451490258aa6c34ffb8ced9e93353e3b3f2345f99a919e96763f3e05ede99ca"
194
+ "sha256": "464d5d501c71a1bbe4a38712465244d9aec70c125e75b124ff120d61c1b6bc83"
195
195
  },
196
196
  {
197
197
  "path": "mikka-mcp.mjs",
@@ -201,22 +201,27 @@
201
201
  {
202
202
  "path": "mikka.js",
203
203
  "size": 650246,
204
- "sha256": "31125fea354f25f9ec7ee9152404e20fda7786d80bc82ae309c9544e7ea24280"
204
+ "sha256": "a06968aefae3c1ccd33dd43f165d9492119d21db921dee708a7a0896d09a734f"
205
205
  },
206
206
  {
207
207
  "path": "npm-shrinkwrap.json",
208
208
  "size": 78117,
209
- "sha256": "40ca75057e21c063a2637aabc338d35f354676d1a62d7c138406242609f43157"
209
+ "sha256": "65a4dfcacfbb51ec07e851a08615dea08e603bca3ab661e7bb210aaeac8a395a"
210
210
  },
211
211
  {
212
212
  "path": "package.json",
213
213
  "size": 1247,
214
- "sha256": "806a8d151256ed272b6b8c94414058c6107540b0982f8399f1f7f3b5899ecf77"
214
+ "sha256": "b04797960d02bec545262483034f898bd2ef46bc2a2ca23fb8e8d4f48bc66c7f"
215
215
  },
216
216
  {
217
217
  "path": "paths.js",
218
218
  "size": 4138,
219
- "sha256": "01f69fa71cfe973e3a1ee6ec4a98d81bf0b84877c68680531be00e2d66682527"
219
+ "sha256": "16aaad5f1e7e7b699fa646821418d2136f6c40dc4d7dd63e838240c8e3f75e89"
220
+ },
221
+ {
222
+ "path": "run-sandbox-worker.mjs",
223
+ "size": 15600,
224
+ "sha256": "e66dd3ff9beaef137695abc18486acee89f22ab0d9ba51e01d0f8fd4c947c4d7"
220
225
  },
221
226
  {
222
227
  "path": "sandbox.js",
@@ -226,7 +231,7 @@
226
231
  {
227
232
  "path": "sbom.cdx.json",
228
233
  "size": 144314,
229
- "sha256": "9f11de1ee8a867f5fa4b77fd84d48a94e233d5cff82712e33b612bf6f400c0cd"
234
+ "sha256": "ae89074dbaea988c336c6016873da9ce849d258390fdc794ea172d1cbf7b562f"
230
235
  }
231
236
  ]
232
237
  }
package/mikka.js CHANGED
@@ -4481,7 +4481,7 @@ import { join as join4 } from "node:path";
4481
4481
  // package.json
4482
4482
  var package_default = {
4483
4483
  name: "@mikka/daemon",
4484
- version: "0.0.171",
4484
+ version: "0.0.173",
4485
4485
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
4486
4486
  type: "module",
4487
4487
  private: true,
@@ -4541,7 +4541,7 @@ var package_default = {
4541
4541
  engines: {
4542
4542
  node: ">=24"
4543
4543
  },
4544
- gitHead: "1c0688f38d0babb142a9bccb3ff0eb6a0b2f5ef6"
4544
+ gitHead: "f0f4857928d1cfc385e5087b443f6c740b47727d"
4545
4545
  };
4546
4546
 
4547
4547
  // src/paths.ts
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@aspectlylabs/mikka",
3
- "version": "0.0.171",
3
+ "version": "0.0.173",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@aspectlylabs/mikka",
9
- "version": "0.0.171",
9
+ "version": "0.0.173",
10
10
  "license": "AGPL-3.0-only",
11
11
  "dependencies": {
12
12
  "@agentclientprotocol/sdk": "1.9.0",
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@aspectlylabs/mikka",
3
- "version": "0.0.171",
3
+ "version": "0.0.173",
4
4
  "description": "Local Mikka daemon: runs agents through the user's own CLIs",
5
- "gitHead": "1c0688f38d0babb142a9bccb3ff0eb6a0b2f5ef6",
5
+ "gitHead": "f0f4857928d1cfc385e5087b443f6c740b47727d",
6
6
  "type": "module",
7
7
  "private": false,
8
8
  "license": "AGPL-3.0-only",
package/paths.js CHANGED
@@ -6,7 +6,7 @@ import { join } from "node:path";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@mikka/daemon",
9
- version: "0.0.171",
9
+ version: "0.0.173",
10
10
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
11
11
  type: "module",
12
12
  private: true,
@@ -66,7 +66,7 @@ var package_default = {
66
66
  engines: {
67
67
  node: ">=24"
68
68
  },
69
- gitHead: "1c0688f38d0babb142a9bccb3ff0eb6a0b2f5ef6"
69
+ gitHead: "f0f4857928d1cfc385e5087b443f6c740b47727d"
70
70
  };
71
71
 
72
72
  // src/paths.ts
@@ -0,0 +1,360 @@
1
+ // This trusted host process owns exactly one SandboxManager and one CLI.
2
+ // Only its parent's private IPC channel can configure it or answer a request.
3
+ import { spawn } from "node:child_process"
4
+ import { randomUUID } from "node:crypto"
5
+ import { isIP, Socket } from "node:net"
6
+ import { isAbsolute } from "node:path"
7
+ import { fileURLToPath } from "node:url"
8
+
9
+ const AUTH_LIMIT = 1_048_576
10
+ const MAX_PENDING_NETWORK = 128
11
+ const NETWORK_DECISION_MS = 5 * 60_000
12
+
13
+ export function assertRunSandboxDependencies(dependencies, platform = process.platform) {
14
+ if (dependencies.errors.length) {
15
+ throw new Error(`sandbox dependencies unavailable: ${dependencies.errors.join("; ")}`)
16
+ }
17
+ // Official 0.0.80 reports a missing apply-seccomp helper as only a warning.
18
+ // That would leave host Unix sockets reachable, so this launcher refuses to
19
+ // initialize or wrap. Old/unknown Linux dependency warnings also fail closed.
20
+ if (platform === "linux" && dependencies.warnings.length) {
21
+ throw new Error(`sandbox isolation dependencies unsafe: ${dependencies.warnings.join("; ")}`)
22
+ }
23
+ }
24
+
25
+ // Runs INSIDE the official sandbox. Linux bwrap deliberately closes extra
26
+ // inherited fds, so a framed stdin prefix carries the token across that
27
+ // boundary. It is converted to a token-only fd3 pipe before the real CLI starts.
28
+ async function authBridge() {
29
+ let token
30
+ let child
31
+ let headerBytes = 0
32
+ let tokenBytes = 0
33
+ const header = Buffer.alloc(4)
34
+ let complete = false
35
+ const fail = () => {
36
+ token?.fill(0)
37
+ process.stderr.write("run sandbox auth pipe was incomplete or invalid\n")
38
+ process.exit(1)
39
+ }
40
+ process.stdin.on("error", fail)
41
+ process.stdin.once("end", () => { if (!complete) fail() })
42
+ const read = (chunk) => {
43
+ let offset = 0
44
+ if (headerBytes < 4) {
45
+ const count = Math.min(4 - headerBytes, chunk.length)
46
+ chunk.copy(header, headerBytes, 0, count)
47
+ headerBytes += count
48
+ offset += count
49
+ if (headerBytes === 4) {
50
+ const length = header.readUInt32BE()
51
+ if (length < 1 || length > AUTH_LIMIT) return fail()
52
+ token = Buffer.alloc(length)
53
+ }
54
+ }
55
+ if (token) {
56
+ const count = Math.min(token.length - tokenBytes, chunk.length - offset)
57
+ chunk.copy(token, tokenBytes, offset, offset + count)
58
+ chunk.fill(0, offset, offset + count)
59
+ tokenBytes += count
60
+ offset += count
61
+ }
62
+ if (!token || tokenBytes !== token.length) return
63
+ complete = true
64
+ process.stdin.pause()
65
+ process.stdin.off("data", read)
66
+ if (offset < chunk.length) process.stdin.unshift(chunk.subarray(offset))
67
+ child = spawn(process.argv[3], process.argv.slice(4), {
68
+ env: { ...process.env, CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR: "3" },
69
+ stdio: ["pipe", "pipe", "pipe", "pipe"],
70
+ })
71
+ child.once("error", () => fail())
72
+ child.stdin.on("error", () => undefined)
73
+ child.stdio[3].on("error", fail)
74
+ const payload = token
75
+ child.stdio[3].end(payload, () => { payload.fill(0); token = undefined })
76
+ // unshift above preserves protocol bytes delivered in the frame's last
77
+ // chunk. pipe handles subsequent data and backpressure without parsing it.
78
+ process.stdin.pipe(child.stdin)
79
+ child.stdout.pipe(process.stdout, { end: false })
80
+ child.stderr.pipe(process.stderr, { end: false })
81
+ child.once("close", async (code, signal) => {
82
+ token?.fill(0)
83
+ await Promise.all([process.stdout, process.stderr].map((stream) =>
84
+ new Promise((resolve) => stream.write("", resolve))))
85
+ process.exit(code ?? (signal === "SIGINT" ? 130 : 143))
86
+ })
87
+ }
88
+ process.stdin.on("data", read)
89
+ }
90
+
91
+ async function runWorker() {
92
+ const { NetworkConfigSchema, SandboxManager, SandboxRuntimeConfigSchema } = await import("@anthropic-ai/sandbox-runtime")
93
+
94
+ let configured = false
95
+ let active = false
96
+ let stopping = false
97
+ let cli
98
+ let initialize
99
+ let wrapping
100
+ let nextRequest = 0
101
+ let stderr = ""
102
+ let correlation
103
+ let initTimer
104
+ const pending = new Map()
105
+ const lifetime = new AbortController()
106
+
107
+ // Intentionally kept equivalent to the parent's exported matcher. Both sides
108
+ // independently apply the immutable maximum before a permission callback runs.
109
+ function canonicalHost(host) {
110
+ // eslint-disable-next-line no-control-regex -- Reject control bytes in a destination.
111
+ if (!host || /[\s\x00-\x1f\x7f%\\/@?#*]/u.test(host)) return
112
+ const bare = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host
113
+ if (isIP(bare) === 6) return new URL(`http://[${bare}]`).hostname.slice(1, -1)
114
+ if (bare.includes(":")) return
115
+ try { return new URL(`http://${bare}`).hostname.toLowerCase() } catch { return undefined }
116
+ }
117
+
118
+ function matchesDomain(request, domains) {
119
+ const host = canonicalHost(request.host)
120
+ if (!host || !Number.isInteger(request.port) || request.port < 1 || request.port > 65535) return false
121
+ return domains.some((entry) => {
122
+ if (entry === "*") return true
123
+ const parts = /^(\[[^\]]+\]|[^:]+?)(?::([1-9][0-9]{0,4}))?$/u.exec(entry)
124
+ if (!parts || (parts[2] !== undefined &&
125
+ (Number(parts[2]) > 65535 || Number(parts[2]) !== request.port))) return false
126
+ const wildcard = parts[1].startsWith("*.")
127
+ const pattern = canonicalHost(wildcard ? parts[1].slice(2) : parts[1])
128
+ if (!pattern) return false
129
+ return wildcard ? !isIP(host) && pattern.includes(".") && host.endsWith(`.${pattern}`) : host === pattern
130
+ })
131
+ }
132
+
133
+ function quote(arg) {
134
+ return /^[A-Za-z0-9_@%+=:,./-]+$/u.test(arg) ? arg : `'${arg.replaceAll("'", `'"'"'`)}'`
135
+ }
136
+
137
+ function send(message) {
138
+ if (!process.connected) return
139
+ process.send(message, (error) => { if (error) void stop(0) })
140
+ }
141
+
142
+ function denyPending() {
143
+ active = false
144
+ lifetime.abort()
145
+ for (const request of pending.values()) {
146
+ clearTimeout(request.timer)
147
+ request.resolve(false)
148
+ }
149
+ pending.clear()
150
+ }
151
+
152
+ function groupSignal(signal) {
153
+ try { process.kill(-process.pid, signal) } catch (error) {
154
+ if (error.code !== "ESRCH") throw error
155
+ }
156
+ }
157
+
158
+ async function stop(graceMs = 0, outcome = { code: null, signal: "SIGTERM" }) {
159
+ denyPending()
160
+ if (stopping) return
161
+ stopping = true
162
+ clearTimeout(initTimer)
163
+ // The worker catches TERM; CLI descendants and runtime helpers share its
164
+ // group. A final parent group kill also covers a descendant that ignores it.
165
+ const watchdog = setTimeout(() => {
166
+ process.stderr.write("run sandbox teardown timed out; terminating process group\n")
167
+ groupSignal("SIGKILL")
168
+ }, Math.max(0, Math.min(graceMs, 30_000)) + 4000)
169
+ try {
170
+ groupSignal("SIGTERM")
171
+ if (cli && cli.exitCode === null && cli.signalCode === null) {
172
+ // Linux bwrap creates a new session for its PID namespace. Address the
173
+ // owned wrapper child directly as well as our group; --die-with-parent
174
+ // and --unshare-pid end its nested workload when that wrapper dies.
175
+ cli.kill(graceMs > 0 ? "SIGTERM" : "SIGKILL")
176
+ await new Promise((resolve) => {
177
+ const timer = setTimeout(() => { cli.kill("SIGKILL") }, Math.min(graceMs, 30_000))
178
+ cli.once("exit", () => { clearTimeout(timer); resolve() })
179
+ })
180
+ }
181
+ await initialize?.catch(() => undefined)
182
+ await wrapping?.catch(() => undefined)
183
+ // Official reset closes this launcher's established proxy connections and
184
+ // removes only its own ephemeral sockets/mountpoints/CA/masked artifacts.
185
+ // No worktree, run directory, logs or caller-owned data are removed here.
186
+ await SandboxManager.reset()
187
+ if (correlation) {
188
+ const annotated = SandboxManager.annotateStderrWithSandboxFailures(correlation, stderr)
189
+ if (annotated.length > stderr.length) process.stderr.write(annotated.slice(stderr.length))
190
+ }
191
+ if (process.connected) await new Promise((resolve) => {
192
+ process.send({ type: "finished", ...outcome }, () => resolve())
193
+ })
194
+ // process.exit does not wait for writes; flush the bridged output first.
195
+ await Promise.all([process.stdout, process.stderr].map((stream) =>
196
+ new Promise((resolve) => stream.write("", resolve))))
197
+ process.exit(outcome.code ?? (outcome.signal === "SIGINT" ? 130 : 143))
198
+ } catch (error) {
199
+ process.stderr.write(`run sandbox teardown failed: ${error.message}\n`)
200
+ // A failed reset cannot be followed by a successful-looking exit or a
201
+ // lingering live proxy. Group kill is fail-closed; parent also enforces it.
202
+ groupSignal("SIGKILL")
203
+ } finally {
204
+ clearTimeout(watchdog)
205
+ }
206
+ }
207
+
208
+ async function start(message) {
209
+ try {
210
+ if (typeof message.command !== "string" || !message.command || message.command.includes("\0") ||
211
+ !Array.isArray(message.args) || message.args.some((arg) => typeof arg !== "string" || arg.includes("\0")) ||
212
+ typeof message.cwd !== "string" || !isAbsolute(message.cwd) ||
213
+ !message.env || typeof message.env !== "object" || Array.isArray(message.env) ||
214
+ Object.entries(message.env).some(([key, value]) => key.includes("=") || key.includes("\0") ||
215
+ (value !== undefined && (typeof value !== "string" || value.includes("\0")))) ||
216
+ !Array.isArray(message.maxAllowDomains) || !Array.isArray(message.modelApiDomains) ||
217
+ typeof message.hasAuthToken !== "boolean") {
218
+ throw new Error("invalid run sandbox launch configuration")
219
+ }
220
+ const maximum = Object.freeze([...message.maxAllowDomains])
221
+ NetworkConfigSchema.parse({ allowedDomains: maximum.filter((entry) => entry !== "*"), deniedDomains: [] })
222
+ NetworkConfigSchema.parse({ allowedDomains: [...message.modelApiDomains], deniedDomains: [] })
223
+ const config = SandboxRuntimeConfigSchema.parse({
224
+ // Every connection, even a model API connection, must consult the live
225
+ // parent closure. No configured allow or command-id allow bypasses it.
226
+ network: {
227
+ allowedDomains: [], deniedDomains: [], strictAllowlist: false,
228
+ allowLocalBinding: false, allowAllUnixSockets: false, allowUnixSockets: [],
229
+ },
230
+ filesystem: message.policy,
231
+ enableWeakerNetworkIsolation: true,
232
+ enableWeakerNestedSandbox: false,
233
+ allowNestedUserNamespaces: false,
234
+ })
235
+ if (!SandboxManager.isSupportedPlatform()) throw new Error("sandbox platform unsupported")
236
+ const dependencies = SandboxManager.checkDependencies()
237
+ assertRunSandboxDependencies(dependencies)
238
+ if (stopping || !process.connected) return
239
+ active = true
240
+ initialize = SandboxManager.initialize(config, async (request) => {
241
+ if (!active || stopping || !process.connected || pending.size >= MAX_PENDING_NETWORK || !matchesDomain(request, maximum)) return false
242
+ const id = ++nextRequest
243
+ return new Promise((resolve) => {
244
+ const timer = setTimeout(() => {
245
+ if (pending.delete(id)) resolve(false)
246
+ }, NETWORK_DECISION_MS)
247
+ pending.set(id, { resolve, timer })
248
+ send({ type: "network", id, host: request.host, port: request.port })
249
+ })
250
+ })
251
+ await initialize
252
+ if (!active || stopping || !process.connected) return
253
+ const argv = message.hasAuthToken
254
+ ? [process.execPath, fileURLToPath(import.meta.url), "--auth-bridge", message.command, ...message.args]
255
+ : [message.command, ...message.args]
256
+ const command = argv.map(quote).join(" ")
257
+ // Correlation is only for diagnostics, never network/run authority.
258
+ correlation = randomUUID()
259
+ wrapping = SandboxManager.wrapWithSandbox(command, "/bin/sh", undefined, lifetime.signal, { commandId: correlation })
260
+ const wrapped = await wrapping
261
+ if (!active || stopping || !process.connected) return
262
+ const env = { ...message.env }
263
+ // Node's private IPC setup must not be inherited by the untrusted CLI.
264
+ delete env.NODE_CHANNEL_FD
265
+ delete env.NODE_CHANNEL_SERIALIZATION_MODE
266
+ if (message.hasAuthToken === true) {
267
+ env.CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR = "3"
268
+ delete env.CLAUDE_CODE_OAUTH_TOKEN
269
+ }
270
+ cli = spawn("/bin/sh", ["-c", `exec ${wrapped}`], {
271
+ cwd: message.cwd,
272
+ env,
273
+ stdio: ["pipe", "pipe", "pipe"],
274
+ // Stay in the launcher's group, so even an abrupt worker failure cannot
275
+ // orphan an independently detached CLI before its pid can be reported.
276
+ detached: false,
277
+ })
278
+ cli.stdin.on("error", () => undefined)
279
+ if (message.hasAuthToken) {
280
+ // The token arrives on a separate host pipe. Frame it before forwarding
281
+ // any protocol input, so neither packet boundaries nor early SDK writes
282
+ // can mix credentials with the first CLI message.
283
+ const source = new Socket({ fd: 3, readable: true, writable: false })
284
+ const chunks = []
285
+ let length = 0
286
+ source.on("data", (data) => {
287
+ length += data.length
288
+ if (length > AUTH_LIMIT) {
289
+ data.fill(0)
290
+ source.destroy(new Error("auth pipe payload too large"))
291
+ } else chunks.push(data)
292
+ })
293
+ source.once("error", () => {
294
+ for (const chunk of chunks) chunk.fill(0)
295
+ process.stderr.write("run sandbox auth pipe failed\n")
296
+ void stop(0, { code: 1, signal: null })
297
+ })
298
+ source.once("end", () => {
299
+ if (!length || stopping) {
300
+ for (const chunk of chunks) chunk.fill(0)
301
+ void stop(0, { code: 1, signal: null })
302
+ return
303
+ }
304
+ const payload = Buffer.concat(chunks)
305
+ for (const chunk of chunks) chunk.fill(0)
306
+ const header = Buffer.alloc(4)
307
+ header.writeUInt32BE(payload.length)
308
+ cli.stdin.write(header)
309
+ cli.stdin.write(payload, () => payload.fill(0))
310
+ process.stdin.pipe(cli.stdin)
311
+ })
312
+ } else process.stdin.pipe(cli.stdin)
313
+ cli.stdout.pipe(process.stdout, { end: false })
314
+ cli.stderr.on("data", (data) => { stderr = (stderr + data.toString()).slice(-16_000) })
315
+ cli.stderr.pipe(process.stderr, { end: false })
316
+ cli.once("error", (error) => {
317
+ process.stderr.write(`sandboxed CLI launch failed: ${error.message}\n`)
318
+ void stop(0, { code: 1, signal: null })
319
+ })
320
+ cli.once("close", (code, signal) => { void stop(0, { code, signal }) })
321
+ } catch (error) {
322
+ process.stderr.write(`run sandbox launch failed: ${error.message}\n`)
323
+ await stop(0, { code: 1, signal: null })
324
+ }
325
+ }
326
+
327
+ process.on("message", (message) => {
328
+ if (!message || typeof message !== "object") return
329
+ if (message.type === "stop") {
330
+ void stop(Number.isFinite(message.graceMs) ? Math.max(0, message.graceMs) : 0)
331
+ } else if (message.type === "init" && !configured && !stopping) {
332
+ configured = true
333
+ clearTimeout(initTimer)
334
+ void start(message)
335
+ } else if (message.type === "decision" && Number.isSafeInteger(message.id)) {
336
+ const request = pending.get(message.id)
337
+ if (!request) return
338
+ pending.delete(message.id)
339
+ clearTimeout(request.timer)
340
+ request.resolve(message.allow === true && active && !stopping && process.connected)
341
+ }
342
+ })
343
+ process.on("disconnect", () => { void stop(0) })
344
+ process.on("SIGTERM", () => { void stop(0) })
345
+ process.on("SIGINT", () => { void stop(0, { code: null, signal: "SIGINT" }) })
346
+ process.stdout.on("error", () => { void stop(0) })
347
+ process.stderr.on("error", () => { void stop(0) })
348
+ initTimer = setTimeout(() => {
349
+ process.stderr.write("run sandbox launch configuration was not received\n")
350
+ void stop(0, { code: 1, signal: null })
351
+ }, 10_000)
352
+ if (!process.connected) void stop(0, { code: 1, signal: null })
353
+ }
354
+
355
+ // Importing the pure dependency check for source-only tests does not start a
356
+ // launcher, touch resources or initialize the official manager.
357
+ if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
358
+ if (process.argv[2] === "--auth-bridge") await authBridge()
359
+ else await runWorker()
360
+ }
package/sbom.cdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:996bddb9-b957-41f7-9c76-37bc5a731d85",
5
+ "serialNumber": "urn:uuid:57e9fca5-ac79-4f36-8d0a-71d72bbad1a7",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-11-01T12:56:15.353Z",
8
+ "timestamp": "2026-11-01T13:04:12.654Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "pre-build"
@@ -19,13 +19,13 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@aspectlylabs/mikka@0.0.171",
22
+ "bom-ref": "@aspectlylabs/mikka@0.0.173",
23
23
  "type": "library",
24
- "name": ".retained-build-qZhAd8",
25
- "version": "0.0.171",
24
+ "name": ".retained-build-lJvCJN",
25
+ "version": "0.0.173",
26
26
  "scope": "required",
27
27
  "description": "Local Mikka daemon: runs agents through the user's own CLIs",
28
- "purl": "pkg:npm/%40aspectlylabs/mikka@0.0.171",
28
+ "purl": "pkg:npm/%40aspectlylabs/mikka@0.0.173",
29
29
  "properties": [],
30
30
  "externalReferences": [
31
31
  {
@@ -4627,7 +4627,7 @@
4627
4627
  ],
4628
4628
  "dependencies": [
4629
4629
  {
4630
- "ref": "@aspectlylabs/mikka@0.0.171",
4630
+ "ref": "@aspectlylabs/mikka@0.0.173",
4631
4631
  "dependsOn": [
4632
4632
  "@agentclientprotocol/sdk@1.9.0",
4633
4633
  "@anthropic-ai/claude-agent-sdk@0.3.305",