@aspectlylabs/mikka 0.0.141 → 0.0.143

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
@@ -3561,6 +3561,16 @@ var setupRecipeSchema = z14.object({
3561
3561
  approved: z14.boolean()
3562
3562
  });
3563
3563
  var REPO_ORIGIN_HEADER = "x-mikka-repo-origin-check";
3564
+ var MODEL_CREDENTIAL_HEADER = "x-mikka-model-credential";
3565
+ var credentialKey = z14.string().min(1).max(4096).refine((value) => !/[\r\n\0]/.test(value));
3566
+ var credentialBaseUrl = z14.url().max(500).refine((value) => {
3567
+ const url = new URL(value);
3568
+ return url.protocol === "https:" && !url.username && !url.password && !url.search && !url.hash;
3569
+ });
3570
+ var runModelCredentialSchema = z14.discriminatedUnion("kind", [
3571
+ z14.object({ kind: z14.literal("api_key"), key: credentialKey }).strict(),
3572
+ z14.object({ kind: z14.literal("provider"), protocol: z14.enum(["anthropic", "openai"]), baseUrl: credentialBaseUrl, key: credentialKey }).strict()
3573
+ ]);
3564
3574
  var deviceRepoSchema = z14.object({
3565
3575
  repoId: id2,
3566
3576
  name: z14.string().max(500),
@@ -3608,6 +3618,12 @@ var runAssignmentSchema = z14.object({
3608
3618
  consumerId: z14.uuid(),
3609
3619
  route: z14.enum(["codex_cli", "claude_code_cli"])
3610
3620
  }).strict().optional(),
3621
+ /**
3622
+ * The run's own API key, opened for this claim only. Never with
3623
+ * `subscriptionBinding`. The daemon keeps it in memory and hands it only
3624
+ * to the run's Agent process or container; it is never journaled.
3625
+ */
3626
+ modelCredential: runModelCredentialSchema.optional(),
3611
3627
  /** Local host authority comes only from the server's owner-bound Bot run. */
3612
3628
  localComputer: z14.object({
3613
3629
  botId: z14.uuid(),
@@ -3725,7 +3741,7 @@ var runAssignmentSchema = z14.object({
3725
3741
  skillReceipt: skillAssignmentReceiptSchema.optional(),
3726
3742
  /** Frozen by the server benchmark ledger; never extracted from model output. */
3727
3743
  benchmark: runBenchmarkContext.optional()
3728
- });
3744
+ }).refine((value) => !(value.modelCredential && value.subscriptionBinding), { message: "A run has one model credential", path: ["modelCredential"] });
3729
3745
  var runPatchSchema = z14.object({
3730
3746
  state: z14.enum([
3731
3747
  "queued",
@@ -4458,7 +4474,7 @@ import { join as join4 } from "node:path";
4458
4474
  // package.json
4459
4475
  var package_default = {
4460
4476
  name: "@mikka/daemon",
4461
- version: "0.0.141",
4477
+ version: "0.0.143",
4462
4478
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
4463
4479
  type: "module",
4464
4480
  private: true,
@@ -4518,7 +4534,7 @@ var package_default = {
4518
4534
  engines: {
4519
4535
  node: ">=24"
4520
4536
  },
4521
- gitHead: "dec8d3597bd9fb2b049a00efcee8e64d3288f2fa"
4537
+ gitHead: "1a7ea7ffcdb44a8228f84d936a7a395f33f13355"
4522
4538
  };
4523
4539
 
4524
4540
  // src/paths.ts
@@ -5359,6 +5375,7 @@ var HttpServerLink = class {
5359
5375
  [TEAM_SKILL_HEADER]: "1",
5360
5376
  [REPO_ORIGIN_HEADER]: "1",
5361
5377
  [RECOVERY_WORKTREE_HEADER]: "1",
5378
+ [MODEL_CREDENTIAL_HEADER]: "1",
5362
5379
  ...token ? { authorization: `Bearer ${token}` } : {},
5363
5380
  ...this.protectionBypass ? { "x-vercel-protection-bypass": this.protectionBypass } : {}
5364
5381
  },
@@ -7659,15 +7676,15 @@ sandbox_mode = "read-only"
7659
7676
  // src/main.ts
7660
7677
  import { randomBytes as randomBytes4, randomUUID as randomUUID10 } from "node:crypto";
7661
7678
  import {
7662
- chmodSync as chmodSync5,
7679
+ chmodSync as chmodSync6,
7663
7680
  existsSync as existsSync9,
7664
- mkdirSync as mkdirSync18,
7681
+ mkdirSync as mkdirSync19,
7665
7682
  readFileSync as readFileSync12,
7666
- rmSync as rmSync20,
7683
+ rmSync as rmSync21,
7667
7684
  realpathSync as realpathSync12
7668
7685
  } from "node:fs";
7669
7686
  import { arch as arch2, hostname, platform as platform3 } from "node:os";
7670
- import { join as join31 } from "node:path";
7687
+ import { join as join32 } from "node:path";
7671
7688
  import { fileURLToPath as fileURLToPath4 } from "node:url";
7672
7689
 
7673
7690
  // src/adapters/claude.ts
@@ -8509,7 +8526,8 @@ var ClaudeAdapter = class {
8509
8526
  },
8510
8527
  ...mode === "new" ? { sessionId } : { resume: sessionId },
8511
8528
  ...options.model ? { model: options.model } : {},
8512
- ...outerLocal ? { spawnClaudeCodeProcess: spawnOuter } : this.options.spawnHosted && externalAuth ? { spawnClaudeCodeProcess: (options2) => this.options.spawnHosted(options2, nativeToken) } : binary || externalAuth ? { spawnClaudeCodeProcess: spawnBinary(binary, nativeToken) } : {},
8529
+ // A hosted runtime always spawns into its own container; an API-key run there holds the placeholder too.
8530
+ ...outerLocal ? { spawnClaudeCodeProcess: spawnOuter } : this.options.spawnHosted ? { spawnClaudeCodeProcess: (options2) => this.options.spawnHosted(options2, nativeToken ?? NATIVE_AUTH_PLACEHOLDER) } : binary || externalAuth ? { spawnClaudeCodeProcess: spawnBinary(binary, nativeToken) } : {},
8513
8531
  stderr: (data) => {
8514
8532
  if (!externalAuth) stderr = (stderr + data).slice(-STDERR_TAIL2 * 4);
8515
8533
  }
@@ -11476,7 +11494,10 @@ function withoutTaskEnv(assignment) {
11476
11494
 
11477
11495
  // src/runs/journal.ts
11478
11496
  function persisted(entries) {
11479
- return Object.fromEntries(Object.entries(entries).map(([id4, entry]) => [id4, { ...entry, assignment: withoutTaskEnv(entry.assignment) }]));
11497
+ return Object.fromEntries(Object.entries(entries).map(([id4, entry]) => {
11498
+ const { modelCredential, ...assignment } = withoutTaskEnv(entry.assignment);
11499
+ return [id4, { ...entry, assignment, ...modelCredential ? { credentialWithheld: true } : {} }];
11500
+ }));
11480
11501
  }
11481
11502
  var RunJournal = class {
11482
11503
  constructor(file) {
@@ -12241,10 +12262,10 @@ var RunSupervisor = class {
12241
12262
  }
12242
12263
  const existing = this.deps.journal.get(assignment.runId);
12243
12264
  if (existing) return this.summary(existing);
12244
- const masker = createRunMasker((assignment.taskSecretNames ?? []).flatMap((name) => {
12265
+ const masker = createRunMasker([...(assignment.taskSecretNames ?? []).flatMap((name) => {
12245
12266
  const value = assignment.taskEnv?.[name];
12246
12267
  return typeof value === "string" ? [{ name, value }] : [];
12247
- }));
12268
+ }), ...assignment.modelCredential ? [{ name: "MODEL_API_KEY", value: assignment.modelCredential.key }] : []]);
12248
12269
  if (masker) this.maskers.set(assignment.runId, masker);
12249
12270
  let repo;
12250
12271
  try {
@@ -12344,6 +12365,10 @@ var RunSupervisor = class {
12344
12365
  }
12345
12366
  continue;
12346
12367
  }
12368
+ if (entry.credentialWithheld && !entry.assignment.modelCredential) {
12369
+ this.finish(entry.assignment.runId, "error", "The run stopped with the daemon; its API key is not kept. Retry the thread.");
12370
+ continue;
12371
+ }
12347
12372
  if (entry.assignment.leaseExpiresAt)
12348
12373
  this.leases.set(entry.assignment.runId, Date.now() + DEFAULT_LEASE_MS);
12349
12374
  this.launch(entry.assignment.runId, repo);
@@ -12921,7 +12946,9 @@ var RunSupervisor = class {
12921
12946
  } : void 0,
12922
12947
  fixture: assignment.fixture,
12923
12948
  model: assignment.model,
12924
- mailbox
12949
+ mailbox,
12950
+ // In memory only: the adapter hands it to the run's CLI environment.
12951
+ credential: assignment.modelCredential
12925
12952
  };
12926
12953
  const resuming = entry.sessionId !== null && adapter.capabilities.supportsResume;
12927
12954
  const inEarlierWorktree = continued !== null || entry.worktree !== null && resolve11(entry.worktree) !== resolve11(this.deps.worktrees.pathFor(runId));
@@ -12946,8 +12973,9 @@ var RunSupervisor = class {
12946
12973
  const previousExecution = entry.execution;
12947
12974
  const previousRuntime = entry.runtime;
12948
12975
  let session;
12976
+ if (assignment.subscriptionBinding && assignment.modelCredential) throw new Error("A run has one model credential");
12949
12977
  try {
12950
- session = assignment.subscriptionBinding ? this.deps.startSubscription ? await this.deps.startSubscription(assignment, { ...options, prompt: assignment.prompt }) : (() => {
12978
+ session = assignment.modelCredential && this.deps.startCredential ? await this.deps.startCredential(assignment, { ...options, prompt: assignment.prompt }) : assignment.subscriptionBinding ? this.deps.startSubscription ? await this.deps.startSubscription(assignment, { ...options, prompt: assignment.prompt }) : (() => {
12951
12979
  throw new Error("subscription_hosted_runtime_unavailable");
12952
12980
  })() : resuming ? await adapter.resume(entry.sessionId, options) : await (async () => {
12953
12981
  if (assignment.requireSessionResume)
@@ -13351,16 +13379,141 @@ import { randomUUID as randomUUID8 } from "node:crypto";
13351
13379
  import {
13352
13380
  existsSync as existsSync8,
13353
13381
  lstatSync as lstatSync10,
13354
- mkdirSync as mkdirSync17,
13355
- mkdtempSync as mkdtempSync8,
13382
+ mkdirSync as mkdirSync18,
13383
+ mkdtempSync as mkdtempSync9,
13356
13384
  readdirSync as readdirSync9,
13357
13385
  realpathSync as realpathSync11,
13358
- rmSync as rmSync19
13386
+ rmSync as rmSync20
13359
13387
  } from "node:fs";
13360
13388
  import { createRequire } from "node:module";
13361
- import { delimiter as delimiter3, dirname as dirname15, join as join30 } from "node:path";
13389
+ import { delimiter as delimiter3, dirname as dirname15, join as join31 } from "node:path";
13362
13390
  import { fileURLToPath as fileURLToPath3 } from "node:url";
13363
13391
  import { promisify as promisify6 } from "node:util";
13392
+
13393
+ // src/api-key-broker.ts
13394
+ import { chmodSync as chmodSync4, mkdirSync as mkdirSync17, mkdtempSync as mkdtempSync8, rmSync as rmSync19 } from "node:fs";
13395
+ import { createServer as createServer4 } from "node:http";
13396
+ import { join as join30 } from "node:path";
13397
+ import { once as once2 } from "node:events";
13398
+ var DEFAULT_BASE = { anthropic: "https://api.anthropic.com", openai: "https://api.openai.com/v1" };
13399
+ var PATHS = {
13400
+ anthropic: /* @__PURE__ */ new Set(["/v1/messages", "/v1/messages/count_tokens"]),
13401
+ openai: /* @__PURE__ */ new Set(["/responses", "/responses/compact"])
13402
+ };
13403
+ var FORWARD = ["content-type", "accept", "anthropic-version", "anthropic-beta", "openai-beta", "user-agent"];
13404
+ var RETURN = ["content-type", "retry-after", "request-id", "x-request-id"];
13405
+ var MAX_BODY = 32 * 1024 * 1024;
13406
+ async function createApiKeyBroker(host) {
13407
+ const { credential, protocol } = host;
13408
+ if (credential.kind === "provider" && credential.protocol !== protocol) throw new Error("api_key_broker_unavailable");
13409
+ const base = new URL(credential.kind === "provider" ? credential.baseUrl : DEFAULT_BASE[protocol]);
13410
+ if (base.protocol !== "https:" || base.username || base.password || !credential.key || /[\r\n\0]/.test(credential.key))
13411
+ throw new Error("api_key_broker_unavailable");
13412
+ const origin = base.href.replace(/\/+$/, "");
13413
+ let key2 = credential.key;
13414
+ const send = host.fetch ?? fetch;
13415
+ await host.check();
13416
+ mkdirSync17(host.root, { recursive: true, mode: 448 });
13417
+ const dir = mkdtempSync8(join30(host.root, "api-key-broker-"));
13418
+ chmodSync4(dir, 448);
13419
+ const socket = join30(dir, "broker.sock");
13420
+ const pending = /* @__PURE__ */ new Set();
13421
+ let halted = false;
13422
+ const server = createServer4(async (request, response) => {
13423
+ const abort = new AbortController();
13424
+ pending.add(abort);
13425
+ response.on("close", () => {
13426
+ if (!response.writableFinished) abort.abort();
13427
+ });
13428
+ try {
13429
+ const url = new URL(request.url ?? "/", "http://broker");
13430
+ if (halted || !key2 || request.method !== "POST" || (request.url ?? "").length > 256 || !PATHS[protocol].has(url.pathname) || url.search && url.search !== "?beta=true") {
13431
+ response.writeHead(404, { "content-type": "application/json", "cache-control": "no-store" }).end('{"error":"not_found"}');
13432
+ return;
13433
+ }
13434
+ const chunks = [];
13435
+ let length = 0;
13436
+ for await (const part of request) {
13437
+ length += part.length;
13438
+ if (length > MAX_BODY) throw new Error("request refused");
13439
+ chunks.push(part);
13440
+ }
13441
+ await host.check();
13442
+ if (halted || !key2 || abort.signal.aborted) throw new Error("request refused");
13443
+ const headers = {};
13444
+ for (const name of FORWARD) {
13445
+ const value = request.headers[name];
13446
+ if (typeof value === "string") headers[name] = value;
13447
+ }
13448
+ if (headers["anthropic-beta"]) {
13449
+ const betas = headers["anthropic-beta"].split(",").map((item) => item.trim()).filter((item) => item && !item.startsWith("oauth-"));
13450
+ if (betas.length) headers["anthropic-beta"] = betas.join(",");
13451
+ else delete headers["anthropic-beta"];
13452
+ }
13453
+ if (protocol === "anthropic") headers["x-api-key"] = key2;
13454
+ else headers.authorization = `Bearer ${key2}`;
13455
+ const upstream = await send(origin + url.pathname + url.search, {
13456
+ method: "POST",
13457
+ headers,
13458
+ body: Buffer.concat(chunks),
13459
+ redirect: "error",
13460
+ signal: abort.signal,
13461
+ cache: "no-store"
13462
+ });
13463
+ const returned = { "cache-control": "no-store" };
13464
+ for (const name of RETURN) {
13465
+ const value = upstream.headers.get(name);
13466
+ if (value) returned[name] = value;
13467
+ }
13468
+ response.writeHead(upstream.status, returned);
13469
+ if (upstream.body) {
13470
+ const reader = upstream.body.getReader();
13471
+ try {
13472
+ for (; ; ) {
13473
+ const { done, value } = await reader.read();
13474
+ if (done) break;
13475
+ if (abort.signal.aborted) throw new Error("request cancelled");
13476
+ if (!response.write(value)) await once2(response, "drain", { signal: abort.signal });
13477
+ }
13478
+ } finally {
13479
+ await reader.cancel().catch(() => void 0);
13480
+ reader.releaseLock();
13481
+ }
13482
+ }
13483
+ response.end();
13484
+ } catch {
13485
+ abort.abort();
13486
+ if (response.headersSent) response.destroy();
13487
+ else response.writeHead(502, { "content-type": "application/json", "cache-control": "no-store" }).end(JSON.stringify({ type: "error", error: { type: "api_key_unavailable", message: "API key unavailable" } }));
13488
+ } finally {
13489
+ pending.delete(abort);
13490
+ }
13491
+ });
13492
+ try {
13493
+ await new Promise((resolve13, reject) => {
13494
+ server.once("error", reject);
13495
+ server.listen(socket, resolve13);
13496
+ });
13497
+ chmodSync4(socket, 384);
13498
+ } catch {
13499
+ key2 = void 0;
13500
+ rmSync19(dir, { recursive: true, force: true });
13501
+ throw new Error("api_key_broker_unavailable");
13502
+ }
13503
+ return {
13504
+ socket,
13505
+ async close() {
13506
+ halted = true;
13507
+ key2 = void 0;
13508
+ for (const abort of pending) abort.abort();
13509
+ server.closeAllConnections();
13510
+ await new Promise((resolve13) => server.close(() => resolve13()));
13511
+ rmSync19(dir, { recursive: true, force: true });
13512
+ }
13513
+ };
13514
+ }
13515
+
13516
+ // src/subscription-hosted-runner.ts
13364
13517
  var exec3 = promisify6(execFile6);
13365
13518
  var image = HOSTED_NATIVE_IMAGE;
13366
13519
  var bootstrap = fileURLToPath3(
@@ -13385,8 +13538,8 @@ async function createHostedBotRunner(host) {
13385
13538
  }).catch(() => {
13386
13539
  throw unavailable3();
13387
13540
  });
13388
- const resources = join30(host.stateDir, "native-resources");
13389
- mkdirSync17(resources, { recursive: true, mode: 448 });
13541
+ const resources = join31(host.stateDir, "native-resources");
13542
+ mkdirSync18(resources, { recursive: true, mode: 448 });
13390
13543
  const removeResource = async (file, record) => {
13391
13544
  if (!/^mikka-native-(?:verify-)?[a-f0-9-]{36}$/.test(record.name) || !/^[a-f0-9-]{36}$/.test(record.nonce))
13392
13545
  throw unavailable3();
@@ -13406,9 +13559,9 @@ async function createHostedBotRunner(host) {
13406
13559
  if (record.state === "created" && /No such (?:container|object)/i.test(
13407
13560
  String(error.stderr)
13408
13561
  )) {
13409
- if (record.assets?.startsWith(join30(host.stateDir, "native-verify-git-")))
13410
- rmSync19(record.assets, { recursive: true, force: true });
13411
- rmSync19(file, { force: true });
13562
+ if (record.assets?.startsWith(join31(host.stateDir, "native-verify-git-")))
13563
+ rmSync20(record.assets, { recursive: true, force: true });
13564
+ rmSync20(file, { force: true });
13412
13565
  return;
13413
13566
  }
13414
13567
  throw new Error("native_runtime_cleanup_unconfirmed");
@@ -13417,13 +13570,13 @@ async function createHostedBotRunner(host) {
13417
13570
  if (labels?.["com.mikka.native.resource"] !== record.nonce || record.id && record.id !== id4)
13418
13571
  throw unavailable3();
13419
13572
  await exec3("docker", ["rm", "-f", id4], { env: bareEnv, timeout: 3e4 });
13420
- if (record.assets?.startsWith(join30(host.stateDir, "native-verify-git-")))
13421
- rmSync19(record.assets, { recursive: true, force: true });
13422
- rmSync19(file, { force: true });
13573
+ if (record.assets?.startsWith(join31(host.stateDir, "native-verify-git-")))
13574
+ rmSync20(record.assets, { recursive: true, force: true });
13575
+ rmSync20(file, { force: true });
13423
13576
  };
13424
13577
  for (const name of readdirSync9(resources))
13425
13578
  if (name.endsWith(".json")) {
13426
- const file = join30(resources, name);
13579
+ const file = join31(resources, name);
13427
13580
  const record = readJson(file);
13428
13581
  if (!record) throw unavailable3();
13429
13582
  await removeResource(file, record);
@@ -13434,7 +13587,7 @@ async function createHostedBotRunner(host) {
13434
13587
  const bundled = createRequire(
13435
13588
  require2.resolve("@anthropic-ai/claude-agent-sdk")
13436
13589
  );
13437
- claude ??= join30(
13590
+ claude ??= join31(
13438
13591
  dirname15(
13439
13592
  bundled.resolve(
13440
13593
  "@anthropic-ai/claude-agent-sdk-linux-x64/package.json"
@@ -13444,7 +13597,7 @@ async function createHostedBotRunner(host) {
13444
13597
  );
13445
13598
  } catch {
13446
13599
  }
13447
- const codex = host.binaries?.codex ?? (process.env.PATH ?? "").split(delimiter3).map((dir) => join30(dir, "codex")).find((path) => existsSync8(path));
13600
+ const codex = host.binaries?.codex ?? (process.env.PATH ?? "").split(delimiter3).map((dir) => join31(dir, "codex")).find((path) => existsSync8(path));
13448
13601
  const binaries = { codex, claude_code: claude };
13449
13602
  for (const kind of ["codex", "claude_code"])
13450
13603
  if (binaries[kind]) {
@@ -13458,12 +13611,12 @@ async function createHostedBotRunner(host) {
13458
13611
  if (!binaries.codex && !binaries.claude_code) throw unavailable3();
13459
13612
  const command = async (worktree, script, readOnly, timeoutMs, signal) => {
13460
13613
  const name = `mikka-native-verify-${randomUUID8()}`;
13461
- const file = join30(resources, name + ".json");
13614
+ const file = join31(resources, name + ".json");
13462
13615
  const resource = { name, nonce: randomUUID8(), state: "creating" };
13463
13616
  const timing = { createMs: 0, runMs: 0 };
13464
13617
  let phase = "create";
13465
13618
  let began = performance.now();
13466
- const gitCopy = mkdtempSync8(join30(host.stateDir, "native-verify-git-"));
13619
+ const gitCopy = mkdtempSync9(join31(host.stateDir, "native-verify-git-"));
13467
13620
  resource.assets = gitCopy;
13468
13621
  try {
13469
13622
  const cwd = realpathSync11(worktree);
@@ -13479,7 +13632,7 @@ async function createHostedBotRunner(host) {
13479
13632
  "--no-checkout",
13480
13633
  "--",
13481
13634
  cwd,
13482
- join30(gitCopy, "repo")
13635
+ join31(gitCopy, "repo")
13483
13636
  ],
13484
13637
  {
13485
13638
  env: {
@@ -13494,8 +13647,8 @@ async function createHostedBotRunner(host) {
13494
13647
  maxBuffer: 1024 * 1024
13495
13648
  }
13496
13649
  );
13497
- const safeGit = join30(gitCopy, "repo", ".git");
13498
- const protectedGit = lstatSync10(join30(cwd, ".git")).isFile() ? join30(cwd, ".git") : safeGit;
13650
+ const safeGit = join31(gitCopy, "repo", ".git");
13651
+ const protectedGit = lstatSync10(join31(cwd, ".git")).isFile() ? join31(cwd, ".git") : safeGit;
13499
13652
  writeJsonAtomic(file, resource);
13500
13653
  const created = await exec3(
13501
13654
  "docker",
@@ -13583,7 +13736,7 @@ async function createHostedBotRunner(host) {
13583
13736
  };
13584
13737
  } finally {
13585
13738
  if (existsSync8(file)) await removeResource(file, resource);
13586
- else rmSync19(gitCopy, { recursive: true, force: true });
13739
+ else rmSync20(gitCopy, { recursive: true, force: true });
13587
13740
  }
13588
13741
  };
13589
13742
  return {
@@ -13594,12 +13747,14 @@ async function createHostedBotRunner(host) {
13594
13747
  async start(assignment, options) {
13595
13748
  const gate = requireRunToolApproval(options.runId, options.toolApproval);
13596
13749
  const selected = assignment.subscriptionBinding;
13750
+ const apiKey = assignment.modelCredential;
13597
13751
  const kind = assignment.harness;
13598
- if (!selected || options.runId !== assignment.runId || kind !== "codex" && kind !== "claude_code" || !binaries[kind] || selected.consumerId.length !== 36 || selected.route !== (kind === "codex" ? "codex_cli" : "claude_code_cli") || options.continueSession)
13752
+ const protocol = kind === "codex" ? "openai" : "anthropic";
13753
+ if (Boolean(selected) === Boolean(apiKey) || options.runId !== assignment.runId || kind !== "codex" && kind !== "claude_code" || !binaries[kind] || selected && (selected.consumerId.length !== 36 || selected.route !== (kind === "codex" ? "codex_cli" : "claude_code_cli")) || apiKey?.kind === "provider" && apiKey.protocol !== protocol || options.continueSession)
13599
13754
  throw unavailable3();
13600
13755
  const name = `mikka-native-${randomUUID8()}`;
13601
13756
  const nonce = randomUUID8();
13602
- const resourceFile = join30(resources, name + ".json");
13757
+ const resourceFile = join31(resources, name + ".json");
13603
13758
  const resource = { name, nonce, state: "creating" };
13604
13759
  const lifetime = new AbortController();
13605
13760
  let closed = false;
@@ -13657,25 +13812,29 @@ async function createHostedBotRunner(host) {
13657
13812
  });
13658
13813
  try {
13659
13814
  await live();
13660
- const context = () => host.link.nativeContext(assignment.deviceId, assignment.runId, lifetime.signal);
13661
- const first = nativeBrokerContextSchema.parse(await context());
13662
- await live();
13663
- if (first.route !== selected.route || first.modelId !== options.model)
13664
- throw unavailable3();
13665
- const revision = first.revision;
13666
- const check = async () => {
13667
- await live();
13668
- const current = await context();
13815
+ const subscription = selected ? await (async () => {
13816
+ const context = () => host.link.nativeContext(assignment.deviceId, assignment.runId, lifetime.signal);
13817
+ const first = nativeBrokerContextSchema.parse(await context());
13669
13818
  await live();
13670
- if (current.revision !== revision || current.accountId !== first.accountId || current.route !== first.route || current.modelId !== first.modelId)
13819
+ if (first.route !== selected.route || first.modelId !== options.model)
13671
13820
  throw unavailable3();
13672
- return current;
13673
- };
13821
+ const revision = first.revision;
13822
+ const check2 = async () => {
13823
+ await live();
13824
+ const current = await context();
13825
+ await live();
13826
+ if (current.revision !== revision || current.accountId !== first.accountId || current.route !== first.route || current.modelId !== first.modelId)
13827
+ throw unavailable3();
13828
+ return current;
13829
+ };
13830
+ return { first, revision, check: check2 };
13831
+ })() : void 0;
13832
+ const check = subscription?.check ?? live;
13674
13833
  const paths = runPaths(host.stateDir, assignment.runId);
13675
- mkdirSync17(paths.runDir, { recursive: true, mode: 448 });
13676
- const shadow = join30(paths.runDir, "runtime-git");
13677
- const emptyHome = join30(paths.runDir, "git-bootstrap-home");
13678
- mkdirSync17(emptyHome, { recursive: true, mode: 448 });
13834
+ mkdirSync18(paths.runDir, { recursive: true, mode: 448 });
13835
+ const shadow = join31(paths.runDir, "runtime-git");
13836
+ const emptyHome = join31(paths.runDir, "git-bootstrap-home");
13837
+ mkdirSync18(emptyHome, { recursive: true, mode: 448 });
13679
13838
  if (!existsSync8(shadow))
13680
13839
  await exec3(
13681
13840
  "git",
@@ -13705,35 +13864,40 @@ async function createHostedBotRunner(host) {
13705
13864
  }
13706
13865
  );
13707
13866
  await live();
13708
- if (!lstatSync10(shadow).isDirectory() || !lstatSync10(join30(shadow, ".git")).isDirectory() || !realpathSync11(shadow).startsWith(realpathSync11(paths.runDir) + "/"))
13867
+ if (!lstatSync10(shadow).isDirectory() || !lstatSync10(join31(shadow, ".git")).isDirectory() || !realpathSync11(shadow).startsWith(realpathSync11(paths.runDir) + "/"))
13709
13868
  throw unavailable3();
13710
- const ledger = join30(
13869
+ const ledger = join31(
13711
13870
  host.stateDir,
13712
13871
  "native-ledgers",
13713
13872
  assignment.runId + ".json"
13714
13873
  );
13715
- const scope = {
13874
+ const scope = selected && subscription ? {
13716
13875
  runId: assignment.runId,
13717
13876
  bindingId: selected.bindingId,
13718
13877
  ownerId: selected.ownerId,
13719
13878
  workspaceId: selected.workspaceId,
13720
13879
  consumerId: selected.consumerId,
13721
13880
  route: selected.route,
13722
- revision,
13723
- accountId: first.accountId,
13724
- modelId: first.modelId
13725
- };
13726
- const previous = readJson(ledger);
13727
- if (existsSync8(ledger) && (!previous || JSON.stringify(previous.scope) !== JSON.stringify(scope) || typeof previous.sessionId !== "string"))
13881
+ revision: subscription.revision,
13882
+ accountId: subscription.first.accountId,
13883
+ modelId: subscription.first.modelId
13884
+ } : void 0;
13885
+ const previous = scope ? readJson(ledger) : void 0;
13886
+ if (scope && existsSync8(ledger) && (!previous || JSON.stringify(previous.scope) !== JSON.stringify(scope) || typeof previous.sessionId !== "string"))
13728
13887
  throw unavailable3();
13729
- mkdirSync17(dirname15(ledger), { recursive: true, mode: 448 });
13888
+ if (scope) mkdirSync18(dirname15(ledger), { recursive: true, mode: 448 });
13730
13889
  const record = async (sessionId) => {
13731
13890
  assertOpen();
13732
- writeJsonAtomic(ledger, { scope, sessionId });
13891
+ if (scope) writeJsonAtomic(ledger, { scope, sessionId });
13733
13892
  };
13734
- brokerStarting = createNativeSubscriptionBroker({
13735
- root: join30(host.stateDir, "native-brokers"),
13736
- revision,
13893
+ brokerStarting = apiKey ? createApiKeyBroker({
13894
+ root: join31(host.stateDir, "native-brokers"),
13895
+ protocol,
13896
+ credential: apiKey,
13897
+ check
13898
+ }) : createNativeSubscriptionBroker({
13899
+ root: join31(host.stateDir, "native-brokers"),
13900
+ revision: subscription.revision,
13737
13901
  check,
13738
13902
  worker: {
13739
13903
  nativeRequest: async (_revision, payload, signal) => {
@@ -13759,7 +13923,7 @@ async function createHostedBotRunner(host) {
13759
13923
  });
13760
13924
  const readyBroker = await brokerStarting;
13761
13925
  await live();
13762
- const githubCli = options.github ? (process.env.PATH ?? "").split(delimiter3).map((dir) => join30(dir, "gh")).find((file) => existsSync8(file)) : void 0;
13926
+ const githubCli = options.github ? (process.env.PATH ?? "").split(delimiter3).map((dir) => join31(dir, "gh")).find((file) => existsSync8(file)) : void 0;
13763
13927
  if (options.github && !githubCli) throw new Error("Install GitHub CLI (gh) in the cloud worker image");
13764
13928
  const githubDomains = options.github ? ["github.com", "api.github.com", new URL(options.github.endpoint).host] : [];
13765
13929
  const egressMaximum = runDomains(runPolicy(options.policy), [...options.networkAllow ?? [], ...githubDomains]);
@@ -13776,13 +13940,13 @@ async function createHostedBotRunner(host) {
13776
13940
  }
13777
13941
  const cwd = realpathSync11(options.cwd);
13778
13942
  const runDir = realpathSync11(paths.runDir);
13779
- const protectedGit = lstatSync10(join30(cwd, ".git")).isFile() ? join30(cwd, ".git") : join30(shadow, ".git");
13943
+ const protectedGit = lstatSync10(join31(cwd, ".git")).isFile() ? join31(cwd, ".git") : join31(shadow, ".git");
13780
13944
  if (!lstatSync10(runDir).isDirectory() || !runDir.startsWith(realpathSync11(host.stateDir) + "/runs/")) {
13781
13945
  await close();
13782
13946
  throw unavailable3();
13783
13947
  }
13784
13948
  const computer = assignment.computer;
13785
- if (computer && (!host.computerBroker || computer.ownerId !== selected.ownerId)) {
13949
+ if (computer && (!host.computerBroker || selected && computer.ownerId !== selected.ownerId)) {
13786
13950
  await close();
13787
13951
  throw unavailable3();
13788
13952
  }
@@ -13830,7 +13994,7 @@ async function createHostedBotRunner(host) {
13830
13994
  `${MCP_SERVER_SCRIPT}:${MCP_SERVER_SCRIPT}:ro`,
13831
13995
  ...githubCli ? ["-v", `${githubCli}:/usr/local/bin/mikka-gh:ro`, "-v", `${GITHUB_CREDENTIAL_SCRIPT}:${GITHUB_CREDENTIAL_SCRIPT}:ro`] : [],
13832
13996
  "-v",
13833
- `${join30(dirname15(MCP_SERVER_SCRIPT), "capture-copy.mjs")}:${join30(dirname15(MCP_SERVER_SCRIPT), "capture-copy.mjs")}:ro`,
13997
+ `${join31(dirname15(MCP_SERVER_SCRIPT), "capture-copy.mjs")}:${join31(dirname15(MCP_SERVER_SCRIPT), "capture-copy.mjs")}:ro`,
13834
13998
  "-v",
13835
13999
  `${readyBroker.socket}:/run/mikka-native.sock:ro`,
13836
14000
  ...computerGrant ? [
@@ -13873,13 +14037,13 @@ async function createHostedBotRunner(host) {
13873
14037
  }
13874
14038
  const spawnHosted = (config) => {
13875
14039
  assertOpen();
13876
- const home = join30(runDir, "runtime-home");
13877
- mkdirSync17(home, { recursive: true, mode: 448 });
14040
+ const home = join31(runDir, "runtime-home");
14041
+ mkdirSync18(home, { recursive: true, mode: 448 });
13878
14042
  const env = {
13879
14043
  ...config.env,
13880
14044
  HOME: kind === "claude_code" ? config.env.HOME ?? home : home,
13881
- PATH: `${options.github ? join30(runDir, "github", "bin") + ":" : ""}/usr/local/bin:/usr/bin:/bin`,
13882
- GIT_DIR: join30(shadow, ".git"),
14045
+ PATH: `${options.github ? join31(runDir, "github", "bin") + ":" : ""}/usr/local/bin:/usr/bin:/bin`,
14046
+ GIT_DIR: join31(shadow, ".git"),
13883
14047
  GIT_WORK_TREE: cwd,
13884
14048
  GIT_CONFIG_GLOBAL: "/dev/null",
13885
14049
  GIT_CONFIG_SYSTEM: "/dev/null",
@@ -13888,7 +14052,7 @@ async function createHostedBotRunner(host) {
13888
14052
  for (const [key2, value] of Object.entries(env))
13889
14053
  if (value !== void 0 && (/INFISICAL|E2B_API_KEY|REFRESH_TOKEN|^AWS_|^GOOGLE_|^OPENAI_|^ANTHROPIC_.*(?:KEY|TOKEN)|SECRET|PASSWORD/.test(
13890
14054
  key2
13891
- ) || key2 === "CLAUDE_CODE_OAUTH_TOKEN" && value !== placeholder))
14055
+ ) || (key2 === "CLAUDE_CODE_OAUTH_TOKEN" || key2 === "MIKKA_MODEL_API_KEY") && value !== placeholder))
13892
14056
  throw unavailable3();
13893
14057
  const task = withTaskEnv(env, assignment.taskEnv);
13894
14058
  if (task.dropped.length) console.warn(`run ${assignment.runId}: skipped reserved task variables ${task.dropped.join(", ")}`);
@@ -13898,7 +14062,7 @@ async function createHostedBotRunner(host) {
13898
14062
  signal: AbortSignal.any([lifetime.signal, ...config.signal ? [config.signal] : []])
13899
14063
  });
13900
14064
  child.stdin.write(
13901
- JSON.stringify({ kind, args: config.args, cwd, env: task.env, publicEgress: Boolean(egress), ...options.github ? { githubBin: join30(runDir, "github", "bin") } : {} }) + "\n"
14065
+ JSON.stringify({ kind, args: config.args, cwd, env: task.env, publicEgress: Boolean(egress), ...options.github ? { githubBin: join31(runDir, "github", "bin") } : {} }) + "\n"
13902
14066
  );
13903
14067
  return child;
13904
14068
  };
@@ -13927,19 +14091,27 @@ async function createHostedBotRunner(host) {
13927
14091
  };
13928
14092
  };
13929
14093
  try {
13930
- const adapter = kind === "codex" ? new CodexAdapter({
14094
+ const placeholderCredential = apiKey && kind === "codex" ? { kind: "provider", protocol: "openai", baseUrl: apiKey.kind === "provider" ? apiKey.baseUrl : "https://api.openai.com/v1", key: placeholder } : void 0;
14095
+ const adapter = apiKey ? kind === "codex" ? new CodexAdapter({ stateDir: host.stateDir, sandbox: blockedSandbox, spawnCli: codexSpawn, computerMcp }) : new ClaudeAdapter({
14096
+ stateDir: host.stateDir,
14097
+ computerMcp,
14098
+ spawnHosted: (config, token) => {
14099
+ if (token !== placeholder) throw unavailable3();
14100
+ return spawnHosted(config);
14101
+ }
14102
+ }) : kind === "codex" ? new CodexAdapter({
13931
14103
  stateDir: host.stateDir,
13932
14104
  sandbox: blockedSandbox,
13933
14105
  spawnCli: codexSpawn,
13934
14106
  onHostedSession: record,
13935
14107
  computerMcp,
13936
14108
  subscriptionAuth: {
13937
- accountId: first.accountId,
14109
+ accountId: subscription.first.accountId,
13938
14110
  verify: async () => {
13939
14111
  await check();
13940
14112
  },
13941
14113
  token: async () => {
13942
- const current = await check();
14114
+ const current = await subscription.check();
13943
14115
  return {
13944
14116
  accessToken: placeholder,
13945
14117
  chatgptAccountId: current.accountId,
@@ -13957,12 +14129,12 @@ async function createHostedBotRunner(host) {
13957
14129
  },
13958
14130
  subscriptionAuth: {
13959
14131
  brokered: true,
13960
- accountId: first.accountId,
14132
+ accountId: subscription.first.accountId,
13961
14133
  verify: async () => {
13962
14134
  await check();
13963
14135
  },
13964
14136
  token: async () => {
13965
- const current = await check();
14137
+ const current = await subscription.check();
13966
14138
  return {
13967
14139
  accessToken: placeholder,
13968
14140
  accountId: current.accountId,
@@ -13971,7 +14143,7 @@ async function createHostedBotRunner(host) {
13971
14143
  }
13972
14144
  }
13973
14145
  });
13974
- const runtimeOptions = { ...options, ...options.github ? { githubRuntime: { nodeBinary: "/usr/local/bin/node", ghBinary: "/usr/local/bin/mikka-gh" } } : {} };
14146
+ const runtimeOptions = { ...options, credential: placeholderCredential, ...options.github ? { githubRuntime: { nodeBinary: "/usr/local/bin/node", ghBinary: "/usr/local/bin/mikka-gh" } } : {} };
13975
14147
  const session = previous ? await adapter.resume(previous.sessionId, runtimeOptions) : await adapter.start(runtimeOptions);
13976
14148
  let checking = false;
13977
14149
  if (!closed) timer = setInterval(() => {
@@ -14033,8 +14205,8 @@ import {
14033
14205
  createHash as createHash9,
14034
14206
  timingSafeEqual as timingSafeEqual2
14035
14207
  } from "node:crypto";
14036
- import { chmodSync as chmodSync4 } from "node:fs";
14037
- import { createServer as createServer4 } from "node:net";
14208
+ import { chmodSync as chmodSync5 } from "node:fs";
14209
+ import { createServer as createServer5 } from "node:net";
14038
14210
 
14039
14211
  // src/computer/driver.mjs
14040
14212
  import { spawn as spawn6 } from "node:child_process";
@@ -14254,7 +14426,7 @@ var ComputerBroker = class {
14254
14426
  }
14255
14427
  async listen() {
14256
14428
  if (this.suspended) throw new Error("Broker suspended");
14257
- this.server = createServer4((socket) => {
14429
+ this.server = createServer5((socket) => {
14258
14430
  this.sockets.add(socket);
14259
14431
  socket.on("close", () => this.sockets.delete(socket));
14260
14432
  let text3 = "", submitted = false;
@@ -14297,7 +14469,7 @@ var ComputerBroker = class {
14297
14469
  else this.server.listen(this.socketPath, resolve13);
14298
14470
  });
14299
14471
  if (this.transport === "tcp") this.socketPath = `tcp://127.0.0.1:${this.server.address().port}`;
14300
- else chmodSync4(this.socketPath, 384);
14472
+ else chmodSync5(this.socketPath, 384);
14301
14473
  }
14302
14474
  request(token, value, signal) {
14303
14475
  const grant = this.grants.get(token);
@@ -14543,6 +14715,9 @@ function loadDeviceFile(raw) {
14543
14715
  return file;
14544
14716
  }
14545
14717
  var HARNESS_RESCAN_MS = 5 * 6e4;
14718
+ function credentialOwner(assignment) {
14719
+ return assignment.subscriptionBinding?.ownerId ?? (assignment.modelCredential ? assignment.computer?.ownerId : void 0);
14720
+ }
14546
14721
  var SANDBOX_REPAIR_RETRY_MS = 60 * 6e4;
14547
14722
  function missingToolsUnchanged(issue) {
14548
14723
  return !issue?.missing.length || missingSandboxTools().length === issue.missing.length;
@@ -14618,8 +14793,8 @@ var Daemon = class {
14618
14793
  }
14619
14794
  async startInternal() {
14620
14795
  const { paths } = this;
14621
- mkdirSync18(paths.dataDir, { recursive: true, mode: 448 });
14622
- if (process.platform !== "win32") chmodSync5(paths.dataDir, 448);
14796
+ mkdirSync19(paths.dataDir, { recursive: true, mode: 448 });
14797
+ if (process.platform !== "win32") chmodSync6(paths.dataDir, 448);
14623
14798
  this.releaseLock = await acquireLock(
14624
14799
  paths.dataDir,
14625
14800
  paths.lock,
@@ -14632,7 +14807,7 @@ var Daemon = class {
14632
14807
  if (this.options.credential)
14633
14808
  this.saveDevice({ credential: this.options.credential });
14634
14809
  this.journal = new RunJournal(paths.journal);
14635
- this.captureUploader = new CaptureUploader((runId) => join31(runPaths(paths.adapterState, runId).runDir, CAPTURES_DIR), this.options.link, this.log, join31(paths.dataDir, "capture-pending"));
14810
+ this.captureUploader = new CaptureUploader((runId) => join32(runPaths(paths.adapterState, runId).runDir, CAPTURES_DIR), this.options.link, this.log, join32(paths.dataDir, "capture-pending"));
14636
14811
  this.outbox = new Outbox(
14637
14812
  paths.outbox,
14638
14813
  this.options.link,
@@ -14649,7 +14824,7 @@ var Daemon = class {
14649
14824
  if (this.localComputerDriver && this.options.link.syncComputerReviews && this.options.link.localComputerAuthority) {
14650
14825
  this.localComputerBroker = new ComputerBroker({
14651
14826
  driver: this.localComputerDriver,
14652
- socketPath: join31(paths.dataDir, "local-computer.sock"),
14827
+ socketPath: join32(paths.dataDir, "local-computer.sock"),
14653
14828
  transport: "tcp",
14654
14829
  permitted: (runId) => {
14655
14830
  const assignment = this.journal.get(runId)?.assignment;
@@ -14682,7 +14857,7 @@ var Daemon = class {
14682
14857
  const liveComputer = (runId, display) => {
14683
14858
  const entry = this.journal.get(runId);
14684
14859
  const computer = entry?.assignment.computer;
14685
- if (this.stopped || !this.registered || !computer || computer.display !== display || computer.ownerId !== entry?.assignment.subscriptionBinding?.ownerId || !this.supervisor.computerRunAllowed(runId)) throw new Error("Cloud computer run unavailable");
14860
+ if (this.stopped || !this.registered || !computer || computer.display !== display || !entry || computer.ownerId !== credentialOwner(entry.assignment) || !this.supervisor.computerRunAllowed(runId)) throw new Error("Cloud computer run unavailable");
14686
14861
  return computer;
14687
14862
  };
14688
14863
  const executeOrdinary = async (current, call, display, runId, assertLive) => {
@@ -14691,7 +14866,7 @@ var Daemon = class {
14691
14866
  };
14692
14867
  this.cloudComputerBroker = new ComputerBroker({
14693
14868
  driver,
14694
- socketPath: join31(paths.dataDir, "computer.sock"),
14869
+ socketPath: join32(paths.dataDir, "computer.sock"),
14695
14870
  permitted: (runId) => {
14696
14871
  const entry = this.journal.get(runId);
14697
14872
  return Boolean(!this.stopped && this.registered && entry?.assignment.computer && this.supervisor?.computerRunAllowed(runId));
@@ -14759,6 +14934,7 @@ var Daemon = class {
14759
14934
  worktrees: this.worktrees,
14760
14935
  adapters,
14761
14936
  startSubscription: hosted?.start ?? this.localSubscriptions()?.start,
14937
+ startCredential: hosted?.start,
14762
14938
  prepareRunMailbox: this.options.link.prepareRunMailbox?.bind(this.options.link),
14763
14939
  prepareRunToolApproval: this.options.link.prepareRunToolApproval?.bind(this.options.link),
14764
14940
  verifyRunPolicy: this.options.link.verifyRunPolicy ? async (assignment, signal) => {
@@ -14818,7 +14994,7 @@ var Daemon = class {
14818
14994
  worktree,
14819
14995
  tree,
14820
14996
  github: { ...assignment.github, runToken: assignment.mcp.token, issueId: assignment.issueId },
14821
- privateDir: join31(paths.adapterState, "pids"),
14997
+ privateDir: join32(paths.adapterState, "pids"),
14822
14998
  ...hosted ? { hosted: true } : {},
14823
14999
  env: githubReceiptEnvironment()
14824
15000
  }) : publishRun({
@@ -15178,11 +15354,11 @@ var Daemon = class {
15178
15354
  return runVerify(sandbox, {
15179
15355
  command,
15180
15356
  worktree: realpathSync12(worktree),
15181
- tmpRoot: join31(this.paths.adapterState, "verify", runId),
15357
+ tmpRoot: join32(this.paths.adapterState, "verify", runId),
15182
15358
  privateDir: paths.privateDir,
15183
15359
  pidFile: paths.pidFile.replace(/\.pgid$/, ".verify.pgid"),
15184
15360
  networkAllow: repo.networkAllow,
15185
- env: { ...buildChildEnv(), MIKKA_HANDOFF_FILE: join31(paths.runDir, "handoff.json") },
15361
+ env: { ...buildChildEnv(), MIKKA_HANDOFF_FILE: join32(paths.runDir, "handoff.json") },
15186
15362
  timeoutMs,
15187
15363
  signal,
15188
15364
  readOnly
@@ -15367,7 +15543,7 @@ var Daemon = class {
15367
15543
  setImmediate(() => {
15368
15544
  void this.stop().then(() => uninstallService(() => {
15369
15545
  this.saveDevice({ credential: void 0 });
15370
- rmSync20(this.paths.secret, { force: true });
15546
+ rmSync21(this.paths.secret, { force: true });
15371
15547
  })).catch(() => {
15372
15548
  this.options.onDrained?.();
15373
15549
  });
@@ -15485,7 +15661,7 @@ var Daemon = class {
15485
15661
  throw new DaemonError(DAEMON_RPC_ERRORS.unauthorized, message);
15486
15662
  }
15487
15663
  }
15488
- if (assignment.computer && (!this.cloudComputerBroker || !assignment.subscriptionBinding || assignment.computer.ownerId !== assignment.subscriptionBinding.ownerId)) throw new Error("Cloud computer runtime unavailable");
15664
+ if (assignment.computer && (!this.cloudComputerBroker || assignment.computer.ownerId !== credentialOwner(assignment))) throw new Error("Cloud computer runtime unavailable");
15489
15665
  return await this.supervisor.start(assignment);
15490
15666
  }
15491
15667
  /**
@@ -15692,7 +15868,7 @@ var Daemon = class {
15692
15868
  if (!job || controller.signal.aborted) return;
15693
15869
  await runNativeCoordinatorJob(job, {
15694
15870
  deviceId,
15695
- stateDir: join31(this.paths.dataDir, "coordinator"),
15871
+ stateDir: join32(this.paths.dataDir, "coordinator"),
15696
15872
  link,
15697
15873
  signal: controller.signal,
15698
15874
  sandbox,
@@ -15735,7 +15911,7 @@ var Daemon = class {
15735
15911
  }, void 0, () => !this.stopped);
15736
15912
  });
15737
15913
  } else if (!this.updateCheck && !this.updateVersion) {
15738
- this.updateCheck = checkLatestVersion(join31(this.paths.dataDir, "auto-update.json"), DAEMON_VERSION, runtime).then((version) => {
15914
+ this.updateCheck = checkLatestVersion(join32(this.paths.dataDir, "auto-update.json"), DAEMON_VERSION, runtime).then((version) => {
15739
15915
  this.updateVersion = version;
15740
15916
  }).catch(() => {
15741
15917
  this.log.warn("Daemon automatic update check failed");