@aspectlylabs/mikka 0.0.86 → 0.0.87

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/main.js CHANGED
@@ -878,10 +878,10 @@ var require_truncate = __commonJS({
878
878
  "../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/truncate.js"(exports, module) {
879
879
  "use strict";
880
880
  var parse2 = require_parse();
881
- var constants3 = require_constants();
881
+ var constants4 = require_constants();
882
882
  var SemVer = require_semver();
883
883
  var truncate = (version, truncation, options) => {
884
- if (!constants3.RELEASE_TYPES.includes(truncation)) {
884
+ if (!constants4.RELEASE_TYPES.includes(truncation)) {
885
885
  return null;
886
886
  }
887
887
  const clonedVersion = cloneInputVersion(version, options);
@@ -1930,7 +1930,7 @@ var require_semver2 = __commonJS({
1930
1930
  "../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/index.js"(exports, module) {
1931
1931
  "use strict";
1932
1932
  var internalRe = require_re();
1933
- var constants3 = require_constants();
1933
+ var constants4 = require_constants();
1934
1934
  var SemVer = require_semver();
1935
1935
  var identifiers = require_identifiers();
1936
1936
  var parse2 = require_parse();
@@ -2014,8 +2014,8 @@ var require_semver2 = __commonJS({
2014
2014
  re: internalRe.re,
2015
2015
  src: internalRe.src,
2016
2016
  tokens: internalRe.t,
2017
- SEMVER_SPEC_VERSION: constants3.SEMVER_SPEC_VERSION,
2018
- RELEASE_TYPES: constants3.RELEASE_TYPES,
2017
+ SEMVER_SPEC_VERSION: constants4.SEMVER_SPEC_VERSION,
2018
+ RELEASE_TYPES: constants4.RELEASE_TYPES,
2019
2019
  compareIdentifiers: identifiers.compareIdentifiers,
2020
2020
  rcompareIdentifiers: identifiers.rcompareIdentifiers
2021
2021
  };
@@ -3748,7 +3748,7 @@ import { join as join5 } from "node:path";
3748
3748
  // package.json
3749
3749
  var package_default = {
3750
3750
  name: "@mikka/daemon",
3751
- version: "0.0.86",
3751
+ version: "0.0.87",
3752
3752
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
3753
3753
  type: "module",
3754
3754
  private: true,
@@ -3807,7 +3807,7 @@ var package_default = {
3807
3807
  engines: {
3808
3808
  node: ">=24"
3809
3809
  },
3810
- gitHead: "da9593f91f3620f251d08a7260322a52cf39d23a"
3810
+ gitHead: "f2ef942a44623501b27027f8926e0666a640bcfe"
3811
3811
  };
3812
3812
 
3813
3813
  // src/paths.ts
@@ -4347,6 +4347,12 @@ var harnessInfoSchema = z12.object({
4347
4347
  computerBroker: z12.literal(true).optional(),
4348
4348
  /** Run-scoped CLI approvals and policy-version checks are supported. */
4349
4349
  toolApproval: z12.literal(true).optional(),
4350
+ /**
4351
+ * The CLI exists but `installed` stays false because the daemon cannot run it
4352
+ * in a sandbox. `missing` names the absent packages; empty means the machine
4353
+ * itself refused isolation.
4354
+ */
4355
+ sandboxBlocked: z12.object({ missing: z12.array(z12.string().trim().min(1).max(64)).max(8) }).optional(),
4350
4356
  /** Version string reported by the CLI, null when not installed. */
4351
4357
  version: z12.string().nullable()
4352
4358
  });
@@ -5862,6 +5868,7 @@ var RunContext = class {
5862
5868
  ],
5863
5869
  allowDomains: [
5864
5870
  ...HARNESS_DOMAINS[this.options.harness],
5871
+ ...this.options.harnessDomains ?? [],
5865
5872
  ...runAppsHost(this.options.apps) ? [runAppsHost(this.options.apps)] : [],
5866
5873
  ...runDomains(
5867
5874
  runPolicy(this.options.policy),
@@ -6385,15 +6392,15 @@ sandbox_mode = "read-only"
6385
6392
  // src/main.ts
6386
6393
  import { randomBytes as randomBytes3, randomUUID as randomUUID9 } from "node:crypto";
6387
6394
  import {
6388
- chmodSync as chmodSync4,
6389
- existsSync as existsSync7,
6390
- mkdirSync as mkdirSync16,
6391
- readFileSync as readFileSync11,
6392
- rmSync as rmSync17,
6395
+ chmodSync as chmodSync5,
6396
+ existsSync as existsSync8,
6397
+ mkdirSync as mkdirSync17,
6398
+ readFileSync as readFileSync12,
6399
+ rmSync as rmSync18,
6393
6400
  realpathSync as realpathSync13
6394
6401
  } from "node:fs";
6395
6402
  import { arch, hostname, platform as platform2 } from "node:os";
6396
- import { join as join28 } from "node:path";
6403
+ import { join as join32 } from "node:path";
6397
6404
  import { fileURLToPath as fileURLToPath3 } from "node:url";
6398
6405
 
6399
6406
  // src/adapters/claude.ts
@@ -6419,7 +6426,52 @@ function computerSandboxPolicy(policy, spec) {
6419
6426
  import { randomUUID as randomUUID2 } from "node:crypto";
6420
6427
  import { realpathSync as realpathSync8 } from "node:fs";
6421
6428
  import { homedir as homedir4 } from "node:os";
6422
- import { join as join11 } from "node:path";
6429
+
6430
+ // src/adapters/claude-gateway.ts
6431
+ import { readFileSync as readFileSync8 } from "node:fs";
6432
+ import { join as join10 } from "node:path";
6433
+ var GATEWAY_ENV = [
6434
+ "ANTHROPIC_BASE_URL",
6435
+ "ANTHROPIC_AUTH_TOKEN",
6436
+ "ANTHROPIC_API_KEY",
6437
+ "ANTHROPIC_MODEL",
6438
+ "ANTHROPIC_DEFAULT_FABLE_MODEL",
6439
+ "ANTHROPIC_DEFAULT_OPUS_MODEL",
6440
+ "ANTHROPIC_DEFAULT_SONNET_MODEL",
6441
+ "ANTHROPIC_DEFAULT_HAIKU_MODEL",
6442
+ "CLAUDE_CODE_SUBAGENT_MODEL"
6443
+ ];
6444
+ function readClaudeGateway(configDir) {
6445
+ let settings;
6446
+ try {
6447
+ settings = JSON.parse(readFileSync8(join10(configDir, "settings.json"), "utf8"));
6448
+ } catch {
6449
+ return null;
6450
+ }
6451
+ const declared = settings?.env;
6452
+ if (!declared || typeof declared !== "object") return null;
6453
+ const values = declared;
6454
+ const domain = gatewayDomain(values.ANTHROPIC_BASE_URL);
6455
+ if (!domain) return null;
6456
+ const env = {};
6457
+ for (const name of GATEWAY_ENV) {
6458
+ const value = values[name];
6459
+ if (typeof value === "string" && value) env[name] = value;
6460
+ }
6461
+ return { env, domain };
6462
+ }
6463
+ function gatewayDomain(baseUrl) {
6464
+ if (typeof baseUrl !== "string") return null;
6465
+ try {
6466
+ const url = new URL(baseUrl);
6467
+ return url.protocol === "https:" || url.protocol === "http:" ? url.hostname : null;
6468
+ } catch {
6469
+ return null;
6470
+ }
6471
+ }
6472
+
6473
+ // src/adapters/claude.ts
6474
+ import { join as join12 } from "node:path";
6423
6475
  import {
6424
6476
  query as query2,
6425
6477
  createSdkMcpServer as createSdkMcpServer2
@@ -6715,15 +6767,15 @@ function mailboxToolResult(result) {
6715
6767
  // src/subscription-native-broker.ts
6716
6768
  import { chmodSync, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync4, rmSync as rmSync9 } from "node:fs";
6717
6769
  import { createServer } from "node:http";
6718
- import { join as join10 } from "node:path";
6770
+ import { join as join11 } from "node:path";
6719
6771
  import { once } from "node:events";
6720
6772
  var NATIVE_AUTH_PLACEHOLDER = "mikka-native-broker-placeholder";
6721
6773
  async function createNativeSubscriptionBroker(host) {
6722
6774
  await host.check();
6723
6775
  mkdirSync9(host.root, { recursive: true, mode: 448 });
6724
- const dir = mkdtempSync4(join10(host.root, "native-broker-"));
6776
+ const dir = mkdtempSync4(join11(host.root, "native-broker-"));
6725
6777
  chmodSync(dir, 448);
6726
- const socket = join10(dir, "broker.sock");
6778
+ const socket = join11(dir, "broker.sock");
6727
6779
  const pending = /* @__PURE__ */ new Set();
6728
6780
  let halted = false;
6729
6781
  const server = createServer(async (request, response) => {
@@ -7077,10 +7129,12 @@ var ClaudeAdapter = class {
7077
7129
  throw new Error(SUBSCRIPTION_ERROR);
7078
7130
  }
7079
7131
  }
7080
- const nativeHome = externalAuth ? join11(runDir, "native-home") : void 0;
7081
- const configDir = nativeHome ? join11(nativeHome, ".claude") : this.options.configDir ?? join11(homedir4(), ".claude");
7132
+ const nativeHome = externalAuth ? join12(runDir, "native-home") : void 0;
7133
+ const configDir = nativeHome ? join12(nativeHome, ".claude") : this.options.configDir ?? join12(homedir4(), ".claude");
7082
7134
  if (nativeHome) ownDir(configDir);
7135
+ const gateway = nativeHome || externalAuth ? null : readClaudeGateway(configDir);
7083
7136
  const ctx = new RunContext({
7137
+ harnessDomains: gateway ? [gateway.domain] : void 0,
7084
7138
  github: options.github,
7085
7139
  apps: options.apps,
7086
7140
  githubRuntime: options.githubRuntime,
@@ -7099,8 +7153,8 @@ var ClaudeAdapter = class {
7099
7153
  privateDir: paths.privateDir,
7100
7154
  // Its session store, so `resume` works; keyed by the cwd it sees.
7101
7155
  extraWrite: [
7102
- join11(configDir, "projects", claudeProjectDirName(options.cwd)),
7103
- join11(
7156
+ join12(configDir, "projects", claudeProjectDirName(options.cwd)),
7157
+ join12(
7104
7158
  configDir,
7105
7159
  "projects",
7106
7160
  claudeProjectDirName(realpathSync8(options.cwd))
@@ -7159,6 +7213,7 @@ var ClaudeAdapter = class {
7159
7213
  ...options.env,
7160
7214
  ...ctx.tempEnv(),
7161
7215
  ...CLAUDE_RUN_ENV,
7216
+ ...gateway?.env,
7162
7217
  CLAUDE_CODE_TMPDIR: ctx.tmpDir,
7163
7218
  ...nativeHome ? {
7164
7219
  HOME: nativeHome,
@@ -7345,7 +7400,26 @@ var ClaudeAdapter = class {
7345
7400
  };
7346
7401
 
7347
7402
  // src/adapters/codex.ts
7348
- import { isAbsolute as isAbsolute4, join as join12, relative as relative3 } from "node:path";
7403
+ import { isAbsolute as isAbsolute4, join as join13, relative as relative3 } from "node:path";
7404
+
7405
+ // src/adapters/codex-version.ts
7406
+ var VERSION = /(?:^|[ /])(\d+)\.(\d+)\.(\d+)(?:$|[ ();])/;
7407
+ var MINIMUM_APPROVAL_VERSION = [0, 162, 0];
7408
+ var AUDITED_DYNAMIC_TOOLS = "0.163.0";
7409
+ function codexSupportsRunApproval(version) {
7410
+ const match = VERSION.exec(version ?? "");
7411
+ if (!match) return false;
7412
+ for (const [index, minimum] of MINIMUM_APPROVAL_VERSION.entries()) {
7413
+ const part = Number(match[index + 1]);
7414
+ if (part !== minimum) return part > minimum;
7415
+ }
7416
+ return true;
7417
+ }
7418
+ function codexHasAuditedDynamicTools(version) {
7419
+ return VERSION.exec(version ?? "")?.slice(1).join(".") === AUDITED_DYNAMIC_TOOLS;
7420
+ }
7421
+
7422
+ // src/adapters/codex.ts
7349
7423
  var SUBSCRIPTION_AUTH_ERROR = "Codex subscription authentication unavailable";
7350
7424
  var SUBSCRIPTION_EXECUTION_ERROR2 = "Codex subscription execution failed";
7351
7425
  function subscriptionTokens(value, accountId) {
@@ -7514,8 +7588,8 @@ var CodexAdapter = class {
7514
7588
  options.continueSession.runId
7515
7589
  ).runDir;
7516
7590
  carryHistory(
7517
- join12(earlier2, "codex-home"),
7518
- join12(runDir, "codex-home"),
7591
+ join13(earlier2, "codex-home"),
7592
+ join13(runDir, "codex-home"),
7519
7593
  CODEX_HISTORY
7520
7594
  );
7521
7595
  } catch (error) {
@@ -7527,7 +7601,7 @@ var CodexAdapter = class {
7527
7601
  }
7528
7602
  }
7529
7603
  const codexHome = prepareCodexHome(
7530
- join12(runDir, "codex-home"),
7604
+ join13(runDir, "codex-home"),
7531
7605
  log,
7532
7606
  this.options.userHome,
7533
7607
  !externalAuth
@@ -7866,7 +7940,8 @@ var CodexAdapter = class {
7866
7940
  }),
7867
7941
  "initialize"
7868
7942
  );
7869
- if ((options.mailbox || !rawCliShellAvailable(runPolicy(options.policy))) && !/(?:^|[ /])0\.163\.0(?:$|[ ();])/.test(initialized.userAgent ?? "")) throw new Error("Run permissions require the audited Codex0.163.0 tool interface");
7943
+ if (options.mailbox && !codexHasAuditedDynamicTools(initialized.userAgent)) throw new Error("Run permissions require the audited Codex0.163.0 tool interface");
7944
+ if (!codexSupportsRunApproval(initialized.userAgent)) throw new Error("This Codex version is too old for Mikka; update Codex");
7870
7945
  await rpc.sendNotification("initialized");
7871
7946
  if (externalAuth) {
7872
7947
  try {
@@ -7979,7 +8054,7 @@ var CodexAdapter = class {
7979
8054
  // src/adapters/cursor.ts
7980
8055
  import { Readable, Writable } from "node:stream";
7981
8056
  import * as acp from "@agentclientprotocol/sdk";
7982
- import { join as join13 } from "node:path";
8057
+ import { join as join14 } from "node:path";
7983
8058
  function acpPermissionResponse(params, policy) {
7984
8059
  const pick = (kinds) => {
7985
8060
  for (const kind of kinds) {
@@ -8114,15 +8189,15 @@ var CursorAdapter = class {
8114
8189
  options.continueSession.runId
8115
8190
  ).runDir;
8116
8191
  carryHistory(
8117
- join13(earlier2, "cursor-home"),
8118
- join13(paths.runDir, "cursor-home"),
8192
+ join14(earlier2, "cursor-home"),
8193
+ join14(paths.runDir, "cursor-home"),
8119
8194
  CURSOR_HISTORY
8120
8195
  );
8121
8196
  } catch (error) {
8122
8197
  log.info({ err: error }, "could not copy the earlier cursor chats");
8123
8198
  }
8124
8199
  }
8125
- const configDir = prepareCursorHome(join13(paths.runDir, "cursor-home"));
8200
+ const configDir = prepareCursorHome(join14(paths.runDir, "cursor-home"));
8126
8201
  const ctx = new RunContext({
8127
8202
  github: options.github,
8128
8203
  childPath: options.env.PATH,
@@ -8354,8 +8429,8 @@ ${firstMessage}` : firstMessage
8354
8429
 
8355
8430
  // src/adapters/mock.ts
8356
8431
  import { randomUUID as randomUUID3 } from "node:crypto";
8357
- import { mkdirSync as mkdirSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
8358
- import { dirname as dirname7, join as join14, resolve as resolve6 } from "node:path";
8432
+ import { mkdirSync as mkdirSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
8433
+ import { dirname as dirname7, join as join15, resolve as resolve6 } from "node:path";
8359
8434
  import { setTimeout as sleep } from "node:timers/promises";
8360
8435
  import { execa as execa5 } from "execa";
8361
8436
 
@@ -8411,7 +8486,7 @@ var MockAdapter = class {
8411
8486
  fixturesDir;
8412
8487
  speed;
8413
8488
  stateFile(sessionId) {
8414
- return join14(
8489
+ return join15(
8415
8490
  this.options.stateDir,
8416
8491
  `mock-${assertSafeId("session id", sessionId)}.json`
8417
8492
  );
@@ -8455,7 +8530,7 @@ var MockAdapter = class {
8455
8530
  open(sessionId, state, options) {
8456
8531
  const name = assertSafeId("fixture", state.fixture.replace(/\.jsonl$/, ""));
8457
8532
  const lines = parseFixture(
8458
- readFileSync8(join14(this.fixturesDir, `${name}.jsonl`), "utf8"),
8533
+ readFileSync9(join15(this.fixturesDir, `${name}.jsonl`), "utf8"),
8459
8534
  name
8460
8535
  );
8461
8536
  const abort = new AbortController();
@@ -8569,18 +8644,18 @@ var MockAdapter = class {
8569
8644
 
8570
8645
  // src/agents/verify.ts
8571
8646
  import { mkdirSync as mkdirSync11, mkdtempSync as mkdtempSync5, realpathSync as realpathSync9, rmSync as rmSync10 } from "node:fs";
8572
- import { join as join15 } from "node:path";
8647
+ import { join as join16 } from "node:path";
8573
8648
  var OUTPUT_TAIL = 4e3;
8574
8649
  async function runVerify(sandbox, options) {
8575
8650
  mkdirSync11(options.tmpRoot, { recursive: true, mode: 448 });
8576
- const tmpDir = mkdtempSync5(join15(realpathSync9(options.tmpRoot), "verify-"));
8651
+ const tmpDir = mkdtempSync5(join16(realpathSync9(options.tmpRoot), "verify-"));
8577
8652
  const child = await spawnCli(sandbox, ["/bin/sh", "-c", options.command], {
8578
8653
  cwd: options.worktree,
8579
8654
  env: { ...options.env, TMPDIR: tmpDir },
8580
8655
  policy: {
8581
8656
  allowWrite: options.readOnly ? [tmpDir] : [options.worktree, tmpDir],
8582
8657
  denyWrite: [
8583
- join15(options.worktree, ".git"),
8658
+ join16(options.worktree, ".git"),
8584
8659
  ...options.readOnly ? [options.worktree] : []
8585
8660
  ],
8586
8661
  denyRead: [
@@ -8751,7 +8826,7 @@ import { SandboxManager as SandboxManager2 } from "@anthropic-ai/sandbox-runtime
8751
8826
  import { execFile } from "node:child_process";
8752
8827
  import { readdir as readdir2, realpath, stat } from "node:fs/promises";
8753
8828
  import { homedir as homedir5, platform } from "node:os";
8754
- import { basename as basename2, dirname as dirname8, isAbsolute as isAbsolute5, join as join16, resolve as resolve7 } from "node:path";
8829
+ import { basename as basename2, dirname as dirname8, isAbsolute as isAbsolute5, join as join17, resolve as resolve7 } from "node:path";
8755
8830
  import { promisify } from "node:util";
8756
8831
  var run = promisify(execFile);
8757
8832
  async function git(cwd, args) {
@@ -8821,7 +8896,7 @@ async function browseFolder(request) {
8821
8896
  let truncated = false;
8822
8897
  const dirs = names.filter((e) => e.isDirectory() || e.isSymbolicLink()).filter((e) => request.showHidden || !e.name.startsWith(".")).sort((a, b) => a.name.localeCompare(b.name));
8823
8898
  for (const entry of dirs) {
8824
- const full = join16(path, entry.name);
8899
+ const full = join17(path, entry.name);
8825
8900
  if (entry.isSymbolicLink() && !await isDir(full)) continue;
8826
8901
  if (folders.length >= FS_MAX_ENTRIES) {
8827
8902
  truncated = true;
@@ -8830,7 +8905,7 @@ async function browseFolder(request) {
8830
8905
  folders.push({
8831
8906
  name: entry.name,
8832
8907
  path: full,
8833
- isRepo: await exists(join16(full, ".git"))
8908
+ isRepo: await exists(join17(full, ".git"))
8834
8909
  });
8835
8910
  }
8836
8911
  const parent = dirname8(path);
@@ -8861,7 +8936,7 @@ async function verifyExpectedOrigin(path, expected) {
8861
8936
  import { execFile as execFile2 } from "node:child_process";
8862
8937
  import { realpathSync as realpathSync10 } from "node:fs";
8863
8938
  import { homedir as homedir6 } from "node:os";
8864
- import { dirname as dirname9, join as join17, resolve as resolve8 } from "node:path";
8939
+ import { dirname as dirname9, join as join18, resolve as resolve8 } from "node:path";
8865
8940
  import { promisify as promisify2 } from "node:util";
8866
8941
  var exec = promisify2(execFile2);
8867
8942
  var DAY = 24 * 60 * 60 * 1e3;
@@ -8873,7 +8948,7 @@ function newerStableVersion(candidate, current) {
8873
8948
  return false;
8874
8949
  }
8875
8950
  async function runServiceNpm(args) {
8876
- const npm = realpathSync10(join17(dirname9(process.execPath), "npm"));
8951
+ const npm = realpathSync10(join18(dirname9(process.execPath), "npm"));
8877
8952
  const { stdout } = await exec(process.execPath, [npm, ...args], {
8878
8953
  cwd: homedir6(),
8879
8954
  timeout: 3e5,
@@ -8895,7 +8970,7 @@ import { execFile as execFile3 } from "node:child_process";
8895
8970
  import { promisify as promisify3 } from "node:util";
8896
8971
  import { mkdir, writeFile, rm } from "node:fs/promises";
8897
8972
  import { homedir as homedir7 } from "node:os";
8898
- import { dirname as dirname10, join as join18, resolve as resolve9 } from "node:path";
8973
+ import { dirname as dirname10, join as join19, resolve as resolve9 } from "node:path";
8899
8974
  var exec2 = promisify3(execFile3);
8900
8975
  var label = "com.aspectlylabs.mikka.daemon";
8901
8976
  async function restartService(update, beforeRestart, dependencies = {
@@ -8930,10 +9005,10 @@ async function uninstallService(clearCredential, dependencies = {
8930
9005
  try {
8931
9006
  if (dependencies.manager === "systemd") {
8932
9007
  await dependencies.run("systemctl", ["--user", "disable", "mikka-daemon.service"]);
8933
- await rm(join18(dependencies.home, ".config/systemd/user/mikka-daemon.service"), { force: true });
9008
+ await rm(join19(dependencies.home, ".config/systemd/user/mikka-daemon.service"), { force: true });
8934
9009
  await dependencies.run("systemctl", ["--user", "daemon-reload"]);
8935
9010
  } else if (dependencies.manager === "launchd") {
8936
- await rm(join18(dependencies.home, "Library/LaunchAgents", `${label}.plist`), { force: true });
9011
+ await rm(join19(dependencies.home, "Library/LaunchAgents", `${label}.plist`), { force: true });
8937
9012
  }
8938
9013
  } finally {
8939
9014
  clearCredential();
@@ -8975,6 +9050,9 @@ async function detectDeviceType() {
8975
9050
  }
8976
9051
 
8977
9052
  // src/harnesses.ts
9053
+ import { readdirSync as readdirSync4, statSync as statSync2 } from "node:fs";
9054
+ import { homedir as homedir8, userInfo } from "node:os";
9055
+ import { delimiter as delimiter3, isAbsolute as isAbsolute7, join as join21 } from "node:path";
8978
9056
  import { execa as execa9 } from "execa";
8979
9057
 
8980
9058
  // src/harness-models.ts
@@ -9120,12 +9198,99 @@ async function discover(harness, binary) {
9120
9198
  return {};
9121
9199
  }
9122
9200
 
9201
+ // src/path-search.ts
9202
+ import { accessSync, constants as constants2, statSync } from "node:fs";
9203
+ import { delimiter as delimiter2, isAbsolute as isAbsolute6, join as join20 } from "node:path";
9204
+ function findOnPath(command, path = process.env.PATH ?? "") {
9205
+ for (const directory of path.split(delimiter2)) {
9206
+ if (!directory) continue;
9207
+ const candidate = join20(directory, command);
9208
+ try {
9209
+ accessSync(candidate, constants2.X_OK);
9210
+ if (statSync(candidate).isFile()) return candidate;
9211
+ } catch {
9212
+ }
9213
+ }
9214
+ return null;
9215
+ }
9216
+ function appendToPath(directories) {
9217
+ const entries = (process.env.PATH ?? "").split(delimiter2).filter(Boolean);
9218
+ for (const directory of directories) {
9219
+ if (isAbsolute6(directory) && !entries.includes(directory)) entries.push(directory);
9220
+ }
9221
+ process.env.PATH = entries.join(delimiter2);
9222
+ }
9223
+
9123
9224
  // src/harnesses.ts
9124
9225
  var HARNESS_BINARIES = {
9125
9226
  claude_code: ["claude"],
9126
9227
  codex: ["codex"],
9127
9228
  cursor: ["cursor-agent", "agent"]
9128
9229
  };
9230
+ var LOGIN_SHELL_TIMEOUT_MS = 5e3;
9231
+ var PATH_MARKER = "__MIKKA_PATH__";
9232
+ function subdirectories(directory) {
9233
+ try {
9234
+ return readdirSync4(directory).map((name) => join21(directory, name));
9235
+ } catch {
9236
+ return [];
9237
+ }
9238
+ }
9239
+ function knownAgentDirectories(home = homedir8()) {
9240
+ return [
9241
+ join21(home, ".local/bin"),
9242
+ join21(home, "bin"),
9243
+ join21(home, ".claude/local"),
9244
+ join21(home, ".npm-global/bin"),
9245
+ join21(home, ".bun/bin"),
9246
+ join21(home, ".volta/bin"),
9247
+ join21(home, ".local/share/pnpm"),
9248
+ join21(home, "Library/pnpm"),
9249
+ join21(home, ".asdf/shims"),
9250
+ join21(home, ".local/share/mise/shims"),
9251
+ ...subdirectories(join21(home, ".nvm/versions/node")).map((version) => join21(version, "bin")),
9252
+ ...subdirectories(join21(home, ".local/share/fnm/node-versions")).map((version) => join21(version, "installation/bin")),
9253
+ "/opt/homebrew/bin",
9254
+ "/usr/local/bin",
9255
+ "/snap/bin"
9256
+ ];
9257
+ }
9258
+ async function loginShellPath(shell = process.env.SHELL || userInfo().shell) {
9259
+ if (!shell || !isAbsolute7(shell)) return [];
9260
+ let timer;
9261
+ try {
9262
+ const shellProcess = execa9(shell, ["-ilc", `printf '${PATH_MARKER}%s${PATH_MARKER}' "$PATH"`], {
9263
+ stdin: "ignore",
9264
+ detached: true,
9265
+ reject: false
9266
+ });
9267
+ const timedOut = new Promise((resolve12) => {
9268
+ timer = setTimeout(() => {
9269
+ try {
9270
+ process.kill(-shellProcess.pid, "SIGKILL");
9271
+ } catch {
9272
+ }
9273
+ resolve12(null);
9274
+ }, LOGIN_SHELL_TIMEOUT_MS);
9275
+ });
9276
+ const result = await Promise.race([shellProcess, timedOut]);
9277
+ return String(result?.stdout ?? "").split(PATH_MARKER)[1]?.split(delimiter3).filter(isAbsolute7) ?? [];
9278
+ } catch {
9279
+ return [];
9280
+ } finally {
9281
+ clearTimeout(timer);
9282
+ }
9283
+ }
9284
+ function harnessFingerprint() {
9285
+ appendToPath(knownAgentDirectories());
9286
+ return Object.values(HARNESS_BINARIES).map((binaries) => {
9287
+ for (const binary of binaries) {
9288
+ const found = findOnPath(binary);
9289
+ if (found) return `${found}:${statSync2(found).mtimeMs}`;
9290
+ }
9291
+ return "";
9292
+ }).join("|");
9293
+ }
9129
9294
  async function versionOf(binary) {
9130
9295
  try {
9131
9296
  const { stdout } = await execa9(binary, ["--version"], {
@@ -9141,6 +9306,7 @@ async function versionOf(binary) {
9141
9306
  }
9142
9307
  }
9143
9308
  async function detectHarnesses() {
9309
+ if (!daemonTestMode(process.env)) appendToPath([...await loginShellPath(), ...knownAgentDirectories()]);
9144
9310
  const detected = await Promise.all(
9145
9311
  Object.keys(HARNESS_BINARIES).map(
9146
9312
  async (harness) => {
@@ -9161,10 +9327,130 @@ async function detectHarnesses() {
9161
9327
  ];
9162
9328
  }
9163
9329
 
9330
+ // src/sandbox-tools.ts
9331
+ import { chmodSync as chmodSync2, existsSync as existsSync5, lstatSync as lstatSync8, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync6, readdirSync as readdirSync5, renameSync as renameSync2, rmSync as rmSync11, writeFileSync as writeFileSync7 } from "node:fs";
9332
+ import { join as join22 } from "node:path";
9333
+ import { execa as execa10 } from "execa";
9334
+ var TOOLS = [
9335
+ { command: "bwrap", package: "bubblewrap", versionFlag: "--version" },
9336
+ { command: "socat", package: "socat", versionFlag: "-V" },
9337
+ { command: "rg", package: "ripgrep", versionFlag: "--version" }
9338
+ ];
9339
+ var APT_TIMEOUT_MS = 12e4;
9340
+ var TOOL_CHECK_TIMEOUT_MS = 5e3;
9341
+ var runTool = async (file, args, cwd, env) => {
9342
+ const { stdout } = await execa10(file, args, { cwd, env, stdin: "ignore", timeout: file === "apt-get" ? APT_TIMEOUT_MS : TOOL_CHECK_TIMEOUT_MS });
9343
+ return { stdout: String(stdout) };
9344
+ };
9345
+ function sandboxToolsDir(dataDir) {
9346
+ return join22(dataDir, "sandbox-tools", "bin");
9347
+ }
9348
+ function missingSandboxTools() {
9349
+ return TOOLS.filter((tool2) => !findOnPath(tool2.command)).map((tool2) => tool2.package);
9350
+ }
9351
+ async function ensureSandboxTools(options) {
9352
+ if ((options.platform ?? process.platform) !== "linux") return [];
9353
+ const { dataDir, log, run: run2 = runTool } = options;
9354
+ const binDir = sandboxToolsDir(dataDir);
9355
+ appendToPath([binDir]);
9356
+ const needed = TOOLS.filter((tool2) => !findOnPath(tool2.command));
9357
+ if (needed.length === 0) return [];
9358
+ const packages = needed.map((tool2) => tool2.package);
9359
+ if (!findOnPath("apt-get") || !findOnPath("dpkg-deb")) {
9360
+ log.warn({ missing: packages }, "sandbox tools missing and apt is unavailable");
9361
+ return packages;
9362
+ }
9363
+ mkdirSync12(binDir, { recursive: true, mode: 448 });
9364
+ const work = mkdtempSync6(join22(dataDir, "sandbox-tools", ".install-"));
9365
+ try {
9366
+ const apt = await downloadPackages(work, packages, run2);
9367
+ for (const tool2 of needed) {
9368
+ try {
9369
+ await installTool(tool2, { work, dataDir, apt, run: run2 });
9370
+ } catch (err) {
9371
+ log.warn({ package: tool2.package, err: errorMessage2(err) }, "sandbox tool unusable on this machine");
9372
+ }
9373
+ }
9374
+ } catch (err) {
9375
+ log.warn({ missing: packages, err: errorMessage2(err) }, "could not download sandbox tools");
9376
+ } finally {
9377
+ rmSync11(work, { recursive: true, force: true });
9378
+ }
9379
+ const missing = missingSandboxTools();
9380
+ if (missing.length < packages.length) log.info({ installed: packages.filter((name) => !missing.includes(name)) }, "sandbox tools installed");
9381
+ return missing;
9382
+ }
9383
+ async function installTool(tool2, context) {
9384
+ const { work, dataDir, apt, run: run2 } = context;
9385
+ const root = join22(work, "root");
9386
+ await run2("dpkg-deb", ["-x", join22(work, debFile(work, tool2.package)), root], work);
9387
+ const unpacked = join22(root, "usr", "bin", tool2.command);
9388
+ chmodSync2(unpacked, 493);
9389
+ const binDir = sandboxToolsDir(dataDir);
9390
+ try {
9391
+ await run2(unpacked, [tool2.versionFlag], work);
9392
+ renameSync2(unpacked, join22(binDir, tool2.command));
9393
+ return;
9394
+ } catch {
9395
+ }
9396
+ const plan = await run2("apt-get", ["-s", "-qq", ...apt, "install", tool2.package], work);
9397
+ const dependencies = [...String(plan?.stdout ?? "").matchAll(/^Inst (\S+)/gm)].map((match) => match[1]).filter((name) => name !== tool2.package);
9398
+ if (dependencies.length === 0) throw new Error("the tool does not run and has no missing dependencies");
9399
+ await run2("apt-get", ["-qq", ...apt, "download", ...dependencies], work);
9400
+ for (const dependency of dependencies) await run2("dpkg-deb", ["-x", join22(work, debFile(work, dependency)), root], work);
9401
+ const libDir = join22(dataDir, "sandbox-tools", "lib");
9402
+ mkdirSync12(libDir, { recursive: true, mode: 448 });
9403
+ for (const directory of [join22(root, "lib"), join22(root, "usr", "lib")]) moveSharedLibraries(directory, libDir);
9404
+ await run2(unpacked, [tool2.versionFlag], work, { LD_LIBRARY_PATH: libDir });
9405
+ const realDir = join22(dataDir, "sandbox-tools", "libexec");
9406
+ mkdirSync12(realDir, { recursive: true, mode: 448 });
9407
+ renameSync2(unpacked, join22(realDir, tool2.command));
9408
+ const launcher = join22(work, `${tool2.command}.launcher`);
9409
+ writeFileSync7(launcher, `#!/bin/sh
9410
+ LD_LIBRARY_PATH=${shellQuote2(libDir)} exec ${shellQuote2(join22(realDir, tool2.command))} "$@"
9411
+ `, { mode: 493 });
9412
+ renameSync2(launcher, join22(binDir, tool2.command));
9413
+ }
9414
+ function moveSharedLibraries(directory, libDir) {
9415
+ if (!existsSync5(directory)) return;
9416
+ for (const entry of readdirSync5(directory)) {
9417
+ const path = join22(directory, entry);
9418
+ if (lstatSync8(path).isDirectory()) moveSharedLibraries(path, libDir);
9419
+ else if (entry.includes(".so") && !existsSync5(join22(libDir, entry))) renameSync2(path, join22(libDir, entry));
9420
+ }
9421
+ }
9422
+ function shellQuote2(value) {
9423
+ return `'${value.replaceAll("'", `'\\''`)}'`;
9424
+ }
9425
+ async function downloadPackages(work, packages, run2) {
9426
+ const cache = join22(work, "cache");
9427
+ mkdirSync12(join22(cache, "archives", "partial"), { recursive: true });
9428
+ const unprivileged = ["-o", `Dir::Cache=${cache}`, "-o", "Debug::NoLocking=1", "-o", "APT::Sandbox::User="];
9429
+ try {
9430
+ await run2("apt-get", ["-qq", ...unprivileged, "download", ...packages], work);
9431
+ return unprivileged;
9432
+ } catch {
9433
+ const lists = join22(work, "lists");
9434
+ mkdirSync12(join22(lists, "partial"), { recursive: true });
9435
+ const privateLists = [...unprivileged, "-o", `Dir::State::lists=${lists}`];
9436
+ await run2("apt-get", ["-qq", ...privateLists, "update"], work);
9437
+ await run2("apt-get", ["-qq", ...privateLists, "download", ...packages], work);
9438
+ return privateLists;
9439
+ }
9440
+ }
9441
+ function debFile(work, name) {
9442
+ const file = readdirSync5(work).find((entry) => entry === `${name}.deb` || entry.startsWith(`${name}_`));
9443
+ if (!file) throw new Error(`${name} package was not downloaded`);
9444
+ return file;
9445
+ }
9446
+ function errorMessage2(err) {
9447
+ return err instanceof Error ? err.message.slice(0, 300) : "unknown error";
9448
+ }
9449
+
9164
9450
  // src/lock.ts
9165
- import { mkdirSync as mkdirSync12, readFileSync as readFileSync9, rmSync as rmSync11 } from "node:fs";
9451
+ import { mkdirSync as mkdirSync13, readFileSync as readFileSync10, rmSync as rmSync12 } from "node:fs";
9166
9452
  import { createConnection } from "node:net";
9167
- import { join as join19 } from "node:path";
9453
+ import { join as join23 } from "node:path";
9168
9454
  import { setTimeout as sleep2 } from "node:timers/promises";
9169
9455
  import lockfile from "proper-lockfile";
9170
9456
  var DaemonAlreadyRunningError = class extends Error {
@@ -9179,11 +9465,11 @@ var LOCK_STALE_MS = 5 * 6e4;
9179
9465
  var LOCK_UPDATE_MS = 3e4;
9180
9466
  var LOCK_TAKEOVER_MS = 6e3;
9181
9467
  function pidFile(dataDir) {
9182
- return join19(dataDir, "daemon.pid");
9468
+ return join23(dataDir, "daemon.pid");
9183
9469
  }
9184
9470
  function holderPid(dataDir) {
9185
9471
  try {
9186
- const pid = Number(readFileSync9(pidFile(dataDir), "utf8").trim());
9472
+ const pid = Number(readFileSync10(pidFile(dataDir), "utf8").trim());
9187
9473
  return Number.isInteger(pid) && pid > 0 ? pid : null;
9188
9474
  } catch {
9189
9475
  return null;
@@ -9210,7 +9496,7 @@ function socketAnswers(socketPath) {
9210
9496
  });
9211
9497
  }
9212
9498
  async function acquireLock(dataDir, lockfilePath, onCompromised = () => void 0, options = {}) {
9213
- mkdirSync12(dataDir, { recursive: true });
9499
+ mkdirSync13(dataDir, { recursive: true });
9214
9500
  const lock = async () => {
9215
9501
  const release = await lockfile.lock(dataDir, {
9216
9502
  lockfilePath,
@@ -9223,7 +9509,7 @@ async function acquireLock(dataDir, lockfilePath, onCompromised = () => void 0,
9223
9509
  writeFileAtomic(pidFile(dataDir), `${process.pid}
9224
9510
  `);
9225
9511
  return async () => {
9226
- rmSync11(pidFile(dataDir), { force: true });
9512
+ rmSync12(pidFile(dataDir), { force: true });
9227
9513
  await release();
9228
9514
  };
9229
9515
  };
@@ -9240,7 +9526,7 @@ async function acquireLock(dataDir, lockfilePath, onCompromised = () => void 0,
9240
9526
  const pid = holderPid(dataDir);
9241
9527
  const crashed = pid !== null && pid !== process.pid && !processAlive(pid);
9242
9528
  if (crashed || pid === null && Date.now() >= deadline) {
9243
- rmSync11(lockfilePath, { recursive: true, force: true });
9529
+ rmSync12(lockfilePath, { recursive: true, force: true });
9244
9530
  try {
9245
9531
  return await lock();
9246
9532
  } catch (error) {
@@ -9317,13 +9603,13 @@ function closeLogger(logger) {
9317
9603
  // src/outbox.ts
9318
9604
  import {
9319
9605
  appendFileSync,
9320
- mkdirSync as mkdirSync13,
9321
- readFileSync as readFileSync10,
9322
- readdirSync as readdirSync4,
9323
- rmSync as rmSync12,
9606
+ mkdirSync as mkdirSync14,
9607
+ readFileSync as readFileSync11,
9608
+ readdirSync as readdirSync6,
9609
+ rmSync as rmSync13,
9324
9610
  truncateSync
9325
9611
  } from "node:fs";
9326
- import { join as join20 } from "node:path";
9612
+ import { join as join24 } from "node:path";
9327
9613
  var Outbox = class {
9328
9614
  constructor(dir, link, log, retryMs = 1e3, onUndeliverable = () => void 0, retainResources = false) {
9329
9615
  this.dir = dir;
@@ -9332,7 +9618,7 @@ var Outbox = class {
9332
9618
  this.retryMs = retryMs;
9333
9619
  this.onUndeliverable = onUndeliverable;
9334
9620
  this.retainResources = retainResources;
9335
- mkdirSync13(dir, { recursive: true, mode: 448 });
9621
+ mkdirSync14(dir, { recursive: true, mode: 448 });
9336
9622
  }
9337
9623
  dir;
9338
9624
  link;
@@ -9346,15 +9632,15 @@ var Outbox = class {
9346
9632
  /** Runs whose file was checked for a torn tail since this process started. */
9347
9633
  repaired = /* @__PURE__ */ new Set();
9348
9634
  file(runId) {
9349
- return join20(this.dir, `${assertSafeId("run id", runId)}.jsonl`);
9635
+ return join24(this.dir, `${assertSafeId("run id", runId)}.jsonl`);
9350
9636
  }
9351
9637
  ackFile(runId) {
9352
- return join20(this.dir, `${assertSafeId("run id", runId)}.ack.json`);
9638
+ return join24(this.dir, `${assertSafeId("run id", runId)}.ack.json`);
9353
9639
  }
9354
9640
  parse(runId) {
9355
9641
  let data;
9356
9642
  try {
9357
- data = readFileSync10(this.file(runId));
9643
+ data = readFileSync11(this.file(runId));
9358
9644
  } catch {
9359
9645
  return { items: [], validBytes: 0, torn: false, tornTail: false };
9360
9646
  }
@@ -9439,7 +9725,7 @@ var Outbox = class {
9439
9725
  }
9440
9726
  runIds() {
9441
9727
  try {
9442
- return readdirSync4(this.dir).filter((name) => name.endsWith(".jsonl")).map((name) => name.slice(0, -".jsonl".length)).filter((runId) => isSafeId(runId));
9728
+ return readdirSync6(this.dir).filter((name) => name.endsWith(".jsonl")).map((name) => name.slice(0, -".jsonl".length)).filter((runId) => isSafeId(runId));
9443
9729
  } catch {
9444
9730
  return [];
9445
9731
  }
@@ -9507,8 +9793,8 @@ var Outbox = class {
9507
9793
  }
9508
9794
  remove(runId) {
9509
9795
  if (this.retainResources) return;
9510
- rmSync12(this.file(runId), { force: true });
9511
- rmSync12(this.ackFile(runId), { force: true });
9796
+ rmSync13(this.file(runId), { force: true });
9797
+ rmSync13(this.ackFile(runId), { force: true });
9512
9798
  }
9513
9799
  scheduleRetry() {
9514
9800
  if (this.retryTimer || this.closed) return;
@@ -9533,15 +9819,15 @@ var Outbox = class {
9533
9819
  };
9534
9820
 
9535
9821
  // src/quota/local-credentials.ts
9536
- import { homedir as homedir8 } from "node:os";
9537
- import { join as join22 } from "node:path";
9822
+ import { homedir as homedir9 } from "node:os";
9823
+ import { join as join26 } from "node:path";
9538
9824
 
9539
9825
  // src/quota/files.ts
9540
9826
  import { execFile as execFile4 } from "node:child_process";
9541
- import { constants as constants2 } from "node:fs";
9827
+ import { constants as constants3 } from "node:fs";
9542
9828
  import { lstat as lstat2, open } from "node:fs/promises";
9543
9829
  import { promisify as promisify4 } from "node:util";
9544
- var NOFOLLOW = constants2.O_NOFOLLOW ?? 0;
9830
+ var NOFOLLOW = constants3.O_NOFOLLOW ?? 0;
9545
9831
  var execFileAsync = promisify4(execFile4);
9546
9832
  var KEYCHAIN_TIMEOUT_MS = 3e4;
9547
9833
  var MAX_CREDENTIAL_BYTES = 64 * 1024;
@@ -9617,7 +9903,7 @@ async function readSecureFile(filePath, maxBytes = MAX_CREDENTIAL_BYTES) {
9617
9903
  if (before.size > maxBytes) {
9618
9904
  throw new Error(`Credential file exceeds ${maxBytes} bytes: ${filePath}`);
9619
9905
  }
9620
- const handle = await open(filePath, constants2.O_RDONLY | NOFOLLOW);
9906
+ const handle = await open(filePath, constants3.O_RDONLY | NOFOLLOW);
9621
9907
  try {
9622
9908
  const after = await handle.stat();
9623
9909
  assertRegularFile(after, filePath);
@@ -10032,12 +10318,12 @@ async function readCodexQuota(options) {
10032
10318
 
10033
10319
  // src/quota/cursor.ts
10034
10320
  import { lstat as lstat3 } from "node:fs/promises";
10035
- import { join as join21 } from "node:path";
10321
+ import { join as join25 } from "node:path";
10036
10322
  var ENDPOINT3 = "https://cursor.com/api/usage-summary";
10037
10323
  var ACCESS_TOKEN_KEY = "cursorAuth/accessToken";
10038
10324
  function cursorDatabasePath(platform3, home) {
10039
10325
  if (platform3 === "darwin") {
10040
- return join21(
10326
+ return join25(
10041
10327
  home,
10042
10328
  "Library",
10043
10329
  "Application Support",
@@ -10048,7 +10334,7 @@ function cursorDatabasePath(platform3, home) {
10048
10334
  );
10049
10335
  }
10050
10336
  if (platform3 === "win32") {
10051
- return join21(
10337
+ return join25(
10052
10338
  home,
10053
10339
  "AppData",
10054
10340
  "Roaming",
@@ -10058,7 +10344,7 @@ function cursorDatabasePath(platform3, home) {
10058
10344
  "state.vscdb"
10059
10345
  );
10060
10346
  }
10061
- return join21(home, ".config", "Cursor", "User", "globalStorage", "state.vscdb");
10347
+ return join25(home, ".config", "Cursor", "User", "globalStorage", "state.vscdb");
10062
10348
  }
10063
10349
  var CURSOR_PLANS = {
10064
10350
  pro: "Pro",
@@ -10230,10 +10516,10 @@ async function readCursorQuota(options) {
10230
10516
  // src/quota/local-credentials.ts
10231
10517
  var KEYCHAIN_SERVICE = "Claude Code-credentials";
10232
10518
  function claudeCredentialPath(home) {
10233
- return join22(home, ".claude", ".credentials.json");
10519
+ return join26(home, ".claude", ".credentials.json");
10234
10520
  }
10235
10521
  function codexAuthPath(home) {
10236
- return join22(home, ".codex", "auth.json");
10522
+ return join26(home, ".codex", "auth.json");
10237
10523
  }
10238
10524
  function unknown2(vendor, observedAt) {
10239
10525
  return {
@@ -10252,7 +10538,7 @@ var LocalCredentialsSource = class {
10252
10538
  options;
10253
10539
  id = "local_credentials";
10254
10540
  async read(signal) {
10255
- const home = this.options.home ?? homedir8();
10541
+ const home = this.options.home ?? homedir9();
10256
10542
  const platform3 = this.options.platform ?? process.platform;
10257
10543
  const fetchImpl = this.options.fetch ?? globalThis.fetch;
10258
10544
  const now = this.options.now ?? Date.now;
@@ -10385,7 +10671,7 @@ var QuotaPoller = class {
10385
10671
 
10386
10672
  // src/rpc/server.ts
10387
10673
  import { timingSafeEqual } from "node:crypto";
10388
- import { chmodSync as chmodSync2, rmSync as rmSync13 } from "node:fs";
10674
+ import { chmodSync as chmodSync3, rmSync as rmSync14 } from "node:fs";
10389
10675
  import { createServer as createServer2 } from "node:net";
10390
10676
  import {
10391
10677
  createMessageConnection as createMessageConnection2,
@@ -10426,13 +10712,13 @@ var RpcServer = class {
10426
10712
  sockets = /* @__PURE__ */ new Set();
10427
10713
  async listen() {
10428
10714
  const { socketPath } = this.options;
10429
- rmSync13(socketPath, { force: true });
10715
+ rmSync14(socketPath, { force: true });
10430
10716
  const server = createServer2((socket) => this.accept(socket));
10431
10717
  await new Promise((resolve12, reject) => {
10432
10718
  server.once("error", reject);
10433
10719
  server.listen(socketPath, () => resolve12());
10434
10720
  });
10435
- chmodSync2(socketPath, 384);
10721
+ chmodSync3(socketPath, 384);
10436
10722
  this.server = server;
10437
10723
  }
10438
10724
  accept(socket) {
@@ -10499,7 +10785,7 @@ var RpcServer = class {
10499
10785
  this.server.close(() => resolve12());
10500
10786
  });
10501
10787
  this.server = null;
10502
- rmSync13(this.options.socketPath, { force: true });
10788
+ rmSync14(this.options.socketPath, { force: true });
10503
10789
  }
10504
10790
  };
10505
10791
 
@@ -10562,12 +10848,12 @@ var RunJournal = class {
10562
10848
  };
10563
10849
 
10564
10850
  // src/runs/check.ts
10565
- import { execa as execa10 } from "execa";
10851
+ import { execa as execa11 } from "execa";
10566
10852
  async function fixedCheckSnapshot(repoPath, worktree, sha) {
10567
10853
  if (!/^[a-f0-9]{40}$/.test(sha))
10568
10854
  throw new Error("Check requires an exact candidate SHA");
10569
10855
  const gitDir = await worktreeGitDir(repoPath, worktree);
10570
- const git2 = async (...args) => (await execa10(
10856
+ const git2 = async (...args) => (await execa11(
10571
10857
  "git",
10572
10858
  [
10573
10859
  "-c",
@@ -10722,15 +11008,15 @@ function createRunMasker(secrets) {
10722
11008
 
10723
11009
  // src/runs/supervisor.ts
10724
11010
  import { createHash as createHash4, randomUUID as randomUUID5 } from "node:crypto";
10725
- import { join as join24, resolve as resolve10 } from "node:path";
10726
- import { execa as execa12 } from "execa";
11011
+ import { join as join28, resolve as resolve10 } from "node:path";
11012
+ import { execa as execa13 } from "execa";
10727
11013
 
10728
11014
  // src/agents/checkpoint.ts
10729
- import { mkdtempSync as mkdtempSync6, rmSync as rmSync14, writeFileSync as writeFileSync7 } from "node:fs";
11015
+ import { mkdtempSync as mkdtempSync7, rmSync as rmSync15, writeFileSync as writeFileSync8 } from "node:fs";
10730
11016
  import { tmpdir as tmpdir2 } from "node:os";
10731
- import { join as join23 } from "node:path";
11017
+ import { join as join27 } from "node:path";
10732
11018
  import { gunzipSync as gunzipSync2, gzipSync as gzipSync2 } from "node:zlib";
10733
- import { execa as execa11 } from "execa";
11019
+ import { execa as execa12 } from "execa";
10734
11020
  var CheckpointRecoveryError = class extends Error {
10735
11021
  constructor(message) {
10736
11022
  super(message);
@@ -10775,12 +11061,12 @@ async function takeCheckpoint(options) {
10775
11061
  }
10776
11062
  async function applyCheckpoint(options) {
10777
11063
  const git2 = await pinnedGit(options.repoPath, options.worktree);
10778
- const dir = mkdtempSync6(join23(tmpdir2(), "mikka-checkpoint-"));
10779
- const file = join23(dir, "checkpoint.patch");
11064
+ const dir = mkdtempSync7(join27(tmpdir2(), "mikka-checkpoint-"));
11065
+ const file = join27(dir, "checkpoint.patch");
10780
11066
  try {
10781
11067
  const patch = gunzipSync2(Buffer.from(options.checkpoint.patch, "base64"));
10782
11068
  if (!patch.length && options.checkpoint.files === 0) return true;
10783
- writeFileSync7(file, patch);
11069
+ writeFileSync8(file, patch);
10784
11070
  for (const args of [
10785
11071
  ["apply", "--binary", "--whitespace=nowarn", file],
10786
11072
  ["apply", "--binary", "--3way", "--whitespace=nowarn", file]
@@ -10793,11 +11079,11 @@ async function applyCheckpoint(options) {
10793
11079
  }
10794
11080
  return false;
10795
11081
  } finally {
10796
- rmSync14(dir, { recursive: true, force: true });
11082
+ rmSync15(dir, { recursive: true, force: true });
10797
11083
  }
10798
11084
  }
10799
11085
  async function hasCommit(repoPath, commit) {
10800
- return execa11(
11086
+ return execa12(
10801
11087
  "git",
10802
11088
  ["-c", "core.hooksPath=/dev/null", "cat-file", "-e", `${commit}^{commit}`],
10803
11089
  { cwd: repoPath, stdin: "ignore" }
@@ -12014,7 +12300,7 @@ var RunSupervisor = class {
12014
12300
  if (!this.deps.adapterStateDir || assignment.harness === "mock" || !session.sessionId || resuming && session.sessionId !== entry.sessionId || assignment.requireSessionResume && session.sessionId !== assignment.resumeSessionId)
12015
12301
  throw new Error("Skill mount requires the actual original harness session");
12016
12302
  verifySkillAssignment(assignment);
12017
- const file = join24(
12303
+ const file = join28(
12018
12304
  runPaths(this.deps.adapterStateDir, runId).runDir,
12019
12305
  SKILLS_DIR,
12020
12306
  skillSlug(assignment.skills[0].name),
@@ -12247,7 +12533,7 @@ function stopReasonOf(event, run2) {
12247
12533
  return event.outcome === "failed" ? "error" : "turn_ended";
12248
12534
  }
12249
12535
  async function unsandboxedVerify(run2) {
12250
- const result = await execa12(run2.command, {
12536
+ const result = await execa13(run2.command, {
12251
12537
  shell: true,
12252
12538
  cwd: run2.worktree,
12253
12539
  env: buildChildEnv(),
@@ -12290,10 +12576,10 @@ var SessionRejectedError = class extends DaemonError {
12290
12576
 
12291
12577
  // src/repositories.ts
12292
12578
  import { createHash as createHash5, randomUUID as randomUUID6 } from "node:crypto";
12293
- import { existsSync as existsSync5, lstatSync as lstatSync8, mkdirSync as mkdirSync14, readdirSync as readdirSync5, realpathSync as realpathSync11, renameSync as renameSync2, rmSync as rmSync15 } from "node:fs";
12294
- import { dirname as dirname11, join as join25, resolve as resolve11 } from "node:path";
12579
+ import { existsSync as existsSync6, lstatSync as lstatSync9, mkdirSync as mkdirSync15, readdirSync as readdirSync7, realpathSync as realpathSync11, renameSync as renameSync3, rmSync as rmSync16 } from "node:fs";
12580
+ import { dirname as dirname11, join as join29, resolve as resolve11 } from "node:path";
12295
12581
  import { setTimeout as delay2 } from "node:timers/promises";
12296
- import { execa as execa13 } from "execa";
12582
+ import { execa as execa14 } from "execa";
12297
12583
  import lockfile2 from "proper-lockfile";
12298
12584
  var RepositoryCache = class {
12299
12585
  constructor(root, allowFile = daemonTestMode(process.env), retainResources = false) {
@@ -12319,19 +12605,19 @@ var RepositoryCache = class {
12319
12605
  const release = await this.lock(path, signal);
12320
12606
  try {
12321
12607
  signal?.throwIfAborted();
12322
- const git2 = (args, cwd) => execa13("git", [
12608
+ const git2 = (args, cwd) => execa14("git", [
12323
12609
  ...FETCH_GIT,
12324
12610
  "-c",
12325
12611
  `protocol.file.allow=${this.allowFile ? "always" : "never"}`,
12326
12612
  ...args
12327
12613
  ], { cwd, env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }, stdin: "ignore", timeout: FETCH_TIMEOUT_MS, cancelSignal: signal, killDescendants: true });
12328
- if (!existsSync5(path)) {
12614
+ if (!existsSync6(path)) {
12329
12615
  const temporary = `${path}.clone-${randomUUID6()}`;
12330
12616
  try {
12331
12617
  await git2(["clone", "--no-checkout", "--no-hardlinks", "--no-recurse-submodules", "--", remote, temporary]);
12332
- renameSync2(temporary, path);
12618
+ renameSync3(temporary, path);
12333
12619
  } finally {
12334
- if (!this.retainResources) rmSync15(temporary, { recursive: true, force: true });
12620
+ if (!this.retainResources) rmSync16(temporary, { recursive: true, force: true });
12335
12621
  }
12336
12622
  } else {
12337
12623
  this.assertClone(path);
@@ -12351,36 +12637,36 @@ var RepositoryCache = class {
12351
12637
  await assertBranchName(baseBranch);
12352
12638
  return `origin/${baseBranch}`;
12353
12639
  }
12354
- const { stdout } = await execa13("git", [...FETCH_GIT, "symbolic-ref", "--short", "refs/remotes/origin/HEAD"], { cwd: path, stdin: "ignore" });
12640
+ const { stdout } = await execa14("git", [...FETCH_GIT, "symbolic-ref", "--short", "refs/remotes/origin/HEAD"], { cwd: path, stdin: "ignore" });
12355
12641
  if (!stdout.startsWith("origin/")) throw new Error("Repository default branch unavailable");
12356
12642
  return stdout.trim();
12357
12643
  }
12358
12644
  /** Cache paths for retention/orphan cleanup; never consult user checkouts. */
12359
12645
  paths() {
12360
12646
  const visit = (path) => {
12361
- if (!existsSync5(path) || lstatSync8(path).isSymbolicLink()) return [];
12362
- if (existsSync5(join25(path, ".git"))) {
12647
+ if (!existsSync6(path) || lstatSync9(path).isSymbolicLink()) return [];
12648
+ if (existsSync6(join29(path, ".git"))) {
12363
12649
  this.assertClone(path);
12364
12650
  return [path];
12365
12651
  }
12366
- return readdirSync5(path, { withFileTypes: true }).flatMap((entry) => entry.isDirectory() && !entry.name.endsWith(".lock") && !entry.name.includes(".clone-") ? visit(join25(path, entry.name)) : []);
12652
+ return readdirSync7(path, { withFileTypes: true }).flatMap((entry) => entry.isDirectory() && !entry.name.endsWith(".lock") && !entry.name.includes(".clone-") ? visit(join29(path, entry.name)) : []);
12367
12653
  };
12368
12654
  return visit(resolve11(this.root));
12369
12655
  }
12370
12656
  ensureParents(path) {
12371
- mkdirSync14(this.root, { recursive: true, mode: 448 });
12372
- if (lstatSync8(this.root).isSymbolicLink()) throw new Error("Repository cache contains a symlink");
12657
+ mkdirSync15(this.root, { recursive: true, mode: 448 });
12658
+ if (lstatSync9(this.root).isSymbolicLink()) throw new Error("Repository cache contains a symlink");
12373
12659
  const root = realpathSync11(this.root);
12374
12660
  let current = resolve11(this.root);
12375
12661
  for (const part of path.slice(current.length + 1).split("/").filter(Boolean)) {
12376
- current = join25(current, part);
12377
- if (existsSync5(current) && lstatSync8(current).isSymbolicLink()) throw new Error("Repository cache contains a symlink");
12378
- mkdirSync14(current, { recursive: true, mode: 448 });
12662
+ current = join29(current, part);
12663
+ if (existsSync6(current) && lstatSync9(current).isSymbolicLink()) throw new Error("Repository cache contains a symlink");
12664
+ mkdirSync15(current, { recursive: true, mode: 448 });
12379
12665
  if (!isInside(root, realpathSync11(current))) throw new Error("Repository cache escapes its directory");
12380
12666
  }
12381
12667
  }
12382
12668
  assertClone(path) {
12383
- if (lstatSync8(path).isSymbolicLink() || !lstatSync8(join25(path, ".git")).isDirectory() || lstatSync8(join25(path, ".git")).isSymbolicLink()) throw new Error("Repository cache is not a standard clone");
12669
+ if (lstatSync9(path).isSymbolicLink() || !lstatSync9(join29(path, ".git")).isDirectory() || lstatSync9(join29(path, ".git")).isSymbolicLink()) throw new Error("Repository cache is not a standard clone");
12384
12670
  if (!isInside(realpathSync11(this.root), realpathSync11(path))) throw new Error("Repository cache escapes its directory");
12385
12671
  }
12386
12672
  async lock(path, signal) {
@@ -12401,16 +12687,16 @@ var RepositoryCache = class {
12401
12687
  import { execFile as execFile5, spawn as spawn4 } from "node:child_process";
12402
12688
  import { randomUUID as randomUUID7 } from "node:crypto";
12403
12689
  import {
12404
- existsSync as existsSync6,
12405
- lstatSync as lstatSync9,
12406
- mkdirSync as mkdirSync15,
12407
- mkdtempSync as mkdtempSync7,
12408
- readdirSync as readdirSync6,
12690
+ existsSync as existsSync7,
12691
+ lstatSync as lstatSync10,
12692
+ mkdirSync as mkdirSync16,
12693
+ mkdtempSync as mkdtempSync8,
12694
+ readdirSync as readdirSync8,
12409
12695
  realpathSync as realpathSync12,
12410
- rmSync as rmSync16
12696
+ rmSync as rmSync17
12411
12697
  } from "node:fs";
12412
12698
  import { createRequire } from "node:module";
12413
- import { delimiter as delimiter2, dirname as dirname12, join as join27 } from "node:path";
12699
+ import { delimiter as delimiter4, dirname as dirname12, join as join31 } from "node:path";
12414
12700
  import { fileURLToPath as fileURLToPath2 } from "node:url";
12415
12701
  import { promisify as promisify5 } from "node:util";
12416
12702
 
@@ -12420,7 +12706,7 @@ import { chmod, mkdtemp, rm as rm2 } from "node:fs/promises";
12420
12706
  import { createServer as createServer3, request as httpRequest } from "node:http";
12421
12707
  import { connect, isIP as isIP3 } from "node:net";
12422
12708
  import { tmpdir as tmpdir3 } from "node:os";
12423
- import { join as join26 } from "node:path";
12709
+ import { join as join30 } from "node:path";
12424
12710
 
12425
12711
  // ../../lib/search/url-policy.ts
12426
12712
  import { BlockList, isIP as isIP2 } from "node:net";
@@ -12489,9 +12775,9 @@ function endToEndHeaders(input) {
12489
12775
  }
12490
12776
  async function startPublicEgress(options) {
12491
12777
  options.signal.throwIfAborted();
12492
- const directory = await mkdtemp(join26(tmpdir3(), "mikka-egress-"));
12778
+ const directory = await mkdtemp(join30(tmpdir3(), "mikka-egress-"));
12493
12779
  await chmod(directory, 448);
12494
- const socketPath = join26(directory, "egress.sock");
12780
+ const socketPath = join30(directory, "egress.sock");
12495
12781
  const lifetime = new AbortController();
12496
12782
  const signal = AbortSignal.any([options.signal, lifetime.signal]);
12497
12783
  const sockets = /* @__PURE__ */ new Set();
@@ -12648,8 +12934,8 @@ async function createHostedBotRunner(host) {
12648
12934
  }).catch(() => {
12649
12935
  throw unavailable2();
12650
12936
  });
12651
- const resources = join27(host.stateDir, "native-resources");
12652
- mkdirSync15(resources, { recursive: true, mode: 448 });
12937
+ const resources = join31(host.stateDir, "native-resources");
12938
+ mkdirSync16(resources, { recursive: true, mode: 448 });
12653
12939
  const removeResource = async (file, record) => {
12654
12940
  if (!/^mikka-native-(?:verify-)?[a-f0-9-]{36}$/.test(record.name) || !/^[a-f0-9-]{36}$/.test(record.nonce))
12655
12941
  throw unavailable2();
@@ -12669,9 +12955,9 @@ async function createHostedBotRunner(host) {
12669
12955
  if (record.state === "created" && /No such (?:container|object)/i.test(
12670
12956
  String(error.stderr)
12671
12957
  )) {
12672
- if (record.assets?.startsWith(join27(host.stateDir, "native-verify-git-")))
12673
- rmSync16(record.assets, { recursive: true, force: true });
12674
- rmSync16(file, { force: true });
12958
+ if (record.assets?.startsWith(join31(host.stateDir, "native-verify-git-")))
12959
+ rmSync17(record.assets, { recursive: true, force: true });
12960
+ rmSync17(file, { force: true });
12675
12961
  return;
12676
12962
  }
12677
12963
  throw new Error("native_runtime_cleanup_unconfirmed");
@@ -12680,13 +12966,13 @@ async function createHostedBotRunner(host) {
12680
12966
  if (labels?.["com.mikka.native.resource"] !== record.nonce || record.id && record.id !== id4)
12681
12967
  throw unavailable2();
12682
12968
  await exec3("docker", ["rm", "-f", id4], { env: bareEnv, timeout: 3e4 });
12683
- if (record.assets?.startsWith(join27(host.stateDir, "native-verify-git-")))
12684
- rmSync16(record.assets, { recursive: true, force: true });
12685
- rmSync16(file, { force: true });
12969
+ if (record.assets?.startsWith(join31(host.stateDir, "native-verify-git-")))
12970
+ rmSync17(record.assets, { recursive: true, force: true });
12971
+ rmSync17(file, { force: true });
12686
12972
  };
12687
- for (const name of readdirSync6(resources))
12973
+ for (const name of readdirSync8(resources))
12688
12974
  if (name.endsWith(".json")) {
12689
- const file = join27(resources, name);
12975
+ const file = join31(resources, name);
12690
12976
  const record = readJson(file);
12691
12977
  if (!record) throw unavailable2();
12692
12978
  await removeResource(file, record);
@@ -12697,7 +12983,7 @@ async function createHostedBotRunner(host) {
12697
12983
  const bundled = createRequire(
12698
12984
  require2.resolve("@anthropic-ai/claude-agent-sdk")
12699
12985
  );
12700
- claude ??= join27(
12986
+ claude ??= join31(
12701
12987
  dirname12(
12702
12988
  bundled.resolve(
12703
12989
  "@anthropic-ai/claude-agent-sdk-linux-x64/package.json"
@@ -12707,13 +12993,13 @@ async function createHostedBotRunner(host) {
12707
12993
  );
12708
12994
  } catch {
12709
12995
  }
12710
- const codex = host.binaries?.codex ?? (process.env.PATH ?? "").split(delimiter2).map((dir) => join27(dir, "codex")).find((path) => existsSync6(path));
12996
+ const codex = host.binaries?.codex ?? (process.env.PATH ?? "").split(delimiter4).map((dir) => join31(dir, "codex")).find((path) => existsSync7(path));
12711
12997
  const binaries = { codex, claude_code: claude };
12712
12998
  for (const kind of ["codex", "claude_code"])
12713
12999
  if (binaries[kind]) {
12714
13000
  try {
12715
13001
  binaries[kind] = realpathSync12(binaries[kind]);
12716
- if (!lstatSync9(binaries[kind]).isFile()) delete binaries[kind];
13002
+ if (!lstatSync10(binaries[kind]).isFile()) delete binaries[kind];
12717
13003
  } catch {
12718
13004
  delete binaries[kind];
12719
13005
  }
@@ -12721,12 +13007,12 @@ async function createHostedBotRunner(host) {
12721
13007
  if (!binaries.codex && !binaries.claude_code) throw unavailable2();
12722
13008
  const command = async (worktree, script, readOnly, timeoutMs, signal) => {
12723
13009
  const name = `mikka-native-verify-${randomUUID7()}`;
12724
- const file = join27(resources, name + ".json");
13010
+ const file = join31(resources, name + ".json");
12725
13011
  const resource = { name, nonce: randomUUID7(), state: "creating" };
12726
13012
  const timing = { createMs: 0, runMs: 0 };
12727
13013
  let phase = "create";
12728
13014
  let began = performance.now();
12729
- const gitCopy = mkdtempSync7(join27(host.stateDir, "native-verify-git-"));
13015
+ const gitCopy = mkdtempSync8(join31(host.stateDir, "native-verify-git-"));
12730
13016
  resource.assets = gitCopy;
12731
13017
  try {
12732
13018
  const cwd = realpathSync12(worktree);
@@ -12742,7 +13028,7 @@ async function createHostedBotRunner(host) {
12742
13028
  "--no-checkout",
12743
13029
  "--",
12744
13030
  cwd,
12745
- join27(gitCopy, "repo")
13031
+ join31(gitCopy, "repo")
12746
13032
  ],
12747
13033
  {
12748
13034
  env: {
@@ -12757,8 +13043,8 @@ async function createHostedBotRunner(host) {
12757
13043
  maxBuffer: 1024 * 1024
12758
13044
  }
12759
13045
  );
12760
- const safeGit = join27(gitCopy, "repo", ".git");
12761
- const protectedGit = lstatSync9(join27(cwd, ".git")).isFile() ? join27(cwd, ".git") : safeGit;
13046
+ const safeGit = join31(gitCopy, "repo", ".git");
13047
+ const protectedGit = lstatSync10(join31(cwd, ".git")).isFile() ? join31(cwd, ".git") : safeGit;
12762
13048
  writeJsonAtomic(file, resource);
12763
13049
  const created = await exec3(
12764
13050
  "docker",
@@ -12845,8 +13131,8 @@ async function createHostedBotRunner(host) {
12845
13131
  timing
12846
13132
  };
12847
13133
  } finally {
12848
- if (existsSync6(file)) await removeResource(file, resource);
12849
- else rmSync16(gitCopy, { recursive: true, force: true });
13134
+ if (existsSync7(file)) await removeResource(file, resource);
13135
+ else rmSync17(gitCopy, { recursive: true, force: true });
12850
13136
  }
12851
13137
  };
12852
13138
  return {
@@ -12862,7 +13148,7 @@ async function createHostedBotRunner(host) {
12862
13148
  throw unavailable2();
12863
13149
  const name = `mikka-native-${randomUUID7()}`;
12864
13150
  const nonce = randomUUID7();
12865
- const resourceFile = join27(resources, name + ".json");
13151
+ const resourceFile = join31(resources, name + ".json");
12866
13152
  const resource = { name, nonce, state: "creating" };
12867
13153
  const lifetime = new AbortController();
12868
13154
  let closed = false;
@@ -12901,7 +13187,7 @@ async function createHostedBotRunner(host) {
12901
13187
  void brokerClosed.catch(() => void 0);
12902
13188
  try {
12903
13189
  await creating?.catch(() => void 0);
12904
- if (existsSync6(resourceFile)) await removeResource(resourceFile, resource);
13190
+ if (existsSync7(resourceFile)) await removeResource(resourceFile, resource);
12905
13191
  } finally {
12906
13192
  try {
12907
13193
  await brokerClosed;
@@ -12934,11 +13220,11 @@ async function createHostedBotRunner(host) {
12934
13220
  return current;
12935
13221
  };
12936
13222
  const paths = runPaths(host.stateDir, assignment.runId);
12937
- mkdirSync15(paths.runDir, { recursive: true, mode: 448 });
12938
- const shadow = join27(paths.runDir, "runtime-git");
12939
- const emptyHome = join27(paths.runDir, "git-bootstrap-home");
12940
- mkdirSync15(emptyHome, { recursive: true, mode: 448 });
12941
- if (!existsSync6(shadow))
13223
+ mkdirSync16(paths.runDir, { recursive: true, mode: 448 });
13224
+ const shadow = join31(paths.runDir, "runtime-git");
13225
+ const emptyHome = join31(paths.runDir, "git-bootstrap-home");
13226
+ mkdirSync16(emptyHome, { recursive: true, mode: 448 });
13227
+ if (!existsSync7(shadow))
12942
13228
  await exec3(
12943
13229
  "git",
12944
13230
  [
@@ -12967,9 +13253,9 @@ async function createHostedBotRunner(host) {
12967
13253
  }
12968
13254
  );
12969
13255
  await live();
12970
- if (!lstatSync9(shadow).isDirectory() || !lstatSync9(join27(shadow, ".git")).isDirectory() || !realpathSync12(shadow).startsWith(realpathSync12(paths.runDir) + "/"))
13256
+ if (!lstatSync10(shadow).isDirectory() || !lstatSync10(join31(shadow, ".git")).isDirectory() || !realpathSync12(shadow).startsWith(realpathSync12(paths.runDir) + "/"))
12971
13257
  throw unavailable2();
12972
- const ledger = join27(
13258
+ const ledger = join31(
12973
13259
  host.stateDir,
12974
13260
  "native-ledgers",
12975
13261
  assignment.runId + ".json"
@@ -12986,15 +13272,15 @@ async function createHostedBotRunner(host) {
12986
13272
  modelId: first.modelId
12987
13273
  };
12988
13274
  const previous = readJson(ledger);
12989
- if (existsSync6(ledger) && (!previous || JSON.stringify(previous.scope) !== JSON.stringify(scope) || typeof previous.sessionId !== "string"))
13275
+ if (existsSync7(ledger) && (!previous || JSON.stringify(previous.scope) !== JSON.stringify(scope) || typeof previous.sessionId !== "string"))
12990
13276
  throw unavailable2();
12991
- mkdirSync15(dirname12(ledger), { recursive: true, mode: 448 });
13277
+ mkdirSync16(dirname12(ledger), { recursive: true, mode: 448 });
12992
13278
  const record = async (sessionId) => {
12993
13279
  assertOpen();
12994
13280
  writeJsonAtomic(ledger, { scope, sessionId });
12995
13281
  };
12996
13282
  brokerStarting = createNativeSubscriptionBroker({
12997
- root: join27(host.stateDir, "native-brokers"),
13283
+ root: join31(host.stateDir, "native-brokers"),
12998
13284
  revision,
12999
13285
  check,
13000
13286
  worker: {
@@ -13021,7 +13307,7 @@ async function createHostedBotRunner(host) {
13021
13307
  });
13022
13308
  const readyBroker = await brokerStarting;
13023
13309
  await live();
13024
- const githubCli = options.github ? (process.env.PATH ?? "").split(delimiter2).map((dir) => join27(dir, "gh")).find((file) => existsSync6(file)) : void 0;
13310
+ const githubCli = options.github ? (process.env.PATH ?? "").split(delimiter4).map((dir) => join31(dir, "gh")).find((file) => existsSync7(file)) : void 0;
13025
13311
  if (options.github && !githubCli) throw new Error("Install GitHub CLI (gh) in the cloud worker image");
13026
13312
  const githubDomains = options.github ? ["github.com", "api.github.com", new URL(options.github.endpoint).host] : [];
13027
13313
  const egressMaximum = runDomains(runPolicy(options.policy), [...options.networkAllow ?? [], ...githubDomains]);
@@ -13038,8 +13324,8 @@ async function createHostedBotRunner(host) {
13038
13324
  }
13039
13325
  const cwd = realpathSync12(options.cwd);
13040
13326
  const runDir = realpathSync12(paths.runDir);
13041
- const protectedGit = lstatSync9(join27(cwd, ".git")).isFile() ? join27(cwd, ".git") : join27(shadow, ".git");
13042
- if (!lstatSync9(runDir).isDirectory() || !runDir.startsWith(realpathSync12(host.stateDir) + "/runs/")) {
13327
+ const protectedGit = lstatSync10(join31(cwd, ".git")).isFile() ? join31(cwd, ".git") : join31(shadow, ".git");
13328
+ if (!lstatSync10(runDir).isDirectory() || !runDir.startsWith(realpathSync12(host.stateDir) + "/runs/")) {
13043
13329
  await close();
13044
13330
  throw unavailable2();
13045
13331
  }
@@ -13092,7 +13378,7 @@ async function createHostedBotRunner(host) {
13092
13378
  `${MCP_SERVER_SCRIPT}:${MCP_SERVER_SCRIPT}:ro`,
13093
13379
  ...githubCli ? ["-v", `${githubCli}:/usr/local/bin/mikka-gh:ro`, "-v", `${GITHUB_CREDENTIAL_SCRIPT}:${GITHUB_CREDENTIAL_SCRIPT}:ro`] : [],
13094
13380
  "-v",
13095
- `${join27(dirname12(MCP_SERVER_SCRIPT), "capture-copy.mjs")}:${join27(dirname12(MCP_SERVER_SCRIPT), "capture-copy.mjs")}:ro`,
13381
+ `${join31(dirname12(MCP_SERVER_SCRIPT), "capture-copy.mjs")}:${join31(dirname12(MCP_SERVER_SCRIPT), "capture-copy.mjs")}:ro`,
13096
13382
  "-v",
13097
13383
  `${readyBroker.socket}:/run/mikka-native.sock:ro`,
13098
13384
  ...computerGrant ? [
@@ -13135,13 +13421,13 @@ async function createHostedBotRunner(host) {
13135
13421
  }
13136
13422
  const spawnHosted = (config) => {
13137
13423
  assertOpen();
13138
- const home = join27(runDir, "runtime-home");
13139
- mkdirSync15(home, { recursive: true, mode: 448 });
13424
+ const home = join31(runDir, "runtime-home");
13425
+ mkdirSync16(home, { recursive: true, mode: 448 });
13140
13426
  const env = {
13141
13427
  ...config.env,
13142
13428
  HOME: kind === "claude_code" ? config.env.HOME ?? home : home,
13143
- PATH: `${options.github ? join27(runDir, "github", "bin") + ":" : ""}/usr/local/bin:/usr/bin:/bin`,
13144
- GIT_DIR: join27(shadow, ".git"),
13429
+ PATH: `${options.github ? join31(runDir, "github", "bin") + ":" : ""}/usr/local/bin:/usr/bin:/bin`,
13430
+ GIT_DIR: join31(shadow, ".git"),
13145
13431
  GIT_WORK_TREE: cwd,
13146
13432
  GIT_CONFIG_GLOBAL: "/dev/null",
13147
13433
  GIT_CONFIG_SYSTEM: "/dev/null",
@@ -13160,7 +13446,7 @@ async function createHostedBotRunner(host) {
13160
13446
  signal: AbortSignal.any([lifetime.signal, ...config.signal ? [config.signal] : []])
13161
13447
  });
13162
13448
  child.stdin.write(
13163
- JSON.stringify({ kind, args: config.args, cwd, env: task.env, publicEgress: Boolean(egress), ...options.github ? { githubBin: join27(runDir, "github", "bin") } : {} }) + "\n"
13449
+ JSON.stringify({ kind, args: config.args, cwd, env: task.env, publicEgress: Boolean(egress), ...options.github ? { githubBin: join31(runDir, "github", "bin") } : {} }) + "\n"
13164
13450
  );
13165
13451
  return child;
13166
13452
  };
@@ -13295,7 +13581,7 @@ import {
13295
13581
  createHash as createHash7,
13296
13582
  timingSafeEqual as timingSafeEqual2
13297
13583
  } from "node:crypto";
13298
- import { chmodSync as chmodSync3 } from "node:fs";
13584
+ import { chmodSync as chmodSync4 } from "node:fs";
13299
13585
  import { createServer as createServer4 } from "node:net";
13300
13586
 
13301
13587
  // src/computer/driver.mjs
@@ -13545,7 +13831,7 @@ var ComputerBroker = class {
13545
13831
  else this.server.listen(this.socketPath, resolve12);
13546
13832
  });
13547
13833
  if (this.transport === "tcp") this.socketPath = `tcp://127.0.0.1:${this.server.address().port}`;
13548
- else chmodSync3(this.socketPath, 384);
13834
+ else chmodSync4(this.socketPath, 384);
13549
13835
  }
13550
13836
  request(token, value, signal) {
13551
13837
  const grant = this.grants.get(token);
@@ -13769,6 +14055,11 @@ function loadDeviceFile(raw) {
13769
14055
  }
13770
14056
  return file;
13771
14057
  }
14058
+ var HARNESS_RESCAN_MS = 5 * 6e4;
14059
+ var SANDBOX_REPAIR_RETRY_MS = 60 * 6e4;
14060
+ function missingToolsUnchanged(issue) {
14061
+ return !issue?.missing.length || missingSandboxTools().length === issue.missing.length;
14062
+ }
13772
14063
  var Daemon = class {
13773
14064
  constructor(options) {
13774
14065
  this.options = options;
@@ -13840,8 +14131,8 @@ var Daemon = class {
13840
14131
  }
13841
14132
  async startInternal() {
13842
14133
  const { paths } = this;
13843
- mkdirSync16(paths.dataDir, { recursive: true, mode: 448 });
13844
- if (process.platform !== "win32") chmodSync4(paths.dataDir, 448);
14134
+ mkdirSync17(paths.dataDir, { recursive: true, mode: 448 });
14135
+ if (process.platform !== "win32") chmodSync5(paths.dataDir, 448);
13845
14136
  this.releaseLock = await acquireLock(
13846
14137
  paths.dataDir,
13847
14138
  paths.lock,
@@ -13854,7 +14145,7 @@ var Daemon = class {
13854
14145
  if (this.options.credential)
13855
14146
  this.saveDevice({ credential: this.options.credential });
13856
14147
  this.journal = new RunJournal(paths.journal);
13857
- this.captureUploader = new CaptureUploader((runId) => join28(runPaths(paths.adapterState, runId).runDir, CAPTURES_DIR), this.options.link, this.log, join28(paths.dataDir, "capture-pending"));
14148
+ this.captureUploader = new CaptureUploader((runId) => join32(runPaths(paths.adapterState, runId).runDir, CAPTURES_DIR), this.options.link, this.log, join32(paths.dataDir, "capture-pending"));
13858
14149
  this.outbox = new Outbox(
13859
14150
  paths.outbox,
13860
14151
  this.options.link,
@@ -13871,7 +14162,7 @@ var Daemon = class {
13871
14162
  if (this.localComputerDriver && this.options.link.syncComputerReviews && this.options.link.localComputerAuthority) {
13872
14163
  this.localComputerBroker = new ComputerBroker({
13873
14164
  driver: this.localComputerDriver,
13874
- socketPath: join28(paths.dataDir, "local-computer.sock"),
14165
+ socketPath: join32(paths.dataDir, "local-computer.sock"),
13875
14166
  transport: "tcp",
13876
14167
  permitted: (runId) => {
13877
14168
  const assignment = this.journal.get(runId)?.assignment;
@@ -13913,7 +14204,7 @@ var Daemon = class {
13913
14204
  };
13914
14205
  this.cloudComputerBroker = new ComputerBroker({
13915
14206
  driver,
13916
- socketPath: join28(paths.dataDir, "computer.sock"),
14207
+ socketPath: join32(paths.dataDir, "computer.sock"),
13917
14208
  permitted: (runId) => {
13918
14209
  const entry = this.journal.get(runId);
13919
14210
  return Boolean(!this.stopped && this.registered && entry?.assignment.computer && this.supervisor?.computerRunAllowed(runId));
@@ -14036,7 +14327,7 @@ var Daemon = class {
14036
14327
  worktree,
14037
14328
  tree,
14038
14329
  github: { ...assignment.github, runToken: assignment.mcp.token, issueId: assignment.issueId },
14039
- privateDir: join28(paths.adapterState, "pids"),
14330
+ privateDir: join32(paths.adapterState, "pids"),
14040
14331
  ...hosted ? { hosted: true } : {},
14041
14332
  env: githubReceiptEnvironment()
14042
14333
  }) : publishRun({
@@ -14077,17 +14368,16 @@ var Daemon = class {
14077
14368
  if (this.stopped) throw new Error("daemon stopped during startup");
14078
14369
  const detected = hosted ? hosted.harnesses.map((harness) => ({ harness, installed: true, version: null, subscriptionBroker: true, ...this.cloudComputerBroker ? { computerBroker: true } : {} })) : this.options.harnesses ?? await detectHarnesses();
14079
14370
  if (this.stopped) throw new Error("daemon stopped during startup");
14080
- const runApprovalTransport = typeof this.options.link.prepareRunToolApproval === "function";
14081
- const localIsolation = this.ownedSandbox !== null && this.sandbox === this.ownedSandbox;
14082
- this.harnesses = detected.filter((info) => this.adapters.has(info.harness)).map((info) => ({
14371
+ if (!hosted && !this.options.harnesses) this.harnessPrint = harnessFingerprint();
14372
+ this.harnesses = [...detected.filter((info) => this.adapters.has(info.harness)).map((info) => ({
14083
14373
  ...info,
14084
14374
  // Local enforcement requires the successful owned SRT probe. Hosted
14085
14375
  // enforcement uses its existing network-none/read-only Docker boundary
14086
14376
  // and gate-bound broker/container teardown; general egress stays outside
14087
14377
  // that ceiling. Codex also verifies its pinned interface at initialize.
14088
- toolApproval: runApprovalTransport && (hosted || localIsolation && (info.harness === "claude_code" || info.harness === "codex" && /(?:^|[ /])0\.163\.0(?:$|[ ();])/.test(info.version ?? ""))) ? true : void 0,
14378
+ toolApproval: this.supportsToolApproval(info),
14089
14379
  coordinator: hosted ? false : coordinatorCapable(info)
14090
- }));
14380
+ })), ...this.sandboxBlockedHarnesses(detected)];
14091
14381
  await this.supervisor.resumeAll();
14092
14382
  if (!hosted && this.options.quotaSource !== null) {
14093
14383
  this.quota = new QuotaPoller(
@@ -14271,6 +14561,58 @@ var Daemon = class {
14271
14561
  }
14272
14562
  return acted;
14273
14563
  }
14564
+ supportsToolApproval(info) {
14565
+ if (typeof this.options.link.prepareRunToolApproval !== "function") return void 0;
14566
+ if (this.options.hostedSubscriptions) return true;
14567
+ if (this.ownedSandbox === null || this.sandbox !== this.ownedSandbox) return void 0;
14568
+ return info.harness === "claude_code" || info.harness === "codex" && codexSupportsRunApproval(info.version) ? true : void 0;
14569
+ }
14570
+ /** Report a CLI the daemon cannot run as present but not installed, so no run is pinned here. */
14571
+ sandboxBlockedHarnesses(detected) {
14572
+ const issue = this.sandboxIssue;
14573
+ if (!issue) return [];
14574
+ return detected.filter((info) => info.installed && !this.adapters.has(info.harness)).map((info) => ({
14575
+ harness: info.harness,
14576
+ installed: false,
14577
+ version: info.version,
14578
+ sandboxBlocked: { missing: issue.missing }
14579
+ }));
14580
+ }
14581
+ async redetectHarnesses() {
14582
+ const repairing = this.sandboxIssue?.missing.length;
14583
+ if (this.sandboxIssue && repairing) {
14584
+ this.lastSandboxRepair = Date.now();
14585
+ this.sandboxIssue = { missing: await ensureSandboxTools({ dataDir: this.paths.dataDir, log: this.log }) };
14586
+ }
14587
+ const detected = await detectHarnesses();
14588
+ this.harnessPrint = harnessFingerprint();
14589
+ this.harnesses = [...detected.filter((info) => this.adapters.has(info.harness)).map((info) => {
14590
+ return { ...info, toolApproval: this.supportsToolApproval(info), coordinator: coordinatorCapable(info) };
14591
+ }), ...this.sandboxBlockedHarnesses(detected)];
14592
+ if (repairing && this.sandboxIssue?.missing.length === 0) {
14593
+ this.startMaintenance(() => restartService(false, () => {
14594
+ }, void 0, () => !this.stopped));
14595
+ }
14596
+ }
14597
+ /** Notice an agent installed after startup, or retry a failed tool download, without spawning anything per tick. */
14598
+ rescanHarnesses() {
14599
+ const now = Date.now();
14600
+ if (this.options.hostedSubscriptions || this.options.harnesses || this.rescanning || now - this.lastHarnessScan < HARNESS_RESCAN_MS) return;
14601
+ this.lastHarnessScan = now;
14602
+ const retryRepair = Boolean(this.sandboxIssue?.missing.length) && now - this.lastSandboxRepair >= SANDBOX_REPAIR_RETRY_MS;
14603
+ if (harnessFingerprint() === this.harnessPrint && !retryRepair && missingToolsUnchanged(this.sandboxIssue)) return;
14604
+ this.rescanning = true;
14605
+ void this.redetectHarnesses().then(() => this.syncWithServer()).catch((err) => {
14606
+ this.log.warn({ err }, "harness rescan failed");
14607
+ }).finally(() => {
14608
+ this.rescanning = false;
14609
+ });
14610
+ }
14611
+ harnessPrint = "";
14612
+ lastHarnessScan = Date.now();
14613
+ lastSandboxRepair = Date.now();
14614
+ rescanning = false;
14615
+ sandboxIssue = null;
14274
14616
  sandbox = null;
14275
14617
  ownedSandbox = null;
14276
14618
  /** The agent sandbox (one per daemon), or null where there is none. */
@@ -14279,8 +14621,10 @@ var Daemon = class {
14279
14621
  }
14280
14622
  async createAgentSandbox() {
14281
14623
  if (this.options.agentSandbox !== void 0) return this.options.agentSandbox;
14624
+ const missing = await ensureSandboxTools({ dataDir: this.paths.dataDir, log: this.log });
14282
14625
  if (!SandboxRuntime.supported()) {
14283
- this.log.warn("agent sandbox unavailable: platform or dependencies unsupported");
14626
+ this.log.warn({ missing }, "agent sandbox unavailable: platform or dependencies unsupported");
14627
+ this.sandboxIssue = { missing };
14284
14628
  return null;
14285
14629
  }
14286
14630
  const sandbox = new SandboxRuntime(async ({ host }) => {
@@ -14297,6 +14641,7 @@ var Daemon = class {
14297
14641
  return sandbox;
14298
14642
  } catch (err) {
14299
14643
  this.log.warn({ err }, "agent sandbox unavailable");
14644
+ this.sandboxIssue = { missing: [] };
14300
14645
  if (!this.options.retainResources) await sandbox.reset().catch((resetError) => {
14301
14646
  this.log.warn({ err: resetError }, "agent sandbox cleanup failed");
14302
14647
  });
@@ -14320,11 +14665,11 @@ var Daemon = class {
14320
14665
  return runVerify(sandbox, {
14321
14666
  command,
14322
14667
  worktree: realpathSync13(worktree),
14323
- tmpRoot: join28(this.paths.adapterState, "verify", runId),
14668
+ tmpRoot: join32(this.paths.adapterState, "verify", runId),
14324
14669
  privateDir: paths.privateDir,
14325
14670
  pidFile: paths.pidFile.replace(/\.pgid$/, ".verify.pgid"),
14326
14671
  networkAllow: repo.networkAllow,
14327
- env: { ...buildChildEnv(), MIKKA_HANDOFF_FILE: join28(paths.runDir, "handoff.json") },
14672
+ env: { ...buildChildEnv(), MIKKA_HANDOFF_FILE: join32(paths.runDir, "handoff.json") },
14328
14673
  timeoutMs,
14329
14674
  signal,
14330
14675
  readOnly
@@ -14369,8 +14714,8 @@ var Daemon = class {
14369
14714
  void this.stop().finally(() => this.options.onLockLost?.(error));
14370
14715
  }
14371
14716
  ensureSecret() {
14372
- if (existsSync7(this.paths.secret)) {
14373
- return readFileSync11(this.paths.secret, "utf8").trim();
14717
+ if (existsSync8(this.paths.secret)) {
14718
+ return readFileSync12(this.paths.secret, "utf8").trim();
14374
14719
  }
14375
14720
  const secret = randomBytes3(32).toString("hex");
14376
14721
  writeFileAtomic(this.paths.secret, `${secret}
@@ -14467,6 +14812,7 @@ var Daemon = class {
14467
14812
  this.revokeLocalComputerGrants();
14468
14813
  this.registered = false;
14469
14814
  }
14815
+ this.rescanHarnesses();
14470
14816
  const command = deviceCommands?.[0];
14471
14817
  if (command?.kind === "uninstall") {
14472
14818
  this.draining = true;
@@ -14480,7 +14826,7 @@ var Daemon = class {
14480
14826
  setImmediate(() => {
14481
14827
  void this.stop().then(() => uninstallService(() => {
14482
14828
  this.saveDevice({ credential: void 0 });
14483
- rmSync17(this.paths.secret, { force: true });
14829
+ rmSync18(this.paths.secret, { force: true });
14484
14830
  })).catch(() => {
14485
14831
  this.options.onDrained?.();
14486
14832
  });
@@ -14492,11 +14838,7 @@ var Daemon = class {
14492
14838
  if (command.kind === "redetect" || this.maintenanceIdle()) {
14493
14839
  try {
14494
14840
  if (command.kind === "redetect") {
14495
- const detected = await detectHarnesses();
14496
- this.harnesses = detected.filter((info) => this.adapters.has(info.harness)).map((info) => {
14497
- const previous = this.harnesses.find((old) => old.harness === info.harness && old.version === info.version);
14498
- return { ...info, toolApproval: previous?.toolApproval, coordinator: coordinatorCapable(info) };
14499
- });
14841
+ await this.redetectHarnesses();
14500
14842
  this.saveDevice({ completedDeviceCommands: [command.id], failedDeviceCommands: [] });
14501
14843
  void this.syncWithServer().catch(() => void 0);
14502
14844
  } else {
@@ -14809,7 +15151,7 @@ var Daemon = class {
14809
15151
  if (!job || controller.signal.aborted) return;
14810
15152
  await runNativeCoordinatorJob(job, {
14811
15153
  deviceId,
14812
- stateDir: join28(this.paths.dataDir, "coordinator"),
15154
+ stateDir: join32(this.paths.dataDir, "coordinator"),
14813
15155
  link,
14814
15156
  signal: controller.signal,
14815
15157
  sandbox,
@@ -14852,7 +15194,7 @@ var Daemon = class {
14852
15194
  }, void 0, () => !this.stopped);
14853
15195
  });
14854
15196
  } else if (!this.updateCheck && !this.updateVersion) {
14855
- this.updateCheck = checkLatestVersion(join28(this.paths.dataDir, "auto-update.json"), DAEMON_VERSION, runtime).then((version) => {
15197
+ this.updateCheck = checkLatestVersion(join32(this.paths.dataDir, "auto-update.json"), DAEMON_VERSION, runtime).then((version) => {
14856
15198
  this.updateVersion = version;
14857
15199
  }).catch(() => {
14858
15200
  this.log.warn("Daemon automatic update check failed");