@aspectlylabs/mikka 0.0.140 → 0.0.142

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