@aspectlylabs/mikka 0.0.86 → 0.0.89

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
@@ -879,10 +879,10 @@ var require_truncate = __commonJS({
879
879
  "../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/truncate.js"(exports, module) {
880
880
  "use strict";
881
881
  var parse2 = require_parse();
882
- var constants3 = require_constants();
882
+ var constants4 = require_constants();
883
883
  var SemVer = require_semver();
884
884
  var truncate = (version, truncation, options) => {
885
- if (!constants3.RELEASE_TYPES.includes(truncation)) {
885
+ if (!constants4.RELEASE_TYPES.includes(truncation)) {
886
886
  return null;
887
887
  }
888
888
  const clonedVersion = cloneInputVersion(version, options);
@@ -1931,7 +1931,7 @@ var require_semver2 = __commonJS({
1931
1931
  "../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/index.js"(exports, module) {
1932
1932
  "use strict";
1933
1933
  var internalRe = require_re();
1934
- var constants3 = require_constants();
1934
+ var constants4 = require_constants();
1935
1935
  var SemVer = require_semver();
1936
1936
  var identifiers = require_identifiers();
1937
1937
  var parse2 = require_parse();
@@ -2015,8 +2015,8 @@ var require_semver2 = __commonJS({
2015
2015
  re: internalRe.re,
2016
2016
  src: internalRe.src,
2017
2017
  tokens: internalRe.t,
2018
- SEMVER_SPEC_VERSION: constants3.SEMVER_SPEC_VERSION,
2019
- RELEASE_TYPES: constants3.RELEASE_TYPES,
2018
+ SEMVER_SPEC_VERSION: constants4.SEMVER_SPEC_VERSION,
2019
+ RELEASE_TYPES: constants4.RELEASE_TYPES,
2020
2020
  compareIdentifiers: identifiers.compareIdentifiers,
2021
2021
  rcompareIdentifiers: identifiers.rcompareIdentifiers
2022
2022
  };
@@ -2805,6 +2805,12 @@ var harnessInfoSchema = z6.object({
2805
2805
  computerBroker: z6.literal(true).optional(),
2806
2806
  /** Run-scoped CLI approvals and policy-version checks are supported. */
2807
2807
  toolApproval: z6.literal(true).optional(),
2808
+ /**
2809
+ * The CLI exists but `installed` stays false because the daemon cannot run it
2810
+ * in a sandbox. `missing` names the absent packages; empty means the machine
2811
+ * itself refused isolation.
2812
+ */
2813
+ sandboxBlocked: z6.object({ missing: z6.array(z6.string().trim().min(1).max(64)).max(8) }).optional(),
2808
2814
  /** Version string reported by the CLI, null when not installed. */
2809
2815
  version: z6.string().nullable()
2810
2816
  });
@@ -4432,7 +4438,7 @@ import { join as join4 } from "node:path";
4432
4438
  // package.json
4433
4439
  var package_default = {
4434
4440
  name: "@mikka/daemon",
4435
- version: "0.0.86",
4441
+ version: "0.0.89",
4436
4442
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
4437
4443
  type: "module",
4438
4444
  private: true,
@@ -4491,7 +4497,7 @@ var package_default = {
4491
4497
  engines: {
4492
4498
  node: ">=24"
4493
4499
  },
4494
- gitHead: "da9593f91f3620f251d08a7260322a52cf39d23a"
4500
+ gitHead: "16b71d6c5aa7e0122cafab65524823236ecbad64"
4495
4501
  };
4496
4502
 
4497
4503
  // src/paths.ts
@@ -7073,6 +7079,7 @@ var RunContext = class {
7073
7079
  ],
7074
7080
  allowDomains: [
7075
7081
  ...HARNESS_DOMAINS[this.options.harness],
7082
+ ...this.options.harnessDomains ?? [],
7076
7083
  ...runAppsHost(this.options.apps) ? [runAppsHost(this.options.apps)] : [],
7077
7084
  ...runDomains(
7078
7085
  runPolicy(this.options.policy),
@@ -7596,15 +7603,15 @@ sandbox_mode = "read-only"
7596
7603
  // src/main.ts
7597
7604
  import { randomBytes as randomBytes3, randomUUID as randomUUID10 } from "node:crypto";
7598
7605
  import {
7599
- chmodSync as chmodSync4,
7600
- existsSync as existsSync7,
7601
- mkdirSync as mkdirSync16,
7602
- readFileSync as readFileSync11,
7603
- rmSync as rmSync17,
7606
+ chmodSync as chmodSync5,
7607
+ existsSync as existsSync8,
7608
+ mkdirSync as mkdirSync17,
7609
+ readFileSync as readFileSync12,
7610
+ rmSync as rmSync18,
7604
7611
  realpathSync as realpathSync13
7605
7612
  } from "node:fs";
7606
7613
  import { arch, hostname, platform as platform2 } from "node:os";
7607
- import { join as join28 } from "node:path";
7614
+ import { join as join32 } from "node:path";
7608
7615
  import { fileURLToPath as fileURLToPath3 } from "node:url";
7609
7616
 
7610
7617
  // src/adapters/claude.ts
@@ -7630,7 +7637,52 @@ function computerSandboxPolicy(policy, spec) {
7630
7637
  import { randomUUID as randomUUID3 } from "node:crypto";
7631
7638
  import { realpathSync as realpathSync9 } from "node:fs";
7632
7639
  import { homedir as homedir6 } from "node:os";
7633
- import { join as join14 } from "node:path";
7640
+
7641
+ // src/adapters/claude-gateway.ts
7642
+ import { readFileSync as readFileSync9 } from "node:fs";
7643
+ import { join as join13 } from "node:path";
7644
+ var GATEWAY_ENV = [
7645
+ "ANTHROPIC_BASE_URL",
7646
+ "ANTHROPIC_AUTH_TOKEN",
7647
+ "ANTHROPIC_API_KEY",
7648
+ "ANTHROPIC_MODEL",
7649
+ "ANTHROPIC_DEFAULT_FABLE_MODEL",
7650
+ "ANTHROPIC_DEFAULT_OPUS_MODEL",
7651
+ "ANTHROPIC_DEFAULT_SONNET_MODEL",
7652
+ "ANTHROPIC_DEFAULT_HAIKU_MODEL",
7653
+ "CLAUDE_CODE_SUBAGENT_MODEL"
7654
+ ];
7655
+ function readClaudeGateway(configDir) {
7656
+ let settings;
7657
+ try {
7658
+ settings = JSON.parse(readFileSync9(join13(configDir, "settings.json"), "utf8"));
7659
+ } catch {
7660
+ return null;
7661
+ }
7662
+ const declared = settings?.env;
7663
+ if (!declared || typeof declared !== "object") return null;
7664
+ const values = declared;
7665
+ const domain = gatewayDomain(values.ANTHROPIC_BASE_URL);
7666
+ if (!domain) return null;
7667
+ const env = {};
7668
+ for (const name of GATEWAY_ENV) {
7669
+ const value = values[name];
7670
+ if (typeof value === "string" && value) env[name] = value;
7671
+ }
7672
+ return { env, domain };
7673
+ }
7674
+ function gatewayDomain(baseUrl) {
7675
+ if (typeof baseUrl !== "string") return null;
7676
+ try {
7677
+ const url = new URL(baseUrl);
7678
+ return url.protocol === "https:" || url.protocol === "http:" ? url.hostname : null;
7679
+ } catch {
7680
+ return null;
7681
+ }
7682
+ }
7683
+
7684
+ // src/adapters/claude.ts
7685
+ import { join as join15 } from "node:path";
7634
7686
  import {
7635
7687
  query as query2,
7636
7688
  createSdkMcpServer as createSdkMcpServer2
@@ -7891,15 +7943,15 @@ function runNetworkApproval(runId, harness, gate, maximum, localComputerEndpoint
7891
7943
  // src/subscription-native-broker.ts
7892
7944
  import { chmodSync, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync4, rmSync as rmSync10 } from "node:fs";
7893
7945
  import { createServer } from "node:http";
7894
- import { join as join13 } from "node:path";
7946
+ import { join as join14 } from "node:path";
7895
7947
  import { once } from "node:events";
7896
7948
  var NATIVE_AUTH_PLACEHOLDER = "mikka-native-broker-placeholder";
7897
7949
  async function createNativeSubscriptionBroker(host) {
7898
7950
  await host.check();
7899
7951
  mkdirSync10(host.root, { recursive: true, mode: 448 });
7900
- const dir = mkdtempSync4(join13(host.root, "native-broker-"));
7952
+ const dir = mkdtempSync4(join14(host.root, "native-broker-"));
7901
7953
  chmodSync(dir, 448);
7902
- const socket = join13(dir, "broker.sock");
7954
+ const socket = join14(dir, "broker.sock");
7903
7955
  const pending = /* @__PURE__ */ new Set();
7904
7956
  let halted = false;
7905
7957
  const server = createServer(async (request, response) => {
@@ -8253,10 +8305,12 @@ var ClaudeAdapter = class {
8253
8305
  throw new Error(SUBSCRIPTION_ERROR);
8254
8306
  }
8255
8307
  }
8256
- const nativeHome = externalAuth ? join14(runDir, "native-home") : void 0;
8257
- const configDir = nativeHome ? join14(nativeHome, ".claude") : this.options.configDir ?? join14(homedir6(), ".claude");
8308
+ const nativeHome = externalAuth ? join15(runDir, "native-home") : void 0;
8309
+ const configDir = nativeHome ? join15(nativeHome, ".claude") : this.options.configDir ?? join15(homedir6(), ".claude");
8258
8310
  if (nativeHome) ownDir(configDir);
8311
+ const gateway = nativeHome || externalAuth ? null : readClaudeGateway(configDir);
8259
8312
  const ctx = new RunContext({
8313
+ harnessDomains: gateway ? [gateway.domain] : void 0,
8260
8314
  github: options.github,
8261
8315
  apps: options.apps,
8262
8316
  githubRuntime: options.githubRuntime,
@@ -8275,8 +8329,8 @@ var ClaudeAdapter = class {
8275
8329
  privateDir: paths.privateDir,
8276
8330
  // Its session store, so `resume` works; keyed by the cwd it sees.
8277
8331
  extraWrite: [
8278
- join14(configDir, "projects", claudeProjectDirName(options.cwd)),
8279
- join14(
8332
+ join15(configDir, "projects", claudeProjectDirName(options.cwd)),
8333
+ join15(
8280
8334
  configDir,
8281
8335
  "projects",
8282
8336
  claudeProjectDirName(realpathSync9(options.cwd))
@@ -8335,6 +8389,7 @@ var ClaudeAdapter = class {
8335
8389
  ...options.env,
8336
8390
  ...ctx.tempEnv(),
8337
8391
  ...CLAUDE_RUN_ENV,
8392
+ ...gateway?.env,
8338
8393
  CLAUDE_CODE_TMPDIR: ctx.tmpDir,
8339
8394
  ...nativeHome ? {
8340
8395
  HOME: nativeHome,
@@ -8521,7 +8576,26 @@ var ClaudeAdapter = class {
8521
8576
  };
8522
8577
 
8523
8578
  // src/adapters/codex.ts
8524
- import { isAbsolute as isAbsolute4, join as join15, relative as relative3 } from "node:path";
8579
+ import { isAbsolute as isAbsolute4, join as join16, relative as relative3 } from "node:path";
8580
+
8581
+ // src/adapters/codex-version.ts
8582
+ var VERSION = /(?:^|[ /])(\d+)\.(\d+)\.(\d+)(?:$|[ ();])/;
8583
+ var MINIMUM_APPROVAL_VERSION = [0, 162, 0];
8584
+ var AUDITED_DYNAMIC_TOOLS = "0.163.0";
8585
+ function codexSupportsRunApproval(version) {
8586
+ const match = VERSION.exec(version ?? "");
8587
+ if (!match) return false;
8588
+ for (const [index, minimum] of MINIMUM_APPROVAL_VERSION.entries()) {
8589
+ const part = Number(match[index + 1]);
8590
+ if (part !== minimum) return part > minimum;
8591
+ }
8592
+ return true;
8593
+ }
8594
+ function codexHasAuditedDynamicTools(version) {
8595
+ return VERSION.exec(version ?? "")?.slice(1).join(".") === AUDITED_DYNAMIC_TOOLS;
8596
+ }
8597
+
8598
+ // src/adapters/codex.ts
8525
8599
  var SUBSCRIPTION_AUTH_ERROR = "Codex subscription authentication unavailable";
8526
8600
  var SUBSCRIPTION_EXECUTION_ERROR2 = "Codex subscription execution failed";
8527
8601
  function subscriptionTokens(value, accountId) {
@@ -8690,8 +8764,8 @@ var CodexAdapter = class {
8690
8764
  options.continueSession.runId
8691
8765
  ).runDir;
8692
8766
  carryHistory(
8693
- join15(earlier2, "codex-home"),
8694
- join15(runDir, "codex-home"),
8767
+ join16(earlier2, "codex-home"),
8768
+ join16(runDir, "codex-home"),
8695
8769
  CODEX_HISTORY
8696
8770
  );
8697
8771
  } catch (error) {
@@ -8703,7 +8777,7 @@ var CodexAdapter = class {
8703
8777
  }
8704
8778
  }
8705
8779
  const codexHome = prepareCodexHome(
8706
- join15(runDir, "codex-home"),
8780
+ join16(runDir, "codex-home"),
8707
8781
  log,
8708
8782
  this.options.userHome,
8709
8783
  !externalAuth
@@ -9042,7 +9116,8 @@ var CodexAdapter = class {
9042
9116
  }),
9043
9117
  "initialize"
9044
9118
  );
9045
- 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");
9119
+ if (options.mailbox && !codexHasAuditedDynamicTools(initialized.userAgent)) throw new Error("Run permissions require the audited Codex0.163.0 tool interface");
9120
+ if (!codexSupportsRunApproval(initialized.userAgent)) throw new Error("This Codex version is too old for Mikka; update Codex");
9046
9121
  await rpc.sendNotification("initialized");
9047
9122
  if (externalAuth) {
9048
9123
  try {
@@ -9155,7 +9230,7 @@ var CodexAdapter = class {
9155
9230
  // src/adapters/cursor.ts
9156
9231
  import { Readable, Writable } from "node:stream";
9157
9232
  import * as acp from "@agentclientprotocol/sdk";
9158
- import { join as join16 } from "node:path";
9233
+ import { join as join17 } from "node:path";
9159
9234
  function acpPermissionResponse(params, policy) {
9160
9235
  const pick = (kinds) => {
9161
9236
  for (const kind of kinds) {
@@ -9290,15 +9365,15 @@ var CursorAdapter = class {
9290
9365
  options.continueSession.runId
9291
9366
  ).runDir;
9292
9367
  carryHistory(
9293
- join16(earlier2, "cursor-home"),
9294
- join16(paths.runDir, "cursor-home"),
9368
+ join17(earlier2, "cursor-home"),
9369
+ join17(paths.runDir, "cursor-home"),
9295
9370
  CURSOR_HISTORY
9296
9371
  );
9297
9372
  } catch (error) {
9298
9373
  log.info({ err: error }, "could not copy the earlier cursor chats");
9299
9374
  }
9300
9375
  }
9301
- const configDir = prepareCursorHome(join16(paths.runDir, "cursor-home"));
9376
+ const configDir = prepareCursorHome(join17(paths.runDir, "cursor-home"));
9302
9377
  const ctx = new RunContext({
9303
9378
  github: options.github,
9304
9379
  childPath: options.env.PATH,
@@ -9530,8 +9605,8 @@ ${firstMessage}` : firstMessage
9530
9605
 
9531
9606
  // src/adapters/mock.ts
9532
9607
  import { randomUUID as randomUUID4 } from "node:crypto";
9533
- import { mkdirSync as mkdirSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
9534
- import { dirname as dirname9, join as join17, resolve as resolve8 } from "node:path";
9608
+ import { mkdirSync as mkdirSync11, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "node:fs";
9609
+ import { dirname as dirname9, join as join18, resolve as resolve8 } from "node:path";
9535
9610
  import { setTimeout as sleep2 } from "node:timers/promises";
9536
9611
  import { execa as execa5 } from "execa";
9537
9612
 
@@ -9587,7 +9662,7 @@ var MockAdapter = class {
9587
9662
  fixturesDir;
9588
9663
  speed;
9589
9664
  stateFile(sessionId) {
9590
- return join17(
9665
+ return join18(
9591
9666
  this.options.stateDir,
9592
9667
  `mock-${assertSafeId("session id", sessionId)}.json`
9593
9668
  );
@@ -9631,7 +9706,7 @@ var MockAdapter = class {
9631
9706
  open(sessionId, state, options) {
9632
9707
  const name = assertSafeId("fixture", state.fixture.replace(/\.jsonl$/, ""));
9633
9708
  const lines = parseFixture(
9634
- readFileSync9(join17(this.fixturesDir, `${name}.jsonl`), "utf8"),
9709
+ readFileSync10(join18(this.fixturesDir, `${name}.jsonl`), "utf8"),
9635
9710
  name
9636
9711
  );
9637
9712
  const abort = new AbortController();
@@ -9745,18 +9820,18 @@ var MockAdapter = class {
9745
9820
 
9746
9821
  // src/agents/verify.ts
9747
9822
  import { mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync5, realpathSync as realpathSync10, rmSync as rmSync11 } from "node:fs";
9748
- import { join as join18 } from "node:path";
9823
+ import { join as join19 } from "node:path";
9749
9824
  var OUTPUT_TAIL = 4e3;
9750
9825
  async function runVerify(sandbox, options) {
9751
9826
  mkdirSync12(options.tmpRoot, { recursive: true, mode: 448 });
9752
- const tmpDir = mkdtempSync5(join18(realpathSync10(options.tmpRoot), "verify-"));
9827
+ const tmpDir = mkdtempSync5(join19(realpathSync10(options.tmpRoot), "verify-"));
9753
9828
  const child = await spawnCli(sandbox, ["/bin/sh", "-c", options.command], {
9754
9829
  cwd: options.worktree,
9755
9830
  env: { ...options.env, TMPDIR: tmpDir },
9756
9831
  policy: {
9757
9832
  allowWrite: options.readOnly ? [tmpDir] : [options.worktree, tmpDir],
9758
9833
  denyWrite: [
9759
- join18(options.worktree, ".git"),
9834
+ join19(options.worktree, ".git"),
9760
9835
  ...options.readOnly ? [options.worktree] : []
9761
9836
  ],
9762
9837
  denyRead: [
@@ -9927,7 +10002,7 @@ import { SandboxManager as SandboxManager2 } from "@anthropic-ai/sandbox-runtime
9927
10002
  import { execFile as execFile3 } from "node:child_process";
9928
10003
  import { readdir as readdir2, realpath, stat } from "node:fs/promises";
9929
10004
  import { homedir as homedir7, platform } from "node:os";
9930
- import { basename as basename2, dirname as dirname10, isAbsolute as isAbsolute5, join as join19, resolve as resolve9 } from "node:path";
10005
+ import { basename as basename2, dirname as dirname10, isAbsolute as isAbsolute5, join as join20, resolve as resolve9 } from "node:path";
9931
10006
  import { promisify as promisify3 } from "node:util";
9932
10007
  var run = promisify3(execFile3);
9933
10008
  async function git(cwd, args) {
@@ -9997,7 +10072,7 @@ async function browseFolder(request) {
9997
10072
  let truncated = false;
9998
10073
  const dirs = names.filter((e) => e.isDirectory() || e.isSymbolicLink()).filter((e) => request.showHidden || !e.name.startsWith(".")).sort((a, b) => a.name.localeCompare(b.name));
9999
10074
  for (const entry of dirs) {
10000
- const full = join19(path, entry.name);
10075
+ const full = join20(path, entry.name);
10001
10076
  if (entry.isSymbolicLink() && !await isDir(full)) continue;
10002
10077
  if (folders.length >= FS_MAX_ENTRIES) {
10003
10078
  truncated = true;
@@ -10006,7 +10081,7 @@ async function browseFolder(request) {
10006
10081
  folders.push({
10007
10082
  name: entry.name,
10008
10083
  path: full,
10009
- isRepo: await exists(join19(full, ".git"))
10084
+ isRepo: await exists(join20(full, ".git"))
10010
10085
  });
10011
10086
  }
10012
10087
  const parent = dirname10(path);
@@ -10063,6 +10138,9 @@ async function detectDeviceType() {
10063
10138
  }
10064
10139
 
10065
10140
  // src/harnesses.ts
10141
+ import { readdirSync as readdirSync4, statSync as statSync2 } from "node:fs";
10142
+ import { homedir as homedir8, userInfo } from "node:os";
10143
+ import { delimiter as delimiter3, isAbsolute as isAbsolute7, join as join22 } from "node:path";
10066
10144
  import { execa as execa9 } from "execa";
10067
10145
 
10068
10146
  // src/harness-models.ts
@@ -10208,12 +10286,99 @@ async function discover(harness, binary) {
10208
10286
  return {};
10209
10287
  }
10210
10288
 
10289
+ // src/path-search.ts
10290
+ import { accessSync, constants as constants2, statSync } from "node:fs";
10291
+ import { delimiter as delimiter2, isAbsolute as isAbsolute6, join as join21 } from "node:path";
10292
+ function findOnPath(command, path = process.env.PATH ?? "") {
10293
+ for (const directory of path.split(delimiter2)) {
10294
+ if (!directory) continue;
10295
+ const candidate = join21(directory, command);
10296
+ try {
10297
+ accessSync(candidate, constants2.X_OK);
10298
+ if (statSync(candidate).isFile()) return candidate;
10299
+ } catch {
10300
+ }
10301
+ }
10302
+ return null;
10303
+ }
10304
+ function appendToPath(directories) {
10305
+ const entries = (process.env.PATH ?? "").split(delimiter2).filter(Boolean);
10306
+ for (const directory of directories) {
10307
+ if (isAbsolute6(directory) && !entries.includes(directory)) entries.push(directory);
10308
+ }
10309
+ process.env.PATH = entries.join(delimiter2);
10310
+ }
10311
+
10211
10312
  // src/harnesses.ts
10212
10313
  var HARNESS_BINARIES = {
10213
10314
  claude_code: ["claude"],
10214
10315
  codex: ["codex"],
10215
10316
  cursor: ["cursor-agent", "agent"]
10216
10317
  };
10318
+ var LOGIN_SHELL_TIMEOUT_MS = 5e3;
10319
+ var PATH_MARKER = "__MIKKA_PATH__";
10320
+ function subdirectories(directory) {
10321
+ try {
10322
+ return readdirSync4(directory).map((name) => join22(directory, name));
10323
+ } catch {
10324
+ return [];
10325
+ }
10326
+ }
10327
+ function knownAgentDirectories(home = homedir8()) {
10328
+ return [
10329
+ join22(home, ".local/bin"),
10330
+ join22(home, "bin"),
10331
+ join22(home, ".claude/local"),
10332
+ join22(home, ".npm-global/bin"),
10333
+ join22(home, ".bun/bin"),
10334
+ join22(home, ".volta/bin"),
10335
+ join22(home, ".local/share/pnpm"),
10336
+ join22(home, "Library/pnpm"),
10337
+ join22(home, ".asdf/shims"),
10338
+ join22(home, ".local/share/mise/shims"),
10339
+ ...subdirectories(join22(home, ".nvm/versions/node")).map((version) => join22(version, "bin")),
10340
+ ...subdirectories(join22(home, ".local/share/fnm/node-versions")).map((version) => join22(version, "installation/bin")),
10341
+ "/opt/homebrew/bin",
10342
+ "/usr/local/bin",
10343
+ "/snap/bin"
10344
+ ];
10345
+ }
10346
+ async function loginShellPath(shell = process.env.SHELL || userInfo().shell) {
10347
+ if (!shell || !isAbsolute7(shell)) return [];
10348
+ let timer;
10349
+ try {
10350
+ const shellProcess = execa9(shell, ["-ilc", `printf '${PATH_MARKER}%s${PATH_MARKER}' "$PATH"`], {
10351
+ stdin: "ignore",
10352
+ detached: true,
10353
+ reject: false
10354
+ });
10355
+ const timedOut = new Promise((resolve12) => {
10356
+ timer = setTimeout(() => {
10357
+ try {
10358
+ process.kill(-shellProcess.pid, "SIGKILL");
10359
+ } catch {
10360
+ }
10361
+ resolve12(null);
10362
+ }, LOGIN_SHELL_TIMEOUT_MS);
10363
+ });
10364
+ const result = await Promise.race([shellProcess, timedOut]);
10365
+ return String(result?.stdout ?? "").split(PATH_MARKER)[1]?.split(delimiter3).filter(isAbsolute7) ?? [];
10366
+ } catch {
10367
+ return [];
10368
+ } finally {
10369
+ clearTimeout(timer);
10370
+ }
10371
+ }
10372
+ function harnessFingerprint() {
10373
+ appendToPath(knownAgentDirectories());
10374
+ return Object.values(HARNESS_BINARIES).map((binaries) => {
10375
+ for (const binary of binaries) {
10376
+ const found = findOnPath(binary);
10377
+ if (found) return `${found}:${statSync2(found).mtimeMs}`;
10378
+ }
10379
+ return "";
10380
+ }).join("|");
10381
+ }
10217
10382
  async function versionOf(binary) {
10218
10383
  try {
10219
10384
  const { stdout } = await execa9(binary, ["--version"], {
@@ -10229,6 +10394,7 @@ async function versionOf(binary) {
10229
10394
  }
10230
10395
  }
10231
10396
  async function detectHarnesses() {
10397
+ if (!daemonTestMode(process.env)) appendToPath([...await loginShellPath(), ...knownAgentDirectories()]);
10232
10398
  const detected = await Promise.all(
10233
10399
  Object.keys(HARNESS_BINARIES).map(
10234
10400
  async (harness) => {
@@ -10249,16 +10415,136 @@ async function detectHarnesses() {
10249
10415
  ];
10250
10416
  }
10251
10417
 
10418
+ // src/sandbox-tools.ts
10419
+ import { chmodSync as chmodSync2, existsSync as existsSync5, lstatSync as lstatSync8, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync6, readdirSync as readdirSync5, renameSync as renameSync2, rmSync as rmSync12, writeFileSync as writeFileSync7 } from "node:fs";
10420
+ import { join as join23 } from "node:path";
10421
+ import { execa as execa10 } from "execa";
10422
+ var TOOLS = [
10423
+ { command: "bwrap", package: "bubblewrap", versionFlag: "--version" },
10424
+ { command: "socat", package: "socat", versionFlag: "-V" },
10425
+ { command: "rg", package: "ripgrep", versionFlag: "--version" }
10426
+ ];
10427
+ var APT_TIMEOUT_MS = 12e4;
10428
+ var TOOL_CHECK_TIMEOUT_MS = 5e3;
10429
+ var runTool = async (file, args, cwd, env) => {
10430
+ const { stdout } = await execa10(file, args, { cwd, env, stdin: "ignore", timeout: file === "apt-get" ? APT_TIMEOUT_MS : TOOL_CHECK_TIMEOUT_MS });
10431
+ return { stdout: String(stdout) };
10432
+ };
10433
+ function sandboxToolsDir(dataDir) {
10434
+ return join23(dataDir, "sandbox-tools", "bin");
10435
+ }
10436
+ function missingSandboxTools() {
10437
+ return TOOLS.filter((tool2) => !findOnPath(tool2.command)).map((tool2) => tool2.package);
10438
+ }
10439
+ async function ensureSandboxTools(options) {
10440
+ if ((options.platform ?? process.platform) !== "linux") return [];
10441
+ const { dataDir, log, run: run2 = runTool } = options;
10442
+ const binDir = sandboxToolsDir(dataDir);
10443
+ appendToPath([binDir]);
10444
+ const needed = TOOLS.filter((tool2) => !findOnPath(tool2.command));
10445
+ if (needed.length === 0) return [];
10446
+ const packages = needed.map((tool2) => tool2.package);
10447
+ if (!findOnPath("apt-get") || !findOnPath("dpkg-deb")) {
10448
+ log.warn({ missing: packages }, "sandbox tools missing and apt is unavailable");
10449
+ return packages;
10450
+ }
10451
+ mkdirSync13(binDir, { recursive: true, mode: 448 });
10452
+ const work = mkdtempSync6(join23(dataDir, "sandbox-tools", ".install-"));
10453
+ try {
10454
+ const apt = await downloadPackages(work, packages, run2);
10455
+ for (const tool2 of needed) {
10456
+ try {
10457
+ await installTool(tool2, { work, dataDir, apt, run: run2 });
10458
+ } catch (err) {
10459
+ log.warn({ package: tool2.package, err: errorMessage2(err) }, "sandbox tool unusable on this machine");
10460
+ }
10461
+ }
10462
+ } catch (err) {
10463
+ log.warn({ missing: packages, err: errorMessage2(err) }, "could not download sandbox tools");
10464
+ } finally {
10465
+ rmSync12(work, { recursive: true, force: true });
10466
+ }
10467
+ const missing = missingSandboxTools();
10468
+ if (missing.length < packages.length) log.info({ installed: packages.filter((name) => !missing.includes(name)) }, "sandbox tools installed");
10469
+ return missing;
10470
+ }
10471
+ async function installTool(tool2, context) {
10472
+ const { work, dataDir, apt, run: run2 } = context;
10473
+ const root = join23(work, "root");
10474
+ await run2("dpkg-deb", ["-x", join23(work, debFile(work, tool2.package)), root], work);
10475
+ const unpacked = join23(root, "usr", "bin", tool2.command);
10476
+ chmodSync2(unpacked, 493);
10477
+ const binDir = sandboxToolsDir(dataDir);
10478
+ try {
10479
+ await run2(unpacked, [tool2.versionFlag], work);
10480
+ renameSync2(unpacked, join23(binDir, tool2.command));
10481
+ return;
10482
+ } catch {
10483
+ }
10484
+ const plan = await run2("apt-get", ["-s", "-qq", ...apt, "install", tool2.package], work);
10485
+ const dependencies = [...String(plan?.stdout ?? "").matchAll(/^Inst (\S+)/gm)].map((match) => match[1]).filter((name) => name !== tool2.package);
10486
+ if (dependencies.length === 0) throw new Error("the tool does not run and has no missing dependencies");
10487
+ await run2("apt-get", ["-qq", ...apt, "download", ...dependencies], work);
10488
+ for (const dependency of dependencies) await run2("dpkg-deb", ["-x", join23(work, debFile(work, dependency)), root], work);
10489
+ const libDir = join23(dataDir, "sandbox-tools", "lib");
10490
+ mkdirSync13(libDir, { recursive: true, mode: 448 });
10491
+ for (const directory of [join23(root, "lib"), join23(root, "usr", "lib")]) moveSharedLibraries(directory, libDir);
10492
+ await run2(unpacked, [tool2.versionFlag], work, { LD_LIBRARY_PATH: libDir });
10493
+ const realDir = join23(dataDir, "sandbox-tools", "libexec");
10494
+ mkdirSync13(realDir, { recursive: true, mode: 448 });
10495
+ renameSync2(unpacked, join23(realDir, tool2.command));
10496
+ const launcher = join23(work, `${tool2.command}.launcher`);
10497
+ writeFileSync7(launcher, `#!/bin/sh
10498
+ LD_LIBRARY_PATH=${shellQuote2(libDir)} exec ${shellQuote2(join23(realDir, tool2.command))} "$@"
10499
+ `, { mode: 493 });
10500
+ renameSync2(launcher, join23(binDir, tool2.command));
10501
+ }
10502
+ function moveSharedLibraries(directory, libDir) {
10503
+ if (!existsSync5(directory)) return;
10504
+ for (const entry of readdirSync5(directory)) {
10505
+ const path = join23(directory, entry);
10506
+ if (lstatSync8(path).isDirectory()) moveSharedLibraries(path, libDir);
10507
+ else if (entry.includes(".so") && !existsSync5(join23(libDir, entry))) renameSync2(path, join23(libDir, entry));
10508
+ }
10509
+ }
10510
+ function shellQuote2(value) {
10511
+ return `'${value.replaceAll("'", `'\\''`)}'`;
10512
+ }
10513
+ async function downloadPackages(work, packages, run2) {
10514
+ const cache = join23(work, "cache");
10515
+ mkdirSync13(join23(cache, "archives", "partial"), { recursive: true });
10516
+ const unprivileged = ["-o", `Dir::Cache=${cache}`, "-o", "Debug::NoLocking=1", "-o", "APT::Sandbox::User="];
10517
+ try {
10518
+ await run2("apt-get", ["-qq", ...unprivileged, "download", ...packages], work);
10519
+ return unprivileged;
10520
+ } catch {
10521
+ const lists = join23(work, "lists");
10522
+ mkdirSync13(join23(lists, "partial"), { recursive: true });
10523
+ const privateLists = [...unprivileged, "-o", `Dir::State::lists=${lists}`];
10524
+ await run2("apt-get", ["-qq", ...privateLists, "update"], work);
10525
+ await run2("apt-get", ["-qq", ...privateLists, "download", ...packages], work);
10526
+ return privateLists;
10527
+ }
10528
+ }
10529
+ function debFile(work, name) {
10530
+ const file = readdirSync5(work).find((entry) => entry === `${name}.deb` || entry.startsWith(`${name}_`));
10531
+ if (!file) throw new Error(`${name} package was not downloaded`);
10532
+ return file;
10533
+ }
10534
+ function errorMessage2(err) {
10535
+ return err instanceof Error ? err.message.slice(0, 300) : "unknown error";
10536
+ }
10537
+
10252
10538
  // src/outbox.ts
10253
10539
  import {
10254
10540
  appendFileSync,
10255
- mkdirSync as mkdirSync13,
10256
- readFileSync as readFileSync10,
10257
- readdirSync as readdirSync4,
10258
- rmSync as rmSync12,
10541
+ mkdirSync as mkdirSync14,
10542
+ readFileSync as readFileSync11,
10543
+ readdirSync as readdirSync6,
10544
+ rmSync as rmSync13,
10259
10545
  truncateSync
10260
10546
  } from "node:fs";
10261
- import { join as join20 } from "node:path";
10547
+ import { join as join24 } from "node:path";
10262
10548
  var Outbox = class {
10263
10549
  constructor(dir, link, log, retryMs = 1e3, onUndeliverable = () => void 0, retainResources = false) {
10264
10550
  this.dir = dir;
@@ -10267,7 +10553,7 @@ var Outbox = class {
10267
10553
  this.retryMs = retryMs;
10268
10554
  this.onUndeliverable = onUndeliverable;
10269
10555
  this.retainResources = retainResources;
10270
- mkdirSync13(dir, { recursive: true, mode: 448 });
10556
+ mkdirSync14(dir, { recursive: true, mode: 448 });
10271
10557
  }
10272
10558
  dir;
10273
10559
  link;
@@ -10281,15 +10567,15 @@ var Outbox = class {
10281
10567
  /** Runs whose file was checked for a torn tail since this process started. */
10282
10568
  repaired = /* @__PURE__ */ new Set();
10283
10569
  file(runId) {
10284
- return join20(this.dir, `${assertSafeId("run id", runId)}.jsonl`);
10570
+ return join24(this.dir, `${assertSafeId("run id", runId)}.jsonl`);
10285
10571
  }
10286
10572
  ackFile(runId) {
10287
- return join20(this.dir, `${assertSafeId("run id", runId)}.ack.json`);
10573
+ return join24(this.dir, `${assertSafeId("run id", runId)}.ack.json`);
10288
10574
  }
10289
10575
  parse(runId) {
10290
10576
  let data;
10291
10577
  try {
10292
- data = readFileSync10(this.file(runId));
10578
+ data = readFileSync11(this.file(runId));
10293
10579
  } catch {
10294
10580
  return { items: [], validBytes: 0, torn: false, tornTail: false };
10295
10581
  }
@@ -10374,7 +10660,7 @@ var Outbox = class {
10374
10660
  }
10375
10661
  runIds() {
10376
10662
  try {
10377
- return readdirSync4(this.dir).filter((name) => name.endsWith(".jsonl")).map((name) => name.slice(0, -".jsonl".length)).filter((runId) => isSafeId(runId));
10663
+ return readdirSync6(this.dir).filter((name) => name.endsWith(".jsonl")).map((name) => name.slice(0, -".jsonl".length)).filter((runId) => isSafeId(runId));
10378
10664
  } catch {
10379
10665
  return [];
10380
10666
  }
@@ -10442,8 +10728,8 @@ var Outbox = class {
10442
10728
  }
10443
10729
  remove(runId) {
10444
10730
  if (this.retainResources) return;
10445
- rmSync12(this.file(runId), { force: true });
10446
- rmSync12(this.ackFile(runId), { force: true });
10731
+ rmSync13(this.file(runId), { force: true });
10732
+ rmSync13(this.ackFile(runId), { force: true });
10447
10733
  }
10448
10734
  scheduleRetry() {
10449
10735
  if (this.retryTimer || this.closed) return;
@@ -10468,15 +10754,15 @@ var Outbox = class {
10468
10754
  };
10469
10755
 
10470
10756
  // src/quota/local-credentials.ts
10471
- import { homedir as homedir8 } from "node:os";
10472
- import { join as join22 } from "node:path";
10757
+ import { homedir as homedir9 } from "node:os";
10758
+ import { join as join26 } from "node:path";
10473
10759
 
10474
10760
  // src/quota/files.ts
10475
10761
  import { execFile as execFile4 } from "node:child_process";
10476
- import { constants as constants2 } from "node:fs";
10762
+ import { constants as constants3 } from "node:fs";
10477
10763
  import { lstat as lstat2, open } from "node:fs/promises";
10478
10764
  import { promisify as promisify4 } from "node:util";
10479
- var NOFOLLOW = constants2.O_NOFOLLOW ?? 0;
10765
+ var NOFOLLOW = constants3.O_NOFOLLOW ?? 0;
10480
10766
  var execFileAsync = promisify4(execFile4);
10481
10767
  var KEYCHAIN_TIMEOUT_MS = 3e4;
10482
10768
  var MAX_CREDENTIAL_BYTES = 64 * 1024;
@@ -10552,7 +10838,7 @@ async function readSecureFile(filePath, maxBytes = MAX_CREDENTIAL_BYTES) {
10552
10838
  if (before.size > maxBytes) {
10553
10839
  throw new Error(`Credential file exceeds ${maxBytes} bytes: ${filePath}`);
10554
10840
  }
10555
- const handle = await open(filePath, constants2.O_RDONLY | NOFOLLOW);
10841
+ const handle = await open(filePath, constants3.O_RDONLY | NOFOLLOW);
10556
10842
  try {
10557
10843
  const after = await handle.stat();
10558
10844
  assertRegularFile(after, filePath);
@@ -10967,12 +11253,12 @@ async function readCodexQuota(options) {
10967
11253
 
10968
11254
  // src/quota/cursor.ts
10969
11255
  import { lstat as lstat3 } from "node:fs/promises";
10970
- import { join as join21 } from "node:path";
11256
+ import { join as join25 } from "node:path";
10971
11257
  var ENDPOINT3 = "https://cursor.com/api/usage-summary";
10972
11258
  var ACCESS_TOKEN_KEY = "cursorAuth/accessToken";
10973
11259
  function cursorDatabasePath(platform3, home) {
10974
11260
  if (platform3 === "darwin") {
10975
- return join21(
11261
+ return join25(
10976
11262
  home,
10977
11263
  "Library",
10978
11264
  "Application Support",
@@ -10983,7 +11269,7 @@ function cursorDatabasePath(platform3, home) {
10983
11269
  );
10984
11270
  }
10985
11271
  if (platform3 === "win32") {
10986
- return join21(
11272
+ return join25(
10987
11273
  home,
10988
11274
  "AppData",
10989
11275
  "Roaming",
@@ -10993,7 +11279,7 @@ function cursorDatabasePath(platform3, home) {
10993
11279
  "state.vscdb"
10994
11280
  );
10995
11281
  }
10996
- return join21(home, ".config", "Cursor", "User", "globalStorage", "state.vscdb");
11282
+ return join25(home, ".config", "Cursor", "User", "globalStorage", "state.vscdb");
10997
11283
  }
10998
11284
  var CURSOR_PLANS = {
10999
11285
  pro: "Pro",
@@ -11165,10 +11451,10 @@ async function readCursorQuota(options) {
11165
11451
  // src/quota/local-credentials.ts
11166
11452
  var KEYCHAIN_SERVICE = "Claude Code-credentials";
11167
11453
  function claudeCredentialPath(home) {
11168
- return join22(home, ".claude", ".credentials.json");
11454
+ return join26(home, ".claude", ".credentials.json");
11169
11455
  }
11170
11456
  function codexAuthPath(home) {
11171
- return join22(home, ".codex", "auth.json");
11457
+ return join26(home, ".codex", "auth.json");
11172
11458
  }
11173
11459
  function unknown2(vendor, observedAt) {
11174
11460
  return {
@@ -11187,7 +11473,7 @@ var LocalCredentialsSource = class {
11187
11473
  options;
11188
11474
  id = "local_credentials";
11189
11475
  async read(signal) {
11190
- const home = this.options.home ?? homedir8();
11476
+ const home = this.options.home ?? homedir9();
11191
11477
  const platform3 = this.options.platform ?? process.platform;
11192
11478
  const fetchImpl = this.options.fetch ?? globalThis.fetch;
11193
11479
  const now = this.options.now ?? Date.now;
@@ -11320,7 +11606,7 @@ var QuotaPoller = class {
11320
11606
 
11321
11607
  // src/rpc/server.ts
11322
11608
  import { timingSafeEqual } from "node:crypto";
11323
- import { chmodSync as chmodSync2, rmSync as rmSync13 } from "node:fs";
11609
+ import { chmodSync as chmodSync3, rmSync as rmSync14 } from "node:fs";
11324
11610
  import { createServer as createServer2 } from "node:net";
11325
11611
  import {
11326
11612
  createMessageConnection as createMessageConnection2,
@@ -11361,13 +11647,13 @@ var RpcServer = class {
11361
11647
  sockets = /* @__PURE__ */ new Set();
11362
11648
  async listen() {
11363
11649
  const { socketPath } = this.options;
11364
- rmSync13(socketPath, { force: true });
11650
+ rmSync14(socketPath, { force: true });
11365
11651
  const server = createServer2((socket) => this.accept(socket));
11366
11652
  await new Promise((resolve12, reject) => {
11367
11653
  server.once("error", reject);
11368
11654
  server.listen(socketPath, () => resolve12());
11369
11655
  });
11370
- chmodSync2(socketPath, 384);
11656
+ chmodSync3(socketPath, 384);
11371
11657
  this.server = server;
11372
11658
  }
11373
11659
  accept(socket) {
@@ -11434,7 +11720,7 @@ var RpcServer = class {
11434
11720
  this.server.close(() => resolve12());
11435
11721
  });
11436
11722
  this.server = null;
11437
- rmSync13(this.options.socketPath, { force: true });
11723
+ rmSync14(this.options.socketPath, { force: true });
11438
11724
  }
11439
11725
  };
11440
11726
 
@@ -11497,12 +11783,12 @@ var RunJournal = class {
11497
11783
  };
11498
11784
 
11499
11785
  // src/runs/check.ts
11500
- import { execa as execa10 } from "execa";
11786
+ import { execa as execa11 } from "execa";
11501
11787
  async function fixedCheckSnapshot(repoPath, worktree, sha) {
11502
11788
  if (!/^[a-f0-9]{40}$/.test(sha))
11503
11789
  throw new Error("Check requires an exact candidate SHA");
11504
11790
  const gitDir = await worktreeGitDir(repoPath, worktree);
11505
- const git2 = async (...args) => (await execa10(
11791
+ const git2 = async (...args) => (await execa11(
11506
11792
  "git",
11507
11793
  [
11508
11794
  "-c",
@@ -11657,15 +11943,15 @@ function createRunMasker(secrets) {
11657
11943
 
11658
11944
  // src/runs/supervisor.ts
11659
11945
  import { createHash as createHash4, randomUUID as randomUUID6 } from "node:crypto";
11660
- import { join as join24, resolve as resolve10 } from "node:path";
11661
- import { execa as execa12 } from "execa";
11946
+ import { join as join28, resolve as resolve10 } from "node:path";
11947
+ import { execa as execa13 } from "execa";
11662
11948
 
11663
11949
  // src/agents/checkpoint.ts
11664
- import { mkdtempSync as mkdtempSync6, rmSync as rmSync14, writeFileSync as writeFileSync7 } from "node:fs";
11950
+ import { mkdtempSync as mkdtempSync7, rmSync as rmSync15, writeFileSync as writeFileSync8 } from "node:fs";
11665
11951
  import { tmpdir as tmpdir2 } from "node:os";
11666
- import { join as join23 } from "node:path";
11952
+ import { join as join27 } from "node:path";
11667
11953
  import { gunzipSync as gunzipSync2, gzipSync as gzipSync2 } from "node:zlib";
11668
- import { execa as execa11 } from "execa";
11954
+ import { execa as execa12 } from "execa";
11669
11955
  var CheckpointRecoveryError = class extends Error {
11670
11956
  constructor(message) {
11671
11957
  super(message);
@@ -11710,12 +11996,12 @@ async function takeCheckpoint(options) {
11710
11996
  }
11711
11997
  async function applyCheckpoint(options) {
11712
11998
  const git2 = await pinnedGit(options.repoPath, options.worktree);
11713
- const dir = mkdtempSync6(join23(tmpdir2(), "mikka-checkpoint-"));
11714
- const file = join23(dir, "checkpoint.patch");
11999
+ const dir = mkdtempSync7(join27(tmpdir2(), "mikka-checkpoint-"));
12000
+ const file = join27(dir, "checkpoint.patch");
11715
12001
  try {
11716
12002
  const patch = gunzipSync2(Buffer.from(options.checkpoint.patch, "base64"));
11717
12003
  if (!patch.length && options.checkpoint.files === 0) return true;
11718
- writeFileSync7(file, patch);
12004
+ writeFileSync8(file, patch);
11719
12005
  for (const args of [
11720
12006
  ["apply", "--binary", "--whitespace=nowarn", file],
11721
12007
  ["apply", "--binary", "--3way", "--whitespace=nowarn", file]
@@ -11728,11 +12014,11 @@ async function applyCheckpoint(options) {
11728
12014
  }
11729
12015
  return false;
11730
12016
  } finally {
11731
- rmSync14(dir, { recursive: true, force: true });
12017
+ rmSync15(dir, { recursive: true, force: true });
11732
12018
  }
11733
12019
  }
11734
12020
  async function hasCommit(repoPath, commit) {
11735
- return execa11(
12021
+ return execa12(
11736
12022
  "git",
11737
12023
  ["-c", "core.hooksPath=/dev/null", "cat-file", "-e", `${commit}^{commit}`],
11738
12024
  { cwd: repoPath, stdin: "ignore" }
@@ -12949,7 +13235,7 @@ var RunSupervisor = class {
12949
13235
  if (!this.deps.adapterStateDir || assignment.harness === "mock" || !session.sessionId || resuming && session.sessionId !== entry.sessionId || assignment.requireSessionResume && session.sessionId !== assignment.resumeSessionId)
12950
13236
  throw new Error("Skill mount requires the actual original harness session");
12951
13237
  verifySkillAssignment(assignment);
12952
- const file = join24(
13238
+ const file = join28(
12953
13239
  runPaths(this.deps.adapterStateDir, runId).runDir,
12954
13240
  SKILLS_DIR,
12955
13241
  skillSlug(assignment.skills[0].name),
@@ -13182,7 +13468,7 @@ function stopReasonOf(event, run2) {
13182
13468
  return event.outcome === "failed" ? "error" : "turn_ended";
13183
13469
  }
13184
13470
  async function unsandboxedVerify(run2) {
13185
- const result = await execa12(run2.command, {
13471
+ const result = await execa13(run2.command, {
13186
13472
  shell: true,
13187
13473
  cwd: run2.worktree,
13188
13474
  env: buildChildEnv(),
@@ -13213,10 +13499,10 @@ function fixedCandidateCheck(assignment) {
13213
13499
 
13214
13500
  // src/repositories.ts
13215
13501
  import { createHash as createHash5, randomUUID as randomUUID7 } from "node:crypto";
13216
- 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";
13217
- import { dirname as dirname11, join as join25, resolve as resolve11 } from "node:path";
13502
+ 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";
13503
+ import { dirname as dirname11, join as join29, resolve as resolve11 } from "node:path";
13218
13504
  import { setTimeout as delay2 } from "node:timers/promises";
13219
- import { execa as execa13 } from "execa";
13505
+ import { execa as execa14 } from "execa";
13220
13506
  import lockfile2 from "proper-lockfile";
13221
13507
  var RepositoryCache = class {
13222
13508
  constructor(root, allowFile = daemonTestMode(process.env), retainResources = false) {
@@ -13242,19 +13528,19 @@ var RepositoryCache = class {
13242
13528
  const release = await this.lock(path, signal);
13243
13529
  try {
13244
13530
  signal?.throwIfAborted();
13245
- const git2 = (args, cwd) => execa13("git", [
13531
+ const git2 = (args, cwd) => execa14("git", [
13246
13532
  ...FETCH_GIT,
13247
13533
  "-c",
13248
13534
  `protocol.file.allow=${this.allowFile ? "always" : "never"}`,
13249
13535
  ...args
13250
13536
  ], { cwd, env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }, stdin: "ignore", timeout: FETCH_TIMEOUT_MS, cancelSignal: signal, killDescendants: true });
13251
- if (!existsSync5(path)) {
13537
+ if (!existsSync6(path)) {
13252
13538
  const temporary = `${path}.clone-${randomUUID7()}`;
13253
13539
  try {
13254
13540
  await git2(["clone", "--no-checkout", "--no-hardlinks", "--no-recurse-submodules", "--", remote, temporary]);
13255
- renameSync2(temporary, path);
13541
+ renameSync3(temporary, path);
13256
13542
  } finally {
13257
- if (!this.retainResources) rmSync15(temporary, { recursive: true, force: true });
13543
+ if (!this.retainResources) rmSync16(temporary, { recursive: true, force: true });
13258
13544
  }
13259
13545
  } else {
13260
13546
  this.assertClone(path);
@@ -13274,36 +13560,36 @@ var RepositoryCache = class {
13274
13560
  await assertBranchName(baseBranch);
13275
13561
  return `origin/${baseBranch}`;
13276
13562
  }
13277
- const { stdout } = await execa13("git", [...FETCH_GIT, "symbolic-ref", "--short", "refs/remotes/origin/HEAD"], { cwd: path, stdin: "ignore" });
13563
+ const { stdout } = await execa14("git", [...FETCH_GIT, "symbolic-ref", "--short", "refs/remotes/origin/HEAD"], { cwd: path, stdin: "ignore" });
13278
13564
  if (!stdout.startsWith("origin/")) throw new Error("Repository default branch unavailable");
13279
13565
  return stdout.trim();
13280
13566
  }
13281
13567
  /** Cache paths for retention/orphan cleanup; never consult user checkouts. */
13282
13568
  paths() {
13283
13569
  const visit = (path) => {
13284
- if (!existsSync5(path) || lstatSync8(path).isSymbolicLink()) return [];
13285
- if (existsSync5(join25(path, ".git"))) {
13570
+ if (!existsSync6(path) || lstatSync9(path).isSymbolicLink()) return [];
13571
+ if (existsSync6(join29(path, ".git"))) {
13286
13572
  this.assertClone(path);
13287
13573
  return [path];
13288
13574
  }
13289
- return readdirSync5(path, { withFileTypes: true }).flatMap((entry) => entry.isDirectory() && !entry.name.endsWith(".lock") && !entry.name.includes(".clone-") ? visit(join25(path, entry.name)) : []);
13575
+ return readdirSync7(path, { withFileTypes: true }).flatMap((entry) => entry.isDirectory() && !entry.name.endsWith(".lock") && !entry.name.includes(".clone-") ? visit(join29(path, entry.name)) : []);
13290
13576
  };
13291
13577
  return visit(resolve11(this.root));
13292
13578
  }
13293
13579
  ensureParents(path) {
13294
- mkdirSync14(this.root, { recursive: true, mode: 448 });
13295
- if (lstatSync8(this.root).isSymbolicLink()) throw new Error("Repository cache contains a symlink");
13580
+ mkdirSync15(this.root, { recursive: true, mode: 448 });
13581
+ if (lstatSync9(this.root).isSymbolicLink()) throw new Error("Repository cache contains a symlink");
13296
13582
  const root = realpathSync11(this.root);
13297
13583
  let current = resolve11(this.root);
13298
13584
  for (const part of path.slice(current.length + 1).split("/").filter(Boolean)) {
13299
- current = join25(current, part);
13300
- if (existsSync5(current) && lstatSync8(current).isSymbolicLink()) throw new Error("Repository cache contains a symlink");
13301
- mkdirSync14(current, { recursive: true, mode: 448 });
13585
+ current = join29(current, part);
13586
+ if (existsSync6(current) && lstatSync9(current).isSymbolicLink()) throw new Error("Repository cache contains a symlink");
13587
+ mkdirSync15(current, { recursive: true, mode: 448 });
13302
13588
  if (!isInside(root, realpathSync11(current))) throw new Error("Repository cache escapes its directory");
13303
13589
  }
13304
13590
  }
13305
13591
  assertClone(path) {
13306
- if (lstatSync8(path).isSymbolicLink() || !lstatSync8(join25(path, ".git")).isDirectory() || lstatSync8(join25(path, ".git")).isSymbolicLink()) throw new Error("Repository cache is not a standard clone");
13592
+ if (lstatSync9(path).isSymbolicLink() || !lstatSync9(join29(path, ".git")).isDirectory() || lstatSync9(join29(path, ".git")).isSymbolicLink()) throw new Error("Repository cache is not a standard clone");
13307
13593
  if (!isInside(realpathSync11(this.root), realpathSync11(path))) throw new Error("Repository cache escapes its directory");
13308
13594
  }
13309
13595
  async lock(path, signal) {
@@ -13324,16 +13610,16 @@ var RepositoryCache = class {
13324
13610
  import { execFile as execFile5, spawn as spawn4 } from "node:child_process";
13325
13611
  import { randomUUID as randomUUID8 } from "node:crypto";
13326
13612
  import {
13327
- existsSync as existsSync6,
13328
- lstatSync as lstatSync9,
13329
- mkdirSync as mkdirSync15,
13330
- mkdtempSync as mkdtempSync7,
13331
- readdirSync as readdirSync6,
13613
+ existsSync as existsSync7,
13614
+ lstatSync as lstatSync10,
13615
+ mkdirSync as mkdirSync16,
13616
+ mkdtempSync as mkdtempSync8,
13617
+ readdirSync as readdirSync8,
13332
13618
  realpathSync as realpathSync12,
13333
- rmSync as rmSync16
13619
+ rmSync as rmSync17
13334
13620
  } from "node:fs";
13335
13621
  import { createRequire } from "node:module";
13336
- import { delimiter as delimiter2, dirname as dirname12, join as join27 } from "node:path";
13622
+ import { delimiter as delimiter4, dirname as dirname12, join as join31 } from "node:path";
13337
13623
  import { fileURLToPath as fileURLToPath2 } from "node:url";
13338
13624
  import { promisify as promisify5 } from "node:util";
13339
13625
 
@@ -13343,7 +13629,7 @@ import { chmod, mkdtemp, rm as rm2 } from "node:fs/promises";
13343
13629
  import { createServer as createServer3, request as httpRequest } from "node:http";
13344
13630
  import { connect, isIP as isIP3 } from "node:net";
13345
13631
  import { tmpdir as tmpdir3 } from "node:os";
13346
- import { join as join26 } from "node:path";
13632
+ import { join as join30 } from "node:path";
13347
13633
 
13348
13634
  // ../../lib/search/url-policy.ts
13349
13635
  import { BlockList, isIP as isIP2 } from "node:net";
@@ -13412,9 +13698,9 @@ function endToEndHeaders(input) {
13412
13698
  }
13413
13699
  async function startPublicEgress(options) {
13414
13700
  options.signal.throwIfAborted();
13415
- const directory = await mkdtemp(join26(tmpdir3(), "mikka-egress-"));
13701
+ const directory = await mkdtemp(join30(tmpdir3(), "mikka-egress-"));
13416
13702
  await chmod(directory, 448);
13417
- const socketPath = join26(directory, "egress.sock");
13703
+ const socketPath = join30(directory, "egress.sock");
13418
13704
  const lifetime = new AbortController();
13419
13705
  const signal = AbortSignal.any([options.signal, lifetime.signal]);
13420
13706
  const sockets = /* @__PURE__ */ new Set();
@@ -13571,8 +13857,8 @@ async function createHostedBotRunner(host) {
13571
13857
  }).catch(() => {
13572
13858
  throw unavailable2();
13573
13859
  });
13574
- const resources = join27(host.stateDir, "native-resources");
13575
- mkdirSync15(resources, { recursive: true, mode: 448 });
13860
+ const resources = join31(host.stateDir, "native-resources");
13861
+ mkdirSync16(resources, { recursive: true, mode: 448 });
13576
13862
  const removeResource = async (file, record) => {
13577
13863
  if (!/^mikka-native-(?:verify-)?[a-f0-9-]{36}$/.test(record.name) || !/^[a-f0-9-]{36}$/.test(record.nonce))
13578
13864
  throw unavailable2();
@@ -13592,9 +13878,9 @@ async function createHostedBotRunner(host) {
13592
13878
  if (record.state === "created" && /No such (?:container|object)/i.test(
13593
13879
  String(error.stderr)
13594
13880
  )) {
13595
- if (record.assets?.startsWith(join27(host.stateDir, "native-verify-git-")))
13596
- rmSync16(record.assets, { recursive: true, force: true });
13597
- rmSync16(file, { force: true });
13881
+ if (record.assets?.startsWith(join31(host.stateDir, "native-verify-git-")))
13882
+ rmSync17(record.assets, { recursive: true, force: true });
13883
+ rmSync17(file, { force: true });
13598
13884
  return;
13599
13885
  }
13600
13886
  throw new Error("native_runtime_cleanup_unconfirmed");
@@ -13603,13 +13889,13 @@ async function createHostedBotRunner(host) {
13603
13889
  if (labels?.["com.mikka.native.resource"] !== record.nonce || record.id && record.id !== id4)
13604
13890
  throw unavailable2();
13605
13891
  await exec3("docker", ["rm", "-f", id4], { env: bareEnv, timeout: 3e4 });
13606
- if (record.assets?.startsWith(join27(host.stateDir, "native-verify-git-")))
13607
- rmSync16(record.assets, { recursive: true, force: true });
13608
- rmSync16(file, { force: true });
13892
+ if (record.assets?.startsWith(join31(host.stateDir, "native-verify-git-")))
13893
+ rmSync17(record.assets, { recursive: true, force: true });
13894
+ rmSync17(file, { force: true });
13609
13895
  };
13610
- for (const name of readdirSync6(resources))
13896
+ for (const name of readdirSync8(resources))
13611
13897
  if (name.endsWith(".json")) {
13612
- const file = join27(resources, name);
13898
+ const file = join31(resources, name);
13613
13899
  const record = readJson(file);
13614
13900
  if (!record) throw unavailable2();
13615
13901
  await removeResource(file, record);
@@ -13620,7 +13906,7 @@ async function createHostedBotRunner(host) {
13620
13906
  const bundled = createRequire(
13621
13907
  require2.resolve("@anthropic-ai/claude-agent-sdk")
13622
13908
  );
13623
- claude ??= join27(
13909
+ claude ??= join31(
13624
13910
  dirname12(
13625
13911
  bundled.resolve(
13626
13912
  "@anthropic-ai/claude-agent-sdk-linux-x64/package.json"
@@ -13630,13 +13916,13 @@ async function createHostedBotRunner(host) {
13630
13916
  );
13631
13917
  } catch {
13632
13918
  }
13633
- const codex = host.binaries?.codex ?? (process.env.PATH ?? "").split(delimiter2).map((dir) => join27(dir, "codex")).find((path) => existsSync6(path));
13919
+ const codex = host.binaries?.codex ?? (process.env.PATH ?? "").split(delimiter4).map((dir) => join31(dir, "codex")).find((path) => existsSync7(path));
13634
13920
  const binaries = { codex, claude_code: claude };
13635
13921
  for (const kind of ["codex", "claude_code"])
13636
13922
  if (binaries[kind]) {
13637
13923
  try {
13638
13924
  binaries[kind] = realpathSync12(binaries[kind]);
13639
- if (!lstatSync9(binaries[kind]).isFile()) delete binaries[kind];
13925
+ if (!lstatSync10(binaries[kind]).isFile()) delete binaries[kind];
13640
13926
  } catch {
13641
13927
  delete binaries[kind];
13642
13928
  }
@@ -13644,12 +13930,12 @@ async function createHostedBotRunner(host) {
13644
13930
  if (!binaries.codex && !binaries.claude_code) throw unavailable2();
13645
13931
  const command = async (worktree, script, readOnly, timeoutMs, signal) => {
13646
13932
  const name = `mikka-native-verify-${randomUUID8()}`;
13647
- const file = join27(resources, name + ".json");
13933
+ const file = join31(resources, name + ".json");
13648
13934
  const resource = { name, nonce: randomUUID8(), state: "creating" };
13649
13935
  const timing = { createMs: 0, runMs: 0 };
13650
13936
  let phase = "create";
13651
13937
  let began = performance.now();
13652
- const gitCopy = mkdtempSync7(join27(host.stateDir, "native-verify-git-"));
13938
+ const gitCopy = mkdtempSync8(join31(host.stateDir, "native-verify-git-"));
13653
13939
  resource.assets = gitCopy;
13654
13940
  try {
13655
13941
  const cwd = realpathSync12(worktree);
@@ -13665,7 +13951,7 @@ async function createHostedBotRunner(host) {
13665
13951
  "--no-checkout",
13666
13952
  "--",
13667
13953
  cwd,
13668
- join27(gitCopy, "repo")
13954
+ join31(gitCopy, "repo")
13669
13955
  ],
13670
13956
  {
13671
13957
  env: {
@@ -13680,8 +13966,8 @@ async function createHostedBotRunner(host) {
13680
13966
  maxBuffer: 1024 * 1024
13681
13967
  }
13682
13968
  );
13683
- const safeGit = join27(gitCopy, "repo", ".git");
13684
- const protectedGit = lstatSync9(join27(cwd, ".git")).isFile() ? join27(cwd, ".git") : safeGit;
13969
+ const safeGit = join31(gitCopy, "repo", ".git");
13970
+ const protectedGit = lstatSync10(join31(cwd, ".git")).isFile() ? join31(cwd, ".git") : safeGit;
13685
13971
  writeJsonAtomic(file, resource);
13686
13972
  const created = await exec3(
13687
13973
  "docker",
@@ -13768,8 +14054,8 @@ async function createHostedBotRunner(host) {
13768
14054
  timing
13769
14055
  };
13770
14056
  } finally {
13771
- if (existsSync6(file)) await removeResource(file, resource);
13772
- else rmSync16(gitCopy, { recursive: true, force: true });
14057
+ if (existsSync7(file)) await removeResource(file, resource);
14058
+ else rmSync17(gitCopy, { recursive: true, force: true });
13773
14059
  }
13774
14060
  };
13775
14061
  return {
@@ -13785,7 +14071,7 @@ async function createHostedBotRunner(host) {
13785
14071
  throw unavailable2();
13786
14072
  const name = `mikka-native-${randomUUID8()}`;
13787
14073
  const nonce = randomUUID8();
13788
- const resourceFile = join27(resources, name + ".json");
14074
+ const resourceFile = join31(resources, name + ".json");
13789
14075
  const resource = { name, nonce, state: "creating" };
13790
14076
  const lifetime = new AbortController();
13791
14077
  let closed = false;
@@ -13824,7 +14110,7 @@ async function createHostedBotRunner(host) {
13824
14110
  void brokerClosed.catch(() => void 0);
13825
14111
  try {
13826
14112
  await creating?.catch(() => void 0);
13827
- if (existsSync6(resourceFile)) await removeResource(resourceFile, resource);
14113
+ if (existsSync7(resourceFile)) await removeResource(resourceFile, resource);
13828
14114
  } finally {
13829
14115
  try {
13830
14116
  await brokerClosed;
@@ -13857,11 +14143,11 @@ async function createHostedBotRunner(host) {
13857
14143
  return current;
13858
14144
  };
13859
14145
  const paths = runPaths(host.stateDir, assignment.runId);
13860
- mkdirSync15(paths.runDir, { recursive: true, mode: 448 });
13861
- const shadow = join27(paths.runDir, "runtime-git");
13862
- const emptyHome = join27(paths.runDir, "git-bootstrap-home");
13863
- mkdirSync15(emptyHome, { recursive: true, mode: 448 });
13864
- if (!existsSync6(shadow))
14146
+ mkdirSync16(paths.runDir, { recursive: true, mode: 448 });
14147
+ const shadow = join31(paths.runDir, "runtime-git");
14148
+ const emptyHome = join31(paths.runDir, "git-bootstrap-home");
14149
+ mkdirSync16(emptyHome, { recursive: true, mode: 448 });
14150
+ if (!existsSync7(shadow))
13865
14151
  await exec3(
13866
14152
  "git",
13867
14153
  [
@@ -13890,9 +14176,9 @@ async function createHostedBotRunner(host) {
13890
14176
  }
13891
14177
  );
13892
14178
  await live();
13893
- if (!lstatSync9(shadow).isDirectory() || !lstatSync9(join27(shadow, ".git")).isDirectory() || !realpathSync12(shadow).startsWith(realpathSync12(paths.runDir) + "/"))
14179
+ if (!lstatSync10(shadow).isDirectory() || !lstatSync10(join31(shadow, ".git")).isDirectory() || !realpathSync12(shadow).startsWith(realpathSync12(paths.runDir) + "/"))
13894
14180
  throw unavailable2();
13895
- const ledger = join27(
14181
+ const ledger = join31(
13896
14182
  host.stateDir,
13897
14183
  "native-ledgers",
13898
14184
  assignment.runId + ".json"
@@ -13909,15 +14195,15 @@ async function createHostedBotRunner(host) {
13909
14195
  modelId: first.modelId
13910
14196
  };
13911
14197
  const previous = readJson(ledger);
13912
- if (existsSync6(ledger) && (!previous || JSON.stringify(previous.scope) !== JSON.stringify(scope) || typeof previous.sessionId !== "string"))
14198
+ if (existsSync7(ledger) && (!previous || JSON.stringify(previous.scope) !== JSON.stringify(scope) || typeof previous.sessionId !== "string"))
13913
14199
  throw unavailable2();
13914
- mkdirSync15(dirname12(ledger), { recursive: true, mode: 448 });
14200
+ mkdirSync16(dirname12(ledger), { recursive: true, mode: 448 });
13915
14201
  const record = async (sessionId) => {
13916
14202
  assertOpen();
13917
14203
  writeJsonAtomic(ledger, { scope, sessionId });
13918
14204
  };
13919
14205
  brokerStarting = createNativeSubscriptionBroker({
13920
- root: join27(host.stateDir, "native-brokers"),
14206
+ root: join31(host.stateDir, "native-brokers"),
13921
14207
  revision,
13922
14208
  check,
13923
14209
  worker: {
@@ -13944,7 +14230,7 @@ async function createHostedBotRunner(host) {
13944
14230
  });
13945
14231
  const readyBroker = await brokerStarting;
13946
14232
  await live();
13947
- const githubCli = options.github ? (process.env.PATH ?? "").split(delimiter2).map((dir) => join27(dir, "gh")).find((file) => existsSync6(file)) : void 0;
14233
+ const githubCli = options.github ? (process.env.PATH ?? "").split(delimiter4).map((dir) => join31(dir, "gh")).find((file) => existsSync7(file)) : void 0;
13948
14234
  if (options.github && !githubCli) throw new Error("Install GitHub CLI (gh) in the cloud worker image");
13949
14235
  const githubDomains = options.github ? ["github.com", "api.github.com", new URL(options.github.endpoint).host] : [];
13950
14236
  const egressMaximum = runDomains(runPolicy(options.policy), [...options.networkAllow ?? [], ...githubDomains]);
@@ -13961,8 +14247,8 @@ async function createHostedBotRunner(host) {
13961
14247
  }
13962
14248
  const cwd = realpathSync12(options.cwd);
13963
14249
  const runDir = realpathSync12(paths.runDir);
13964
- const protectedGit = lstatSync9(join27(cwd, ".git")).isFile() ? join27(cwd, ".git") : join27(shadow, ".git");
13965
- if (!lstatSync9(runDir).isDirectory() || !runDir.startsWith(realpathSync12(host.stateDir) + "/runs/")) {
14250
+ const protectedGit = lstatSync10(join31(cwd, ".git")).isFile() ? join31(cwd, ".git") : join31(shadow, ".git");
14251
+ if (!lstatSync10(runDir).isDirectory() || !runDir.startsWith(realpathSync12(host.stateDir) + "/runs/")) {
13966
14252
  await close();
13967
14253
  throw unavailable2();
13968
14254
  }
@@ -14015,7 +14301,7 @@ async function createHostedBotRunner(host) {
14015
14301
  `${MCP_SERVER_SCRIPT}:${MCP_SERVER_SCRIPT}:ro`,
14016
14302
  ...githubCli ? ["-v", `${githubCli}:/usr/local/bin/mikka-gh:ro`, "-v", `${GITHUB_CREDENTIAL_SCRIPT}:${GITHUB_CREDENTIAL_SCRIPT}:ro`] : [],
14017
14303
  "-v",
14018
- `${join27(dirname12(MCP_SERVER_SCRIPT), "capture-copy.mjs")}:${join27(dirname12(MCP_SERVER_SCRIPT), "capture-copy.mjs")}:ro`,
14304
+ `${join31(dirname12(MCP_SERVER_SCRIPT), "capture-copy.mjs")}:${join31(dirname12(MCP_SERVER_SCRIPT), "capture-copy.mjs")}:ro`,
14019
14305
  "-v",
14020
14306
  `${readyBroker.socket}:/run/mikka-native.sock:ro`,
14021
14307
  ...computerGrant ? [
@@ -14058,13 +14344,13 @@ async function createHostedBotRunner(host) {
14058
14344
  }
14059
14345
  const spawnHosted = (config) => {
14060
14346
  assertOpen();
14061
- const home = join27(runDir, "runtime-home");
14062
- mkdirSync15(home, { recursive: true, mode: 448 });
14347
+ const home = join31(runDir, "runtime-home");
14348
+ mkdirSync16(home, { recursive: true, mode: 448 });
14063
14349
  const env = {
14064
14350
  ...config.env,
14065
14351
  HOME: kind === "claude_code" ? config.env.HOME ?? home : home,
14066
- PATH: `${options.github ? join27(runDir, "github", "bin") + ":" : ""}/usr/local/bin:/usr/bin:/bin`,
14067
- GIT_DIR: join27(shadow, ".git"),
14352
+ PATH: `${options.github ? join31(runDir, "github", "bin") + ":" : ""}/usr/local/bin:/usr/bin:/bin`,
14353
+ GIT_DIR: join31(shadow, ".git"),
14068
14354
  GIT_WORK_TREE: cwd,
14069
14355
  GIT_CONFIG_GLOBAL: "/dev/null",
14070
14356
  GIT_CONFIG_SYSTEM: "/dev/null",
@@ -14083,7 +14369,7 @@ async function createHostedBotRunner(host) {
14083
14369
  signal: AbortSignal.any([lifetime.signal, ...config.signal ? [config.signal] : []])
14084
14370
  });
14085
14371
  child.stdin.write(
14086
- JSON.stringify({ kind, args: config.args, cwd, env: task.env, publicEgress: Boolean(egress), ...options.github ? { githubBin: join27(runDir, "github", "bin") } : {} }) + "\n"
14372
+ JSON.stringify({ kind, args: config.args, cwd, env: task.env, publicEgress: Boolean(egress), ...options.github ? { githubBin: join31(runDir, "github", "bin") } : {} }) + "\n"
14087
14373
  );
14088
14374
  return child;
14089
14375
  };
@@ -14218,7 +14504,7 @@ import {
14218
14504
  createHash as createHash7,
14219
14505
  timingSafeEqual as timingSafeEqual2
14220
14506
  } from "node:crypto";
14221
- import { chmodSync as chmodSync3 } from "node:fs";
14507
+ import { chmodSync as chmodSync4 } from "node:fs";
14222
14508
  import { createServer as createServer4 } from "node:net";
14223
14509
 
14224
14510
  // src/computer/driver.mjs
@@ -14468,7 +14754,7 @@ var ComputerBroker = class {
14468
14754
  else this.server.listen(this.socketPath, resolve12);
14469
14755
  });
14470
14756
  if (this.transport === "tcp") this.socketPath = `tcp://127.0.0.1:${this.server.address().port}`;
14471
- else chmodSync3(this.socketPath, 384);
14757
+ else chmodSync4(this.socketPath, 384);
14472
14758
  }
14473
14759
  request(token, value, signal) {
14474
14760
  const grant = this.grants.get(token);
@@ -14692,6 +14978,11 @@ function loadDeviceFile(raw) {
14692
14978
  }
14693
14979
  return file;
14694
14980
  }
14981
+ var HARNESS_RESCAN_MS = 5 * 6e4;
14982
+ var SANDBOX_REPAIR_RETRY_MS = 60 * 6e4;
14983
+ function missingToolsUnchanged(issue) {
14984
+ return !issue?.missing.length || missingSandboxTools().length === issue.missing.length;
14985
+ }
14695
14986
  var Daemon = class {
14696
14987
  constructor(options) {
14697
14988
  this.options = options;
@@ -14763,8 +15054,8 @@ var Daemon = class {
14763
15054
  }
14764
15055
  async startInternal() {
14765
15056
  const { paths } = this;
14766
- mkdirSync16(paths.dataDir, { recursive: true, mode: 448 });
14767
- if (process.platform !== "win32") chmodSync4(paths.dataDir, 448);
15057
+ mkdirSync17(paths.dataDir, { recursive: true, mode: 448 });
15058
+ if (process.platform !== "win32") chmodSync5(paths.dataDir, 448);
14768
15059
  this.releaseLock = await acquireLock(
14769
15060
  paths.dataDir,
14770
15061
  paths.lock,
@@ -14777,7 +15068,7 @@ var Daemon = class {
14777
15068
  if (this.options.credential)
14778
15069
  this.saveDevice({ credential: this.options.credential });
14779
15070
  this.journal = new RunJournal(paths.journal);
14780
- this.captureUploader = new CaptureUploader((runId) => join28(runPaths(paths.adapterState, runId).runDir, CAPTURES_DIR), this.options.link, this.log, join28(paths.dataDir, "capture-pending"));
15071
+ this.captureUploader = new CaptureUploader((runId) => join32(runPaths(paths.adapterState, runId).runDir, CAPTURES_DIR), this.options.link, this.log, join32(paths.dataDir, "capture-pending"));
14781
15072
  this.outbox = new Outbox(
14782
15073
  paths.outbox,
14783
15074
  this.options.link,
@@ -14794,7 +15085,7 @@ var Daemon = class {
14794
15085
  if (this.localComputerDriver && this.options.link.syncComputerReviews && this.options.link.localComputerAuthority) {
14795
15086
  this.localComputerBroker = new ComputerBroker({
14796
15087
  driver: this.localComputerDriver,
14797
- socketPath: join28(paths.dataDir, "local-computer.sock"),
15088
+ socketPath: join32(paths.dataDir, "local-computer.sock"),
14798
15089
  transport: "tcp",
14799
15090
  permitted: (runId) => {
14800
15091
  const assignment = this.journal.get(runId)?.assignment;
@@ -14836,7 +15127,7 @@ var Daemon = class {
14836
15127
  };
14837
15128
  this.cloudComputerBroker = new ComputerBroker({
14838
15129
  driver,
14839
- socketPath: join28(paths.dataDir, "computer.sock"),
15130
+ socketPath: join32(paths.dataDir, "computer.sock"),
14840
15131
  permitted: (runId) => {
14841
15132
  const entry = this.journal.get(runId);
14842
15133
  return Boolean(!this.stopped && this.registered && entry?.assignment.computer && this.supervisor?.computerRunAllowed(runId));
@@ -14959,7 +15250,7 @@ var Daemon = class {
14959
15250
  worktree,
14960
15251
  tree,
14961
15252
  github: { ...assignment.github, runToken: assignment.mcp.token, issueId: assignment.issueId },
14962
- privateDir: join28(paths.adapterState, "pids"),
15253
+ privateDir: join32(paths.adapterState, "pids"),
14963
15254
  ...hosted ? { hosted: true } : {},
14964
15255
  env: githubReceiptEnvironment()
14965
15256
  }) : publishRun({
@@ -15000,17 +15291,16 @@ var Daemon = class {
15000
15291
  if (this.stopped) throw new Error("daemon stopped during startup");
15001
15292
  const detected = hosted ? hosted.harnesses.map((harness) => ({ harness, installed: true, version: null, subscriptionBroker: true, ...this.cloudComputerBroker ? { computerBroker: true } : {} })) : this.options.harnesses ?? await detectHarnesses();
15002
15293
  if (this.stopped) throw new Error("daemon stopped during startup");
15003
- const runApprovalTransport = typeof this.options.link.prepareRunToolApproval === "function";
15004
- const localIsolation = this.ownedSandbox !== null && this.sandbox === this.ownedSandbox;
15005
- this.harnesses = detected.filter((info) => this.adapters.has(info.harness)).map((info) => ({
15294
+ if (!hosted && !this.options.harnesses) this.harnessPrint = harnessFingerprint();
15295
+ this.harnesses = [...detected.filter((info) => this.adapters.has(info.harness)).map((info) => ({
15006
15296
  ...info,
15007
15297
  // Local enforcement requires the successful owned SRT probe. Hosted
15008
15298
  // enforcement uses its existing network-none/read-only Docker boundary
15009
15299
  // and gate-bound broker/container teardown; general egress stays outside
15010
15300
  // that ceiling. Codex also verifies its pinned interface at initialize.
15011
- toolApproval: runApprovalTransport && (hosted || localIsolation && (info.harness === "claude_code" || info.harness === "codex" && /(?:^|[ /])0\.163\.0(?:$|[ ();])/.test(info.version ?? ""))) ? true : void 0,
15301
+ toolApproval: this.supportsToolApproval(info),
15012
15302
  coordinator: hosted ? false : coordinatorCapable(info)
15013
- }));
15303
+ })), ...this.sandboxBlockedHarnesses(detected)];
15014
15304
  await this.supervisor.resumeAll();
15015
15305
  if (!hosted && this.options.quotaSource !== null) {
15016
15306
  this.quota = new QuotaPoller(
@@ -15194,6 +15484,58 @@ var Daemon = class {
15194
15484
  }
15195
15485
  return acted;
15196
15486
  }
15487
+ supportsToolApproval(info) {
15488
+ if (typeof this.options.link.prepareRunToolApproval !== "function") return void 0;
15489
+ if (this.options.hostedSubscriptions) return true;
15490
+ if (this.ownedSandbox === null || this.sandbox !== this.ownedSandbox) return void 0;
15491
+ return info.harness === "claude_code" || info.harness === "codex" && codexSupportsRunApproval(info.version) ? true : void 0;
15492
+ }
15493
+ /** Report a CLI the daemon cannot run as present but not installed, so no run is pinned here. */
15494
+ sandboxBlockedHarnesses(detected) {
15495
+ const issue = this.sandboxIssue;
15496
+ if (!issue) return [];
15497
+ return detected.filter((info) => info.installed && !this.adapters.has(info.harness)).map((info) => ({
15498
+ harness: info.harness,
15499
+ installed: false,
15500
+ version: info.version,
15501
+ sandboxBlocked: { missing: issue.missing }
15502
+ }));
15503
+ }
15504
+ async redetectHarnesses() {
15505
+ const repairing = this.sandboxIssue?.missing.length;
15506
+ if (this.sandboxIssue && repairing) {
15507
+ this.lastSandboxRepair = Date.now();
15508
+ this.sandboxIssue = { missing: await ensureSandboxTools({ dataDir: this.paths.dataDir, log: this.log }) };
15509
+ }
15510
+ const detected = await detectHarnesses();
15511
+ this.harnessPrint = harnessFingerprint();
15512
+ this.harnesses = [...detected.filter((info) => this.adapters.has(info.harness)).map((info) => {
15513
+ return { ...info, toolApproval: this.supportsToolApproval(info), coordinator: coordinatorCapable(info) };
15514
+ }), ...this.sandboxBlockedHarnesses(detected)];
15515
+ if (repairing && this.sandboxIssue?.missing.length === 0) {
15516
+ this.startMaintenance(() => restartService(false, () => {
15517
+ }, void 0, () => !this.stopped));
15518
+ }
15519
+ }
15520
+ /** Notice an agent installed after startup, or retry a failed tool download, without spawning anything per tick. */
15521
+ rescanHarnesses() {
15522
+ const now = Date.now();
15523
+ if (this.options.hostedSubscriptions || this.options.harnesses || this.rescanning || now - this.lastHarnessScan < HARNESS_RESCAN_MS) return;
15524
+ this.lastHarnessScan = now;
15525
+ const retryRepair = Boolean(this.sandboxIssue?.missing.length) && now - this.lastSandboxRepair >= SANDBOX_REPAIR_RETRY_MS;
15526
+ if (harnessFingerprint() === this.harnessPrint && !retryRepair && missingToolsUnchanged(this.sandboxIssue)) return;
15527
+ this.rescanning = true;
15528
+ void this.redetectHarnesses().then(() => this.syncWithServer()).catch((err) => {
15529
+ this.log.warn({ err }, "harness rescan failed");
15530
+ }).finally(() => {
15531
+ this.rescanning = false;
15532
+ });
15533
+ }
15534
+ harnessPrint = "";
15535
+ lastHarnessScan = Date.now();
15536
+ lastSandboxRepair = Date.now();
15537
+ rescanning = false;
15538
+ sandboxIssue = null;
15197
15539
  sandbox = null;
15198
15540
  ownedSandbox = null;
15199
15541
  /** The agent sandbox (one per daemon), or null where there is none. */
@@ -15202,8 +15544,10 @@ var Daemon = class {
15202
15544
  }
15203
15545
  async createAgentSandbox() {
15204
15546
  if (this.options.agentSandbox !== void 0) return this.options.agentSandbox;
15547
+ const missing = await ensureSandboxTools({ dataDir: this.paths.dataDir, log: this.log });
15205
15548
  if (!SandboxRuntime.supported()) {
15206
- this.log.warn("agent sandbox unavailable: platform or dependencies unsupported");
15549
+ this.log.warn({ missing }, "agent sandbox unavailable: platform or dependencies unsupported");
15550
+ this.sandboxIssue = { missing };
15207
15551
  return null;
15208
15552
  }
15209
15553
  const sandbox = new SandboxRuntime(async ({ host }) => {
@@ -15220,6 +15564,7 @@ var Daemon = class {
15220
15564
  return sandbox;
15221
15565
  } catch (err) {
15222
15566
  this.log.warn({ err }, "agent sandbox unavailable");
15567
+ this.sandboxIssue = { missing: [] };
15223
15568
  if (!this.options.retainResources) await sandbox.reset().catch((resetError) => {
15224
15569
  this.log.warn({ err: resetError }, "agent sandbox cleanup failed");
15225
15570
  });
@@ -15243,11 +15588,11 @@ var Daemon = class {
15243
15588
  return runVerify(sandbox, {
15244
15589
  command,
15245
15590
  worktree: realpathSync13(worktree),
15246
- tmpRoot: join28(this.paths.adapterState, "verify", runId),
15591
+ tmpRoot: join32(this.paths.adapterState, "verify", runId),
15247
15592
  privateDir: paths.privateDir,
15248
15593
  pidFile: paths.pidFile.replace(/\.pgid$/, ".verify.pgid"),
15249
15594
  networkAllow: repo.networkAllow,
15250
- env: { ...buildChildEnv(), MIKKA_HANDOFF_FILE: join28(paths.runDir, "handoff.json") },
15595
+ env: { ...buildChildEnv(), MIKKA_HANDOFF_FILE: join32(paths.runDir, "handoff.json") },
15251
15596
  timeoutMs,
15252
15597
  signal,
15253
15598
  readOnly
@@ -15292,8 +15637,8 @@ var Daemon = class {
15292
15637
  void this.stop().finally(() => this.options.onLockLost?.(error));
15293
15638
  }
15294
15639
  ensureSecret() {
15295
- if (existsSync7(this.paths.secret)) {
15296
- return readFileSync11(this.paths.secret, "utf8").trim();
15640
+ if (existsSync8(this.paths.secret)) {
15641
+ return readFileSync12(this.paths.secret, "utf8").trim();
15297
15642
  }
15298
15643
  const secret = randomBytes3(32).toString("hex");
15299
15644
  writeFileAtomic(this.paths.secret, `${secret}
@@ -15390,6 +15735,7 @@ var Daemon = class {
15390
15735
  this.revokeLocalComputerGrants();
15391
15736
  this.registered = false;
15392
15737
  }
15738
+ this.rescanHarnesses();
15393
15739
  const command = deviceCommands?.[0];
15394
15740
  if (command?.kind === "uninstall") {
15395
15741
  this.draining = true;
@@ -15403,7 +15749,7 @@ var Daemon = class {
15403
15749
  setImmediate(() => {
15404
15750
  void this.stop().then(() => uninstallService(() => {
15405
15751
  this.saveDevice({ credential: void 0 });
15406
- rmSync17(this.paths.secret, { force: true });
15752
+ rmSync18(this.paths.secret, { force: true });
15407
15753
  })).catch(() => {
15408
15754
  this.options.onDrained?.();
15409
15755
  });
@@ -15415,11 +15761,7 @@ var Daemon = class {
15415
15761
  if (command.kind === "redetect" || this.maintenanceIdle()) {
15416
15762
  try {
15417
15763
  if (command.kind === "redetect") {
15418
- const detected = await detectHarnesses();
15419
- this.harnesses = detected.filter((info) => this.adapters.has(info.harness)).map((info) => {
15420
- const previous = this.harnesses.find((old) => old.harness === info.harness && old.version === info.version);
15421
- return { ...info, toolApproval: previous?.toolApproval, coordinator: coordinatorCapable(info) };
15422
- });
15764
+ await this.redetectHarnesses();
15423
15765
  this.saveDevice({ completedDeviceCommands: [command.id], failedDeviceCommands: [] });
15424
15766
  void this.syncWithServer().catch(() => void 0);
15425
15767
  } else {
@@ -15732,7 +16074,7 @@ var Daemon = class {
15732
16074
  if (!job || controller.signal.aborted) return;
15733
16075
  await runNativeCoordinatorJob(job, {
15734
16076
  deviceId,
15735
- stateDir: join28(this.paths.dataDir, "coordinator"),
16077
+ stateDir: join32(this.paths.dataDir, "coordinator"),
15736
16078
  link,
15737
16079
  signal: controller.signal,
15738
16080
  sandbox,
@@ -15775,7 +16117,7 @@ var Daemon = class {
15775
16117
  }, void 0, () => !this.stopped);
15776
16118
  });
15777
16119
  } else if (!this.updateCheck && !this.updateVersion) {
15778
- this.updateCheck = checkLatestVersion(join28(this.paths.dataDir, "auto-update.json"), DAEMON_VERSION, runtime).then((version) => {
16120
+ this.updateCheck = checkLatestVersion(join32(this.paths.dataDir, "auto-update.json"), DAEMON_VERSION, runtime).then((version) => {
15779
16121
  this.updateVersion = version;
15780
16122
  }).catch(() => {
15781
16123
  this.log.warn("Daemon automatic update check failed");
@@ -15833,7 +16175,7 @@ async function startDaemon(options) {
15833
16175
  }
15834
16176
 
15835
16177
  // src/rpc/client.ts
15836
- import { readFileSync as readFileSync12 } from "node:fs";
16178
+ import { readFileSync as readFileSync13 } from "node:fs";
15837
16179
  import { connect as connect2 } from "node:net";
15838
16180
  import {
15839
16181
  createMessageConnection as createMessageConnection3,
@@ -15913,7 +16255,7 @@ function connectDaemonInDataDir(dataDir, client, extra = {}) {
15913
16255
  const paths = daemonPaths(dataDir);
15914
16256
  let secret;
15915
16257
  try {
15916
- secret = readFileSync12(paths.secret, "utf8").trim();
16258
+ secret = readFileSync13(paths.secret, "utf8").trim();
15917
16259
  } catch (error) {
15918
16260
  return Promise.reject(error);
15919
16261
  }