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