@aspectlylabs/mikka 0.0.156 → 0.0.158

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/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.156",
4484
+ version: "0.0.158",
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: "3fe02256b52ef29ce2581173987f01d3b2054448"
4544
+ gitHead: "5011b7faac02b82a863d07eba4d7180d47fccc2b"
4545
4545
  };
4546
4546
 
4547
4547
  // src/paths.ts
@@ -4882,11 +4882,251 @@ function classifyWrite(worktree, target) {
4882
4882
  return ok2 ? "write_in_worktree" : "write_outside_repo";
4883
4883
  }
4884
4884
 
4885
+ // src/agents/run-sandbox-launcher.ts
4886
+ import { spawn } from "node:child_process";
4887
+ import { isIP } from "node:net";
4888
+ import { isAbsolute as isAbsolute2 } from "node:path";
4889
+ import { fileURLToPath } from "node:url";
4890
+ import { NetworkConfigSchema } from "@anthropic-ai/sandbox-runtime";
4891
+ var MAX_PENDING_NETWORK = 128;
4892
+ var NETWORK_DECISION_MS = 5 * 6e4;
4893
+ function canonicalHost(host) {
4894
+ if (!host || /[\s\x00-\x1f\x7f%\\/@?#*]/u.test(host)) return;
4895
+ const bare = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
4896
+ if (isIP(bare) === 6) return new URL(`http://[${bare}]`).hostname.slice(1, -1);
4897
+ if (bare.includes(":")) return;
4898
+ try {
4899
+ return new URL(`http://${bare}`).hostname.toLowerCase();
4900
+ } catch {
4901
+ return void 0;
4902
+ }
4903
+ }
4904
+ function matchesRunSandboxDomain(request, domains) {
4905
+ const host = canonicalHost(request.host);
4906
+ if (!host || !Number.isInteger(request.port) || request.port < 1 || request.port > 65535) return false;
4907
+ return domains.some((entry) => {
4908
+ if (entry === "*") return true;
4909
+ const parts = /^(\[[^\]]+\]|[^:]+?)(?::([1-9][0-9]{0,4}))?$/u.exec(entry);
4910
+ if (!parts || parts[2] !== void 0 && (Number(parts[2]) > 65535 || Number(parts[2]) !== request.port)) return false;
4911
+ const wildcard = parts[1].startsWith("*.");
4912
+ const pattern = canonicalHost(wildcard ? parts[1].slice(2) : parts[1]);
4913
+ if (!pattern) return false;
4914
+ if (!wildcard) return host === pattern;
4915
+ return !isIP(host) && pattern.includes(".") && host.endsWith(`.${pattern}`);
4916
+ });
4917
+ }
4918
+ function signalGroup(pid, signal) {
4919
+ if (pid === void 0) return;
4920
+ try {
4921
+ process.kill(-pid, signal);
4922
+ } catch (error) {
4923
+ if (error.code !== "ESRCH") throw error;
4924
+ }
4925
+ }
4926
+ function spawnRunSandbox(options) {
4927
+ if (process.platform !== "linux" && process.platform !== "darwin") {
4928
+ throw new Error("run sandbox launcher requires Linux or macOS process groups");
4929
+ }
4930
+ if (!options.command || options.command.includes("\0") || !isAbsolute2(options.cwd)) {
4931
+ throw new Error("run sandbox requires a command and absolute cwd");
4932
+ }
4933
+ if (options.authToken !== void 0 && (!options.authToken || Buffer.byteLength(options.authToken) > 1048576)) {
4934
+ throw new Error("invalid run sandbox auth pipe payload length");
4935
+ }
4936
+ const maximum = Object.freeze([...options.maxAllowDomains]);
4937
+ const modelApiDomains = Object.freeze([...options.modelApiDomains ?? []]);
4938
+ NetworkConfigSchema.parse({ allowedDomains: maximum.filter((entry) => entry !== "*"), deniedDomains: [] });
4939
+ NetworkConfigSchema.parse({ allowedDomains: [...modelApiDomains], deniedDomains: [] });
4940
+ const onNetwork = options.onNetwork;
4941
+ const abortSignal = options.signal;
4942
+ const launch = {
4943
+ type: "init",
4944
+ command: options.command,
4945
+ args: [...options.args],
4946
+ cwd: options.cwd,
4947
+ env: { ...options.env },
4948
+ policy: {
4949
+ allowWrite: [...options.policy.allowWrite],
4950
+ denyWrite: [...options.policy.denyWrite ?? []],
4951
+ denyRead: [...options.policy.denyRead ?? []]
4952
+ },
4953
+ maxAllowDomains: [...maximum],
4954
+ modelApiDomains: [...modelApiDomains],
4955
+ hasAuthToken: options.authToken !== void 0
4956
+ };
4957
+ const child = spawn(process.execPath, [fileURLToPath(new URL("./run-sandbox-worker.mjs", import.meta.url))], {
4958
+ // Runtime helpers use the trusted daemon's environment. CLI env arrives
4959
+ // over IPC and is passed explicitly by the worker, without inheritance.
4960
+ env: process.env,
4961
+ cwd: options.cwd,
4962
+ stdio: ["pipe", "pipe", "pipe", "pipe", "ipc"],
4963
+ detached: true
4964
+ });
4965
+ const lifetime = new AbortController();
4966
+ const pending = /* @__PURE__ */ new Map();
4967
+ let stderr = "";
4968
+ let stopped = false;
4969
+ let gone = false;
4970
+ let outcome;
4971
+ let hardStop;
4972
+ let settle;
4973
+ const exited = new Promise((resolve13) => {
4974
+ settle = resolve13;
4975
+ });
4976
+ function send(message) {
4977
+ if (!child.connected || gone) return;
4978
+ child.send(message, (error) => {
4979
+ if (error) stop(0);
4980
+ });
4981
+ }
4982
+ function stop(graceMs = 3e3) {
4983
+ if (gone) return;
4984
+ if (!stopped) {
4985
+ stopped = true;
4986
+ lifetime.abort();
4987
+ for (const request of pending.values()) {
4988
+ clearTimeout(request.timer);
4989
+ request.controller.abort();
4990
+ }
4991
+ pending.clear();
4992
+ send({ type: "stop", graceMs });
4993
+ }
4994
+ if (!hardStop) hardStop = setTimeout(() => {
4995
+ stderr += "\nrun sandbox worker did not stop; terminating its process group";
4996
+ try {
4997
+ signalGroup(child.pid, "SIGKILL");
4998
+ } catch (error) {
4999
+ stderr += `
5000
+ run sandbox group termination failed: ${String(error)}`;
5001
+ }
5002
+ }, Math.max(0, Math.min(graceMs, 3e4)) + 5e3);
5003
+ }
5004
+ child.stderr.on("data", (data) => {
5005
+ stderr = (stderr + data.toString()).slice(-16e3);
5006
+ });
5007
+ child.stdin.on("error", () => void 0);
5008
+ child.on("message", (message) => {
5009
+ if (!message || typeof message !== "object") return;
5010
+ const value = message;
5011
+ if (value.type === "finished") {
5012
+ if ((value.code === null || Number.isInteger(value.code)) && (value.signal === null || typeof value.signal === "string")) {
5013
+ outcome = { code: value.code, signal: value.signal };
5014
+ }
5015
+ return;
5016
+ }
5017
+ if (value.type !== "network" || !Number.isSafeInteger(value.id) || value.id < 1 || pending.has(value.id)) return;
5018
+ const id4 = value.id;
5019
+ const request = {
5020
+ host: typeof value.host === "string" ? value.host : "",
5021
+ port: typeof value.port === "number" ? value.port : 0
5022
+ };
5023
+ if (typeof value.port !== "number" || stopped || lifetime.signal.aborted || pending.size >= MAX_PENDING_NETWORK || !matchesRunSandboxDomain(request, maximum)) {
5024
+ send({ type: "decision", id: id4, allow: false });
5025
+ return;
5026
+ }
5027
+ const controller = new AbortController();
5028
+ const timer = setTimeout(() => {
5029
+ if (!pending.delete(id4)) return;
5030
+ controller.abort();
5031
+ send({ type: "decision", id: id4, allow: false });
5032
+ }, NETWORK_DECISION_MS);
5033
+ pending.set(id4, { controller, timer });
5034
+ void Promise.resolve().then(() => {
5035
+ if (stopped || lifetime.signal.aborted) return false;
5036
+ return onNetwork(request, controller.signal);
5037
+ }).then((allow) => {
5038
+ if (!pending.delete(id4)) return;
5039
+ clearTimeout(timer);
5040
+ send({ type: "decision", id: id4, allow: allow === true && !stopped && !lifetime.signal.aborted && !controller.signal.aborted });
5041
+ }, () => {
5042
+ if (pending.delete(id4)) {
5043
+ clearTimeout(timer);
5044
+ send({ type: "decision", id: id4, allow: false });
5045
+ }
5046
+ });
5047
+ });
5048
+ function onParentExit() {
5049
+ try {
5050
+ signalGroup(child.pid, "SIGKILL");
5051
+ } catch {
5052
+ }
5053
+ }
5054
+ process.once("exit", onParentExit);
5055
+ function finish(code, signal) {
5056
+ if (gone) return;
5057
+ gone = true;
5058
+ stopped = true;
5059
+ lifetime.abort();
5060
+ for (const request of pending.values()) {
5061
+ clearTimeout(request.timer);
5062
+ request.controller.abort();
5063
+ }
5064
+ pending.clear();
5065
+ clearTimeout(hardStop);
5066
+ abortSignal?.removeEventListener("abort", onAbort);
5067
+ process.removeListener("exit", onParentExit);
5068
+ try {
5069
+ signalGroup(child.pid, "SIGKILL");
5070
+ } catch (error) {
5071
+ stderr += `
5072
+ run sandbox group cleanup failed: ${String(error)}`;
5073
+ }
5074
+ settle(outcome ?? { code, signal });
5075
+ }
5076
+ child.once("error", (error) => {
5077
+ stderr += `
5078
+ ${error.message}`;
5079
+ stop(0);
5080
+ if (child.pid === void 0) finish(null, null);
5081
+ });
5082
+ child.once("exit", finish);
5083
+ child.once("disconnect", () => {
5084
+ if (!outcome) stop(0);
5085
+ });
5086
+ const authPipe = child.stdio[3];
5087
+ authPipe.on("error", () => stop(0));
5088
+ authPipe.end(options.authToken);
5089
+ function onAbort() {
5090
+ stop(0);
5091
+ }
5092
+ abortSignal?.addEventListener("abort", onAbort, { once: true });
5093
+ child.kill = (signal = "SIGTERM") => {
5094
+ if (gone) return false;
5095
+ if (signal === 0) {
5096
+ try {
5097
+ process.kill(child.pid, 0);
5098
+ return true;
5099
+ } catch {
5100
+ return false;
5101
+ }
5102
+ }
5103
+ stop(signal === "SIGKILL" ? 0 : 3e3);
5104
+ return true;
5105
+ };
5106
+ Object.defineProperty(child, "killed", { get: () => stopped });
5107
+ if (abortSignal?.aborted) stop(0);
5108
+ else send(launch);
5109
+ return {
5110
+ process: child,
5111
+ exited,
5112
+ stderrTail: () => stderr.slice(-4e3).trim(),
5113
+ async kill(graceMs = 3e3) {
5114
+ stop(graceMs);
5115
+ await exited;
5116
+ },
5117
+ async revoke() {
5118
+ stop(0);
5119
+ await exited;
5120
+ }
5121
+ };
5122
+ }
5123
+
4885
5124
  // src/agents/tool-approval-policy.ts
4886
- function toolApprovalDecision(request, policy, worktree, apps = []) {
5125
+ function toolApprovalDecision(request, policy, worktree, apps = [], runHosts = []) {
4887
5126
  if (request.method === "sandbox/network" && policy) {
4888
5127
  const value = request.input;
4889
5128
  if (!value || typeof value.host !== "string" || /[*/:]/.test(value.host) || !networkDomainSchema.safeParse(value.host).success || !Number.isInteger(value.port) || Number(value.port) < 1 || Number(value.port) > 65535) return "deny";
5129
+ if (policy.permissions.network === "ask" && matchesRunSandboxDomain({ host: value.host, port: Number(value.port) }, [...policy.networkAllow, ...runHosts])) return "allow";
4890
5130
  return policy.permissions.network;
4891
5131
  }
4892
5132
  if (request.method.startsWith("cli/") && policy && worktree) {
@@ -5249,7 +5489,13 @@ var HttpServerLink = class {
5249
5489
  const response = z26.object({ decision: z26.enum(["pending", "allow", "deny"]) });
5250
5490
  const liveness = new AbortController();
5251
5491
  const gate = new ToolApprovalGate(assignment.runId, {
5252
- permission: (request) => toolApprovalDecision(request, assignment.policy, worktree, runApps(assignment.mcp)?.apps.map((app) => app.name)),
5492
+ permission: (request) => toolApprovalDecision(
5493
+ request,
5494
+ assignment.policy,
5495
+ worktree,
5496
+ runApps(assignment.mcp)?.apps.map((app) => app.name),
5497
+ assignment.github ? [new URL(assignment.github.endpoint).host] : []
5498
+ ),
5253
5499
  // Keep the callback pending at the tool boundary. The adapter's current
5254
5500
  // session and checkpoint remain intact; handback resolves this same call.
5255
5501
  isLive: async () => {
@@ -5755,7 +6001,7 @@ function buildChildEnv(options = {}) {
5755
6001
  }
5756
6002
 
5757
6003
  // src/agents/child.ts
5758
- import { spawn } from "node:child_process";
6004
+ import { spawn as spawn2 } from "node:child_process";
5759
6005
  import {
5760
6006
  mkdirSync as mkdirSync4,
5761
6007
  readFileSync as readFileSync3,
@@ -5920,7 +6166,7 @@ function endedSession(sessionId, exit) {
5920
6166
  };
5921
6167
  }
5922
6168
  var STDERR_TAIL = 4e3;
5923
- function signalGroup(pgid, signal) {
6169
+ function signalGroup2(pgid, signal) {
5924
6170
  if (pgid === void 0) return;
5925
6171
  try {
5926
6172
  process.kill(-pgid, signal);
@@ -5942,7 +6188,7 @@ async function reapStale(pidFile2, marker) {
5942
6188
  const [group, ...command] = line.trim().split(/\s+/);
5943
6189
  return Number(group) === pgid && command.join(" ").includes(marker);
5944
6190
  });
5945
- if (member) signalGroup(pgid, "SIGKILL");
6191
+ if (member) signalGroup2(pgid, "SIGKILL");
5946
6192
  }
5947
6193
  async function claimRunDir(paths) {
5948
6194
  ownDir(paths.runDir);
@@ -5953,7 +6199,7 @@ async function claimRunDir(paths) {
5953
6199
  async function spawnCli(sandbox, argv, options) {
5954
6200
  await reapStale(options.pidFile, options.marker);
5955
6201
  const wrapped = await sandbox.wrap(argv, options.policy);
5956
- const child = spawn("/bin/sh", ["-c", wrapped.command], {
6202
+ const child = spawn2("/bin/sh", ["-c", wrapped.command], {
5957
6203
  cwd: options.cwd,
5958
6204
  env: options.env,
5959
6205
  stdio: ["pipe", "pipe", "pipe"],
@@ -5980,7 +6226,7 @@ ${error.message}`;
5980
6226
  child.once("exit", (code, signal) => resolve13({ code, signal }));
5981
6227
  }
5982
6228
  ).finally(() => {
5983
- signalGroup(pgid, "SIGKILL");
6229
+ signalGroup2(pgid, "SIGKILL");
5984
6230
  rmSync3(options.pidFile, { force: true });
5985
6231
  wrapped.release();
5986
6232
  });
@@ -5990,7 +6236,7 @@ ${error.message}`;
5990
6236
  exited,
5991
6237
  stderrTail: () => wrapped.annotate(stderr.slice(-STDERR_TAIL)).trim(),
5992
6238
  async kill(graceMs = 3e3) {
5993
- signalGroup(pgid, "SIGTERM");
6239
+ signalGroup2(pgid, "SIGTERM");
5994
6240
  let timer;
5995
6241
  await Promise.race([
5996
6242
  exited,
@@ -5999,7 +6245,7 @@ ${error.message}`;
5999
6245
  })
6000
6246
  ]);
6001
6247
  clearTimeout(timer);
6002
- signalGroup(pgid, "SIGKILL");
6248
+ signalGroup2(pgid, "SIGKILL");
6003
6249
  await exited;
6004
6250
  }
6005
6251
  };
@@ -6154,7 +6400,7 @@ import {
6154
6400
  rmSync as rmSync4
6155
6401
  } from "node:fs";
6156
6402
  import { lstat, readdir } from "node:fs/promises";
6157
- import { dirname as dirname6, isAbsolute as isAbsolute2, join as join7, relative as relative2, resolve as resolve4 } from "node:path";
6403
+ import { dirname as dirname6, isAbsolute as isAbsolute3, join as join7, relative as relative2, resolve as resolve4 } from "node:path";
6158
6404
  import { execa as execa2 } from "execa";
6159
6405
  import { simpleGit } from "simple-git";
6160
6406
  var DISK_USAGE_TTL_MS = 5 * 6e4;
@@ -6172,7 +6418,7 @@ function runBranch(runId) {
6172
6418
  }
6173
6419
  function isInside(parent, child) {
6174
6420
  const rel = relative2(parent, child);
6175
- return rel === "" || !rel.startsWith("..") && !isAbsolute2(rel);
6421
+ return rel === "" || !rel.startsWith("..") && !isAbsolute3(rel);
6176
6422
  }
6177
6423
  var configWriters = /* @__PURE__ */ new Map();
6178
6424
  function withRepoConfig(repoPath, work) {
@@ -6310,7 +6556,7 @@ var WorktreeManager = class {
6310
6556
  const worktreeReal = realpathSync4(worktree);
6311
6557
  for (const file of recipe.copyFiles) {
6312
6558
  const rel = relative2(repoPath, resolve4(repoPath, file));
6313
- if (rel === "" || rel.startsWith("..") || isAbsolute2(rel)) {
6559
+ if (rel === "" || rel.startsWith("..") || isAbsolute3(rel)) {
6314
6560
  throw new Error(`setup recipe copies a file outside the repo: ${file}`);
6315
6561
  }
6316
6562
  const from = join7(repoPath, rel);
@@ -7819,245 +8065,6 @@ import {
7819
8065
  createSdkMcpServer as createSdkMcpServer2
7820
8066
  } from "@anthropic-ai/claude-agent-sdk";
7821
8067
 
7822
- // src/agents/run-sandbox-launcher.ts
7823
- import { spawn as spawn2 } from "node:child_process";
7824
- import { isIP } from "node:net";
7825
- import { isAbsolute as isAbsolute3 } from "node:path";
7826
- import { fileURLToPath } from "node:url";
7827
- import { NetworkConfigSchema } from "@anthropic-ai/sandbox-runtime";
7828
- var MAX_PENDING_NETWORK = 128;
7829
- var NETWORK_DECISION_MS = 5 * 6e4;
7830
- function canonicalHost(host) {
7831
- if (!host || /[\s\x00-\x1f\x7f%\\/@?#*]/u.test(host)) return;
7832
- const bare = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
7833
- if (isIP(bare) === 6) return new URL(`http://[${bare}]`).hostname.slice(1, -1);
7834
- if (bare.includes(":")) return;
7835
- try {
7836
- return new URL(`http://${bare}`).hostname.toLowerCase();
7837
- } catch {
7838
- return void 0;
7839
- }
7840
- }
7841
- function matchesRunSandboxDomain(request, domains) {
7842
- const host = canonicalHost(request.host);
7843
- if (!host || !Number.isInteger(request.port) || request.port < 1 || request.port > 65535) return false;
7844
- return domains.some((entry) => {
7845
- if (entry === "*") return true;
7846
- const parts = /^(\[[^\]]+\]|[^:]+?)(?::([1-9][0-9]{0,4}))?$/u.exec(entry);
7847
- if (!parts || parts[2] !== void 0 && (Number(parts[2]) > 65535 || Number(parts[2]) !== request.port)) return false;
7848
- const wildcard = parts[1].startsWith("*.");
7849
- const pattern = canonicalHost(wildcard ? parts[1].slice(2) : parts[1]);
7850
- if (!pattern) return false;
7851
- if (!wildcard) return host === pattern;
7852
- return !isIP(host) && pattern.includes(".") && host.endsWith(`.${pattern}`);
7853
- });
7854
- }
7855
- function signalGroup2(pid, signal) {
7856
- if (pid === void 0) return;
7857
- try {
7858
- process.kill(-pid, signal);
7859
- } catch (error) {
7860
- if (error.code !== "ESRCH") throw error;
7861
- }
7862
- }
7863
- function spawnRunSandbox(options) {
7864
- if (process.platform !== "linux" && process.platform !== "darwin") {
7865
- throw new Error("run sandbox launcher requires Linux or macOS process groups");
7866
- }
7867
- if (!options.command || options.command.includes("\0") || !isAbsolute3(options.cwd)) {
7868
- throw new Error("run sandbox requires a command and absolute cwd");
7869
- }
7870
- if (options.authToken !== void 0 && (!options.authToken || Buffer.byteLength(options.authToken) > 1048576)) {
7871
- throw new Error("invalid run sandbox auth pipe payload length");
7872
- }
7873
- const maximum = Object.freeze([...options.maxAllowDomains]);
7874
- const modelApiDomains = Object.freeze([...options.modelApiDomains ?? []]);
7875
- NetworkConfigSchema.parse({ allowedDomains: maximum.filter((entry) => entry !== "*"), deniedDomains: [] });
7876
- NetworkConfigSchema.parse({ allowedDomains: [...modelApiDomains], deniedDomains: [] });
7877
- const onNetwork = options.onNetwork;
7878
- const abortSignal = options.signal;
7879
- const launch = {
7880
- type: "init",
7881
- command: options.command,
7882
- args: [...options.args],
7883
- cwd: options.cwd,
7884
- env: { ...options.env },
7885
- policy: {
7886
- allowWrite: [...options.policy.allowWrite],
7887
- denyWrite: [...options.policy.denyWrite ?? []],
7888
- denyRead: [...options.policy.denyRead ?? []]
7889
- },
7890
- maxAllowDomains: [...maximum],
7891
- modelApiDomains: [...modelApiDomains],
7892
- hasAuthToken: options.authToken !== void 0
7893
- };
7894
- const child = spawn2(process.execPath, [fileURLToPath(new URL("./run-sandbox-worker.mjs", import.meta.url))], {
7895
- // Runtime helpers use the trusted daemon's environment. CLI env arrives
7896
- // over IPC and is passed explicitly by the worker, without inheritance.
7897
- env: process.env,
7898
- cwd: options.cwd,
7899
- stdio: ["pipe", "pipe", "pipe", "pipe", "ipc"],
7900
- detached: true
7901
- });
7902
- const lifetime = new AbortController();
7903
- const pending = /* @__PURE__ */ new Map();
7904
- let stderr = "";
7905
- let stopped = false;
7906
- let gone = false;
7907
- let outcome;
7908
- let hardStop;
7909
- let settle;
7910
- const exited = new Promise((resolve13) => {
7911
- settle = resolve13;
7912
- });
7913
- function send(message) {
7914
- if (!child.connected || gone) return;
7915
- child.send(message, (error) => {
7916
- if (error) stop(0);
7917
- });
7918
- }
7919
- function stop(graceMs = 3e3) {
7920
- if (gone) return;
7921
- if (!stopped) {
7922
- stopped = true;
7923
- lifetime.abort();
7924
- for (const request of pending.values()) {
7925
- clearTimeout(request.timer);
7926
- request.controller.abort();
7927
- }
7928
- pending.clear();
7929
- send({ type: "stop", graceMs });
7930
- }
7931
- if (!hardStop) hardStop = setTimeout(() => {
7932
- stderr += "\nrun sandbox worker did not stop; terminating its process group";
7933
- try {
7934
- signalGroup2(child.pid, "SIGKILL");
7935
- } catch (error) {
7936
- stderr += `
7937
- run sandbox group termination failed: ${String(error)}`;
7938
- }
7939
- }, Math.max(0, Math.min(graceMs, 3e4)) + 5e3);
7940
- }
7941
- child.stderr.on("data", (data) => {
7942
- stderr = (stderr + data.toString()).slice(-16e3);
7943
- });
7944
- child.stdin.on("error", () => void 0);
7945
- child.on("message", (message) => {
7946
- if (!message || typeof message !== "object") return;
7947
- const value = message;
7948
- if (value.type === "finished") {
7949
- if ((value.code === null || Number.isInteger(value.code)) && (value.signal === null || typeof value.signal === "string")) {
7950
- outcome = { code: value.code, signal: value.signal };
7951
- }
7952
- return;
7953
- }
7954
- if (value.type !== "network" || !Number.isSafeInteger(value.id) || value.id < 1 || pending.has(value.id)) return;
7955
- const id4 = value.id;
7956
- const request = {
7957
- host: typeof value.host === "string" ? value.host : "",
7958
- port: typeof value.port === "number" ? value.port : 0
7959
- };
7960
- if (typeof value.port !== "number" || stopped || lifetime.signal.aborted || pending.size >= MAX_PENDING_NETWORK || !matchesRunSandboxDomain(request, maximum)) {
7961
- send({ type: "decision", id: id4, allow: false });
7962
- return;
7963
- }
7964
- const controller = new AbortController();
7965
- const timer = setTimeout(() => {
7966
- if (!pending.delete(id4)) return;
7967
- controller.abort();
7968
- send({ type: "decision", id: id4, allow: false });
7969
- }, NETWORK_DECISION_MS);
7970
- pending.set(id4, { controller, timer });
7971
- void Promise.resolve().then(() => {
7972
- if (stopped || lifetime.signal.aborted) return false;
7973
- return onNetwork(request, controller.signal);
7974
- }).then((allow) => {
7975
- if (!pending.delete(id4)) return;
7976
- clearTimeout(timer);
7977
- send({ type: "decision", id: id4, allow: allow === true && !stopped && !lifetime.signal.aborted && !controller.signal.aborted });
7978
- }, () => {
7979
- if (pending.delete(id4)) {
7980
- clearTimeout(timer);
7981
- send({ type: "decision", id: id4, allow: false });
7982
- }
7983
- });
7984
- });
7985
- function onParentExit() {
7986
- try {
7987
- signalGroup2(child.pid, "SIGKILL");
7988
- } catch {
7989
- }
7990
- }
7991
- process.once("exit", onParentExit);
7992
- function finish(code, signal) {
7993
- if (gone) return;
7994
- gone = true;
7995
- stopped = true;
7996
- lifetime.abort();
7997
- for (const request of pending.values()) {
7998
- clearTimeout(request.timer);
7999
- request.controller.abort();
8000
- }
8001
- pending.clear();
8002
- clearTimeout(hardStop);
8003
- abortSignal?.removeEventListener("abort", onAbort);
8004
- process.removeListener("exit", onParentExit);
8005
- try {
8006
- signalGroup2(child.pid, "SIGKILL");
8007
- } catch (error) {
8008
- stderr += `
8009
- run sandbox group cleanup failed: ${String(error)}`;
8010
- }
8011
- settle(outcome ?? { code, signal });
8012
- }
8013
- child.once("error", (error) => {
8014
- stderr += `
8015
- ${error.message}`;
8016
- stop(0);
8017
- if (child.pid === void 0) finish(null, null);
8018
- });
8019
- child.once("exit", finish);
8020
- child.once("disconnect", () => {
8021
- if (!outcome) stop(0);
8022
- });
8023
- const authPipe = child.stdio[3];
8024
- authPipe.on("error", () => stop(0));
8025
- authPipe.end(options.authToken);
8026
- function onAbort() {
8027
- stop(0);
8028
- }
8029
- abortSignal?.addEventListener("abort", onAbort, { once: true });
8030
- child.kill = (signal = "SIGTERM") => {
8031
- if (gone) return false;
8032
- if (signal === 0) {
8033
- try {
8034
- process.kill(child.pid, 0);
8035
- return true;
8036
- } catch {
8037
- return false;
8038
- }
8039
- }
8040
- stop(signal === "SIGKILL" ? 0 : 3e3);
8041
- return true;
8042
- };
8043
- Object.defineProperty(child, "killed", { get: () => stopped });
8044
- if (abortSignal?.aborted) stop(0);
8045
- else send(launch);
8046
- return {
8047
- process: child,
8048
- exited,
8049
- stderrTail: () => stderr.slice(-4e3).trim(),
8050
- async kill(graceMs = 3e3) {
8051
- stop(graceMs);
8052
- await exited;
8053
- },
8054
- async revoke() {
8055
- stop(0);
8056
- await exited;
8057
- }
8058
- };
8059
- }
8060
-
8061
8068
  // src/agents/run-network.ts
8062
8069
  function runNetworkApproval(runId, harness, gate, maximum, localComputerEndpoint, appHost) {
8063
8070
  if (gate.runId !== runId) throw new Error("Run approval scope mismatch");
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@aspectlylabs/mikka",
3
- "version": "0.0.156",
3
+ "version": "0.0.158",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@aspectlylabs/mikka",
9
- "version": "0.0.156",
9
+ "version": "0.0.158",
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.156",
3
+ "version": "0.0.158",
4
4
  "description": "Local Mikka daemon: runs agents through the user's own CLIs",
5
- "gitHead": "3fe02256b52ef29ce2581173987f01d3b2054448",
5
+ "gitHead": "5011b7faac02b82a863d07eba4d7180d47fccc2b",
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.156",
9
+ version: "0.0.158",
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: "3fe02256b52ef29ce2581173987f01d3b2054448"
69
+ gitHead: "5011b7faac02b82a863d07eba4d7180d47fccc2b"
70
70
  };
71
71
 
72
72
  // src/paths.ts