@aspectlylabs/mikka 0.0.1 → 0.0.4
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 +20 -4
- package/cli.js +101 -15
- package/client.js +10 -4
- package/http-link.js +32 -8
- package/login.js +10 -4
- package/main.js +218 -146
- package/mikka-mcp.mjs +4 -0
- package/mikka.js +101 -15
- package/package.json +2 -1
- package/paths.js +3 -2
package/README.md
CHANGED
|
@@ -49,10 +49,26 @@ index for inspection. The test daemon still performs its normal lifecycle
|
|
|
49
49
|
cleanup inside the new dedicated fixture; previously retained resources are
|
|
50
50
|
not part of that fixture.
|
|
51
51
|
|
|
52
|
-
No global `tsx` or separate `@mikka/protocol` package is needed.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
No global `tsx` or separate `@mikka/protocol` package is needed. Every push to
|
|
53
|
+
`main` publishes through `.github/workflows/publish-daemon.yml` after daemon
|
|
54
|
+
checks and the installed-package runtime test pass. The workflow uses npm
|
|
55
|
+
trusted publishing and provenance; its npm trust configuration must authorize
|
|
56
|
+
this exact repository and workflow filename.
|
|
57
|
+
|
|
58
|
+
CI stamps `0.0.<workflow run number + 1>` into the source manifest before the
|
|
59
|
+
build, so the npm package and runtime report the same version. Source commits
|
|
60
|
+
keep their development version. Re-running a workflow keeps its version and
|
|
61
|
+
skips publication if npm already records that version from the same commit.
|
|
62
|
+
CI writes the commit SHA into the published manifest as `gitHead`; an existing
|
|
63
|
+
version with absent or different commit metadata stops the release. After
|
|
64
|
+
publication, CI reads npm metadata back and checks the commit SHA. If npm
|
|
65
|
+
serves 404 while the published version becomes available, CI checks up to 31
|
|
66
|
+
times with 10-second waits. Exhausting that wait reports registry verification
|
|
67
|
+
as incomplete; it does not claim that npm rejected publication.
|
|
68
|
+
Releases queue without cancellation (up to GitHub's 100 pending-run limit).
|
|
69
|
+
An older run can publish under its own `build-<version>` tag, preserving the
|
|
70
|
+
newer `latest` version. Manual dispatch remains available on `main` and gets
|
|
71
|
+
a new run version. Running local tests or builds does not publish anything.
|
|
56
72
|
|
|
57
73
|
`test:package` installs the actual tarball into a new directory with public
|
|
58
74
|
registry dependencies, without workspace symlinks or install scripts. Plain
|
package/cli.js
CHANGED
|
@@ -2216,7 +2216,7 @@ function closeLogger(logger) {
|
|
|
2216
2216
|
// src/service.ts
|
|
2217
2217
|
import { execFile } from "node:child_process";
|
|
2218
2218
|
import { promisify } from "node:util";
|
|
2219
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
2219
|
+
import { mkdir, writeFile, rm } from "node:fs/promises";
|
|
2220
2220
|
import { homedir } from "node:os";
|
|
2221
2221
|
import { dirname as dirname2, join as join2, resolve } from "node:path";
|
|
2222
2222
|
var exec = promisify(execFile);
|
|
@@ -2284,6 +2284,34 @@ async function restartService(update, beforeRestart, dependencies = {
|
|
|
2284
2284
|
beforeRestart();
|
|
2285
2285
|
dependencies.restart();
|
|
2286
2286
|
}
|
|
2287
|
+
async function uninstallService(clearCredential, dependencies = {
|
|
2288
|
+
manager: process.env.MIKKA_SERVICE,
|
|
2289
|
+
home: homedir(),
|
|
2290
|
+
uid: process.getuid?.() ?? 0,
|
|
2291
|
+
run: async (program, args) => {
|
|
2292
|
+
await exec(program, args, { timeout: 1e4 });
|
|
2293
|
+
},
|
|
2294
|
+
exit: () => {
|
|
2295
|
+
process.exit(0);
|
|
2296
|
+
}
|
|
2297
|
+
}) {
|
|
2298
|
+
try {
|
|
2299
|
+
if (dependencies.manager === "systemd") {
|
|
2300
|
+
await dependencies.run("systemctl", ["--user", "disable", "mikka-daemon.service"]);
|
|
2301
|
+
await rm(join2(dependencies.home, ".config/systemd/user/mikka-daemon.service"), { force: true });
|
|
2302
|
+
await dependencies.run("systemctl", ["--user", "daemon-reload"]);
|
|
2303
|
+
} else if (dependencies.manager === "launchd") {
|
|
2304
|
+
await rm(join2(dependencies.home, "Library/LaunchAgents", `${label}.plist`), { force: true });
|
|
2305
|
+
}
|
|
2306
|
+
} finally {
|
|
2307
|
+
clearCredential();
|
|
2308
|
+
try {
|
|
2309
|
+
if (dependencies.manager === "launchd") await dependencies.run("launchctl", ["bootout", `gui/${dependencies.uid}/${label}`]);
|
|
2310
|
+
} finally {
|
|
2311
|
+
dependencies.exit();
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2287
2315
|
|
|
2288
2316
|
// ../protocol/src/accounts.ts
|
|
2289
2317
|
import { z } from "zod";
|
|
@@ -2971,13 +2999,18 @@ var runReport = z9.object({
|
|
|
2971
2999
|
sha: z9.string().regex(/^[a-f0-9]{40}$/),
|
|
2972
3000
|
readOnly: z9.literal(true)
|
|
2973
3001
|
}).optional(),
|
|
3002
|
+
/** Preview branch created or used by the producing run; descriptive metadata only. */
|
|
3003
|
+
previewDatabaseBranch: z9.string().trim().min(1).max(500).optional(),
|
|
2974
3004
|
/** Acceptance criteria the agent checked, with evidence. */
|
|
2975
3005
|
criteria: z9.array(
|
|
2976
3006
|
z9.object({
|
|
2977
3007
|
criterionId: z9.uuid().optional(),
|
|
2978
3008
|
text: z9.string().max(2e3).optional(),
|
|
2979
3009
|
passed: z9.boolean(),
|
|
2980
|
-
evidence: z9.string().max(1e4).optional()
|
|
3010
|
+
evidence: z9.string().max(1e4).optional(),
|
|
3011
|
+
/** Agent-reported criterion check; the daemon-owned verify remains authoritative. */
|
|
3012
|
+
command: z9.string().trim().min(1).max(2e3).optional(),
|
|
3013
|
+
exitCode: z9.number().int().nullable().optional()
|
|
2981
3014
|
})
|
|
2982
3015
|
).max(200).optional(),
|
|
2983
3016
|
/**
|
|
@@ -3321,7 +3354,7 @@ var heartbeatRunSchema = z13.object({
|
|
|
3321
3354
|
/** Last tool call, turn boundary or file change (not raw output). */
|
|
3322
3355
|
lastProgressAt: isoTime
|
|
3323
3356
|
});
|
|
3324
|
-
var deviceManagementCommand = z13.object({ id: z13.uuid(), kind: z13.enum(["redetect", "restart", "update"]) });
|
|
3357
|
+
var deviceManagementCommand = z13.object({ id: z13.uuid(), kind: z13.enum(["redetect", "restart", "update", "uninstall"]) });
|
|
3325
3358
|
var deviceHeartbeatSchema = z13.object({
|
|
3326
3359
|
completedDeviceCommands: z13.array(z13.uuid()).max(100).optional(),
|
|
3327
3360
|
failedDeviceCommands: z13.array(z13.object({ id: z13.uuid(), error: z13.string().max(500) })).max(100).optional(),
|
|
@@ -4248,7 +4281,7 @@ import { join as join3 } from "node:path";
|
|
|
4248
4281
|
// package.json
|
|
4249
4282
|
var package_default = {
|
|
4250
4283
|
name: "@mikka/daemon",
|
|
4251
|
-
version: "0.0.
|
|
4284
|
+
version: "0.0.4",
|
|
4252
4285
|
description: "Local Mikka daemon: runs agents through the user's own CLIs",
|
|
4253
4286
|
type: "module",
|
|
4254
4287
|
private: true,
|
|
@@ -4305,7 +4338,8 @@ var package_default = {
|
|
|
4305
4338
|
},
|
|
4306
4339
|
engines: {
|
|
4307
4340
|
node: ">=24"
|
|
4308
|
-
}
|
|
4341
|
+
},
|
|
4342
|
+
gitHead: "4c5f80747928d60ea3e03ed6a3de5ca2dc2216df"
|
|
4309
4343
|
};
|
|
4310
4344
|
|
|
4311
4345
|
// src/paths.ts
|
|
@@ -4944,12 +4978,28 @@ var HttpServerLink = class {
|
|
|
4944
4978
|
const liveness = new AbortController();
|
|
4945
4979
|
const gate = new ToolApprovalGate(assignment.runId, {
|
|
4946
4980
|
permission: (request) => toolApprovalDecision(request, assignment.policy, worktree),
|
|
4981
|
+
// Keep the callback pending at the tool boundary. The adapter's current
|
|
4982
|
+
// session and checkpoint remain intact; handback resolves this same call.
|
|
4947
4983
|
isLive: async () => {
|
|
4948
4984
|
try {
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4985
|
+
for (; ; ) {
|
|
4986
|
+
check();
|
|
4987
|
+
const current = await this.call("POST", path, { body: { operation: "check", deviceId: assignment.deviceId, policyRevision }, schema: z25.object({ live: z25.boolean(), paused: z25.boolean().optional() }), signal: liveness.signal, timeoutMs: 5e3 });
|
|
4988
|
+
check();
|
|
4989
|
+
if (!current.live || !current.paused) return current.live;
|
|
4990
|
+
await new Promise((resolve10, reject) => {
|
|
4991
|
+
const stop = () => {
|
|
4992
|
+
clearTimeout(timer);
|
|
4993
|
+
reject(new Error("cancelled"));
|
|
4994
|
+
};
|
|
4995
|
+
const timer = setTimeout(() => {
|
|
4996
|
+
liveness.signal.removeEventListener("abort", stop);
|
|
4997
|
+
resolve10();
|
|
4998
|
+
}, 1e3);
|
|
4999
|
+
liveness.signal.addEventListener("abort", stop, { once: true });
|
|
5000
|
+
if (liveness.signal.aborted) stop();
|
|
5001
|
+
});
|
|
5002
|
+
}
|
|
4953
5003
|
} catch {
|
|
4954
5004
|
return false;
|
|
4955
5005
|
}
|
|
@@ -4978,9 +5028,11 @@ var HttpServerLink = class {
|
|
|
4978
5028
|
}
|
|
4979
5029
|
}
|
|
4980
5030
|
};
|
|
5031
|
+
if (!await gate.checkLive()) return "deny";
|
|
4981
5032
|
const created = await retry(() => this.call("POST", path, { body: { operation: "propose", deviceId: assignment.deviceId, policyRevision, requestId: request.requestId, harness: request.harness, method: request.method, input: request.input }, schema: proposal, signal: signal2 }));
|
|
4982
5033
|
try {
|
|
4983
5034
|
for (; ; ) {
|
|
5035
|
+
if (!await gate.checkLive()) return "deny";
|
|
4984
5036
|
const result = await retry(() => this.call("POST", path, { body: { operation: "take", deviceId: assignment.deviceId, id: created.id, digest: created.digest }, schema: response, signal: signal2 }));
|
|
4985
5037
|
if (result.decision !== "pending") return result.decision;
|
|
4986
5038
|
await delay3();
|
|
@@ -6193,6 +6245,7 @@ var RunContext = class {
|
|
|
6193
6245
|
nextStep: file.nextStep ?? null,
|
|
6194
6246
|
...file.blockedOn ? { blockedOn: file.blockedOn } : {},
|
|
6195
6247
|
...plan ? { plan } : {},
|
|
6248
|
+
...typeof file.previewDatabaseBranch === "string" ? { previewDatabaseBranch: file.previewDatabaseBranch } : {},
|
|
6196
6249
|
...Array.isArray(file.criteria) ? { criteria: file.criteria } : {},
|
|
6197
6250
|
...runQuestion.safeParse(file.question).success ? { question: runQuestion.parse(file.question) } : {}
|
|
6198
6251
|
};
|
|
@@ -6635,6 +6688,7 @@ import {
|
|
|
6635
6688
|
existsSync as existsSync6,
|
|
6636
6689
|
mkdirSync as mkdirSync15,
|
|
6637
6690
|
readFileSync as readFileSync11,
|
|
6691
|
+
rmSync as rmSync16,
|
|
6638
6692
|
realpathSync as realpathSync11
|
|
6639
6693
|
} from "node:fs";
|
|
6640
6694
|
import { arch, hostname, platform as platform2 } from "node:os";
|
|
@@ -12302,7 +12356,7 @@ var RunSupervisor = class {
|
|
|
12302
12356
|
const current = this.deps.journal.get(runId);
|
|
12303
12357
|
assertMailboxRunAuthority({ held: this.active.get(runId) === run2, state: current?.state, stopped: this.stopping || run2.cancelRequested || run2.abort.signal.aborted, lease });
|
|
12304
12358
|
};
|
|
12305
|
-
|
|
12359
|
+
let mailbox = await this.deps.prepareRunMailbox?.(assignment, run2.abort.signal, checkMailbox);
|
|
12306
12360
|
run2.mailbox = mailbox;
|
|
12307
12361
|
if (this.stopping) return;
|
|
12308
12362
|
if (run2.cancelRequested) {
|
|
@@ -12312,6 +12366,14 @@ var RunSupervisor = class {
|
|
|
12312
12366
|
if (mailbox) checkMailbox();
|
|
12313
12367
|
const toolApproval = await this.deps.prepareRunToolApproval?.(assignment, run2.abort.signal, checkMailbox, worktree);
|
|
12314
12368
|
run2.toolApproval = toolApproval;
|
|
12369
|
+
if (mailbox && toolApproval) {
|
|
12370
|
+
const original = mailbox;
|
|
12371
|
+
mailbox = { tools: original.tools, close: () => original.close(), request: async (body, signal) => {
|
|
12372
|
+
if (!await toolApproval.checkLive()) throw new Error("Run tool approval unavailable");
|
|
12373
|
+
return original.request(body, signal);
|
|
12374
|
+
} };
|
|
12375
|
+
run2.mailbox = mailbox;
|
|
12376
|
+
}
|
|
12315
12377
|
if (this.stopping) {
|
|
12316
12378
|
toolApproval?.revoke();
|
|
12317
12379
|
return;
|
|
@@ -12605,18 +12667,21 @@ function pickAgentReport(agent) {
|
|
|
12605
12667
|
const question = runQuestion.safeParse(agent.question);
|
|
12606
12668
|
if (question.success) picked.question = question.data;
|
|
12607
12669
|
if (agent.plan) picked.plan = agent.plan;
|
|
12670
|
+
if (typeof agent.previewDatabaseBranch === "string" && agent.previewDatabaseBranch.trim())
|
|
12671
|
+
picked.previewDatabaseBranch = agent.previewDatabaseBranch.trim().slice(0, 500);
|
|
12608
12672
|
if (Array.isArray(agent.criteria)) {
|
|
12609
12673
|
const criteria = [];
|
|
12610
12674
|
for (const entry of agent.criteria) {
|
|
12611
12675
|
if (criteria.length >= MAX_REPORTED_CRITERIA) break;
|
|
12612
12676
|
if (!entry || typeof entry !== "object") continue;
|
|
12613
|
-
const { criterionId, passed, evidence } = entry;
|
|
12677
|
+
const { criterionId, passed, evidence, command, exitCode } = entry;
|
|
12614
12678
|
if (typeof criterionId !== "string" || !UUID_RE.test(criterionId))
|
|
12615
12679
|
continue;
|
|
12616
12680
|
if (typeof passed !== "boolean") continue;
|
|
12617
12681
|
criteria.push({
|
|
12618
12682
|
criterionId,
|
|
12619
12683
|
passed,
|
|
12684
|
+
...typeof command === "string" && command.trim() ? { command: command.trim().slice(0, 2e3), ...exitCode === null || typeof exitCode === "number" && Number.isSafeInteger(exitCode) ? { exitCode } : {} } : {},
|
|
12620
12685
|
...typeof evidence === "string" ? { evidence: evidence.slice(0, 1e4) } : {}
|
|
12621
12686
|
});
|
|
12622
12687
|
}
|
|
@@ -12789,7 +12854,7 @@ import { promisify as promisify4 } from "node:util";
|
|
|
12789
12854
|
|
|
12790
12855
|
// src/agents/public-egress.ts
|
|
12791
12856
|
import { lookup } from "node:dns/promises";
|
|
12792
|
-
import { chmod, mkdtemp, rm } from "node:fs/promises";
|
|
12857
|
+
import { chmod, mkdtemp, rm as rm2 } from "node:fs/promises";
|
|
12793
12858
|
import { createServer as createServer3, request as httpRequest } from "node:http";
|
|
12794
12859
|
import { connect, isIP as isIP3 } from "node:net";
|
|
12795
12860
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
@@ -12971,7 +13036,7 @@ async function startPublicEgress(options) {
|
|
|
12971
13036
|
for (const socket of sockets) socket.destroy();
|
|
12972
13037
|
closing = new Promise((resolve10, reject) => server.close((error) => {
|
|
12973
13038
|
options.signal.removeEventListener("abort", onAbort);
|
|
12974
|
-
void
|
|
13039
|
+
void rm2(directory, { recursive: true, force: true }).then(() => error && error.code !== "ERR_SERVER_NOT_RUNNING" ? reject(error) : resolve10(), reject);
|
|
12975
13040
|
}));
|
|
12976
13041
|
return closing;
|
|
12977
13042
|
};
|
|
@@ -14777,7 +14842,7 @@ var Daemon = class {
|
|
|
14777
14842
|
}
|
|
14778
14843
|
const deviceId = this.device.deviceId;
|
|
14779
14844
|
const quotas = this.quota?.snapshot().quotas;
|
|
14780
|
-
const
|
|
14845
|
+
const heartbeat = {
|
|
14781
14846
|
completedDeviceCommands: this.device.completedDeviceCommands,
|
|
14782
14847
|
failedDeviceCommands: this.device.failedDeviceCommands,
|
|
14783
14848
|
harnesses: this.harnesses,
|
|
@@ -14785,7 +14850,8 @@ var Daemon = class {
|
|
|
14785
14850
|
runs: this.supervisor.heartbeatRuns(),
|
|
14786
14851
|
worktreeDiskBytes: await this.worktrees.diskUsage(),
|
|
14787
14852
|
...quotas ? { quotas } : {}
|
|
14788
|
-
}
|
|
14853
|
+
};
|
|
14854
|
+
const { leases, revoked, cloudCredential, deviceCommands } = await link.heartbeat(deviceId, heartbeat);
|
|
14789
14855
|
this.supervisor.renewLeases(leases);
|
|
14790
14856
|
if (revoked) this.supervisor.revokeLeases(revoked);
|
|
14791
14857
|
if (this.options.cloudComputer && cloudCredential && this.device.credential === credential) {
|
|
@@ -14794,6 +14860,26 @@ var Daemon = class {
|
|
|
14794
14860
|
this.registered = false;
|
|
14795
14861
|
}
|
|
14796
14862
|
const command = deviceCommands?.[0];
|
|
14863
|
+
if (command?.kind === "uninstall") {
|
|
14864
|
+
this.draining = true;
|
|
14865
|
+
if (this.supervisor.heartbeatRuns().length === 0) {
|
|
14866
|
+
this.saveDevice({ completedDeviceCommands: [command.id], failedDeviceCommands: [] });
|
|
14867
|
+
try {
|
|
14868
|
+
await link.heartbeat(deviceId, { ...heartbeat, runs: [], completedDeviceCommands: [command.id], failedDeviceCommands: [] });
|
|
14869
|
+
} catch {
|
|
14870
|
+
this.log.warn("Could not confirm uninstall receipt");
|
|
14871
|
+
}
|
|
14872
|
+
setImmediate(() => {
|
|
14873
|
+
void this.stop().then(() => uninstallService(() => {
|
|
14874
|
+
this.saveDevice({ credential: void 0 });
|
|
14875
|
+
rmSync16(this.paths.secret, { force: true });
|
|
14876
|
+
})).catch(() => {
|
|
14877
|
+
this.options.onDrained?.();
|
|
14878
|
+
});
|
|
14879
|
+
});
|
|
14880
|
+
}
|
|
14881
|
+
return;
|
|
14882
|
+
}
|
|
14797
14883
|
if (command && !this.device.completedDeviceCommands?.includes(command.id) && !this.device.failedDeviceCommands?.some((failure) => failure.id === command.id)) {
|
|
14798
14884
|
if (command.kind === "redetect" || this.supervisor.heartbeatRuns().length === 0) {
|
|
14799
14885
|
try {
|
package/client.js
CHANGED
|
@@ -2547,13 +2547,18 @@ var runReport = z9.object({
|
|
|
2547
2547
|
sha: z9.string().regex(/^[a-f0-9]{40}$/),
|
|
2548
2548
|
readOnly: z9.literal(true)
|
|
2549
2549
|
}).optional(),
|
|
2550
|
+
/** Preview branch created or used by the producing run; descriptive metadata only. */
|
|
2551
|
+
previewDatabaseBranch: z9.string().trim().min(1).max(500).optional(),
|
|
2550
2552
|
/** Acceptance criteria the agent checked, with evidence. */
|
|
2551
2553
|
criteria: z9.array(
|
|
2552
2554
|
z9.object({
|
|
2553
2555
|
criterionId: z9.uuid().optional(),
|
|
2554
2556
|
text: z9.string().max(2e3).optional(),
|
|
2555
2557
|
passed: z9.boolean(),
|
|
2556
|
-
evidence: z9.string().max(1e4).optional()
|
|
2558
|
+
evidence: z9.string().max(1e4).optional(),
|
|
2559
|
+
/** Agent-reported criterion check; the daemon-owned verify remains authoritative. */
|
|
2560
|
+
command: z9.string().trim().min(1).max(2e3).optional(),
|
|
2561
|
+
exitCode: z9.number().int().nullable().optional()
|
|
2557
2562
|
})
|
|
2558
2563
|
).max(200).optional(),
|
|
2559
2564
|
/**
|
|
@@ -2809,7 +2814,7 @@ var heartbeatRunSchema = z13.object({
|
|
|
2809
2814
|
/** Last tool call, turn boundary or file change (not raw output). */
|
|
2810
2815
|
lastProgressAt: isoTime
|
|
2811
2816
|
});
|
|
2812
|
-
var deviceManagementCommand = z13.object({ id: z13.uuid(), kind: z13.enum(["redetect", "restart", "update"]) });
|
|
2817
|
+
var deviceManagementCommand = z13.object({ id: z13.uuid(), kind: z13.enum(["redetect", "restart", "update", "uninstall"]) });
|
|
2813
2818
|
var deviceHeartbeatSchema = z13.object({
|
|
2814
2819
|
completedDeviceCommands: z13.array(z13.uuid()).max(100).optional(),
|
|
2815
2820
|
failedDeviceCommands: z13.array(z13.object({ id: z13.uuid(), error: z13.string().max(500) })).max(100).optional(),
|
|
@@ -3616,7 +3621,7 @@ import { join } from "node:path";
|
|
|
3616
3621
|
// package.json
|
|
3617
3622
|
var package_default = {
|
|
3618
3623
|
name: "@mikka/daemon",
|
|
3619
|
-
version: "0.0.
|
|
3624
|
+
version: "0.0.4",
|
|
3620
3625
|
description: "Local Mikka daemon: runs agents through the user's own CLIs",
|
|
3621
3626
|
type: "module",
|
|
3622
3627
|
private: true,
|
|
@@ -3673,7 +3678,8 @@ var package_default = {
|
|
|
3673
3678
|
},
|
|
3674
3679
|
engines: {
|
|
3675
3680
|
node: ">=24"
|
|
3676
|
-
}
|
|
3681
|
+
},
|
|
3682
|
+
gitHead: "4c5f80747928d60ea3e03ed6a3de5ca2dc2216df"
|
|
3677
3683
|
};
|
|
3678
3684
|
|
|
3679
3685
|
// src/paths.ts
|
package/http-link.js
CHANGED
|
@@ -2993,13 +2993,18 @@ var runReport = z15.object({
|
|
|
2993
2993
|
sha: z15.string().regex(/^[a-f0-9]{40}$/),
|
|
2994
2994
|
readOnly: z15.literal(true)
|
|
2995
2995
|
}).optional(),
|
|
2996
|
+
/** Preview branch created or used by the producing run; descriptive metadata only. */
|
|
2997
|
+
previewDatabaseBranch: z15.string().trim().min(1).max(500).optional(),
|
|
2996
2998
|
/** Acceptance criteria the agent checked, with evidence. */
|
|
2997
2999
|
criteria: z15.array(
|
|
2998
3000
|
z15.object({
|
|
2999
3001
|
criterionId: z15.uuid().optional(),
|
|
3000
3002
|
text: z15.string().max(2e3).optional(),
|
|
3001
3003
|
passed: z15.boolean(),
|
|
3002
|
-
evidence: z15.string().max(1e4).optional()
|
|
3004
|
+
evidence: z15.string().max(1e4).optional(),
|
|
3005
|
+
/** Agent-reported criterion check; the daemon-owned verify remains authoritative. */
|
|
3006
|
+
command: z15.string().trim().min(1).max(2e3).optional(),
|
|
3007
|
+
exitCode: z15.number().int().nullable().optional()
|
|
3003
3008
|
})
|
|
3004
3009
|
).max(200).optional(),
|
|
3005
3010
|
/**
|
|
@@ -3217,7 +3222,7 @@ var heartbeatRunSchema = z17.object({
|
|
|
3217
3222
|
/** Last tool call, turn boundary or file change (not raw output). */
|
|
3218
3223
|
lastProgressAt: isoTime
|
|
3219
3224
|
});
|
|
3220
|
-
var deviceManagementCommand = z17.object({ id: z17.uuid(), kind: z17.enum(["redetect", "restart", "update"]) });
|
|
3225
|
+
var deviceManagementCommand = z17.object({ id: z17.uuid(), kind: z17.enum(["redetect", "restart", "update", "uninstall"]) });
|
|
3221
3226
|
var deviceHeartbeatSchema = z17.object({
|
|
3222
3227
|
completedDeviceCommands: z17.array(z17.uuid()).max(100).optional(),
|
|
3223
3228
|
failedDeviceCommands: z17.array(z17.object({ id: z17.uuid(), error: z17.string().max(500) })).max(100).optional(),
|
|
@@ -3916,7 +3921,7 @@ var InvalidIdError = class extends DaemonError {
|
|
|
3916
3921
|
// package.json
|
|
3917
3922
|
var package_default = {
|
|
3918
3923
|
name: "@mikka/daemon",
|
|
3919
|
-
version: "0.0.
|
|
3924
|
+
version: "0.0.4",
|
|
3920
3925
|
description: "Local Mikka daemon: runs agents through the user's own CLIs",
|
|
3921
3926
|
type: "module",
|
|
3922
3927
|
private: true,
|
|
@@ -3973,7 +3978,8 @@ var package_default = {
|
|
|
3973
3978
|
},
|
|
3974
3979
|
engines: {
|
|
3975
3980
|
node: ">=24"
|
|
3976
|
-
}
|
|
3981
|
+
},
|
|
3982
|
+
gitHead: "4c5f80747928d60ea3e03ed6a3de5ca2dc2216df"
|
|
3977
3983
|
};
|
|
3978
3984
|
|
|
3979
3985
|
// src/paths.ts
|
|
@@ -4170,12 +4176,28 @@ var HttpServerLink = class {
|
|
|
4170
4176
|
const liveness = new AbortController();
|
|
4171
4177
|
const gate = new ToolApprovalGate(assignment.runId, {
|
|
4172
4178
|
permission: (request) => toolApprovalDecision(request, assignment.policy, worktree),
|
|
4179
|
+
// Keep the callback pending at the tool boundary. The adapter's current
|
|
4180
|
+
// session and checkpoint remain intact; handback resolves this same call.
|
|
4173
4181
|
isLive: async () => {
|
|
4174
4182
|
try {
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4183
|
+
for (; ; ) {
|
|
4184
|
+
check();
|
|
4185
|
+
const current = await this.call("POST", path, { body: { operation: "check", deviceId: assignment.deviceId, policyRevision }, schema: z25.object({ live: z25.boolean(), paused: z25.boolean().optional() }), signal: liveness.signal, timeoutMs: 5e3 });
|
|
4186
|
+
check();
|
|
4187
|
+
if (!current.live || !current.paused) return current.live;
|
|
4188
|
+
await new Promise((resolve2, reject) => {
|
|
4189
|
+
const stop = () => {
|
|
4190
|
+
clearTimeout(timer);
|
|
4191
|
+
reject(new Error("cancelled"));
|
|
4192
|
+
};
|
|
4193
|
+
const timer = setTimeout(() => {
|
|
4194
|
+
liveness.signal.removeEventListener("abort", stop);
|
|
4195
|
+
resolve2();
|
|
4196
|
+
}, 1e3);
|
|
4197
|
+
liveness.signal.addEventListener("abort", stop, { once: true });
|
|
4198
|
+
if (liveness.signal.aborted) stop();
|
|
4199
|
+
});
|
|
4200
|
+
}
|
|
4179
4201
|
} catch {
|
|
4180
4202
|
return false;
|
|
4181
4203
|
}
|
|
@@ -4204,9 +4226,11 @@ var HttpServerLink = class {
|
|
|
4204
4226
|
}
|
|
4205
4227
|
}
|
|
4206
4228
|
};
|
|
4229
|
+
if (!await gate.checkLive()) return "deny";
|
|
4207
4230
|
const created = await retry(() => this.call("POST", path, { body: { operation: "propose", deviceId: assignment.deviceId, policyRevision, requestId: request.requestId, harness: request.harness, method: request.method, input: request.input }, schema: proposal, signal: signal2 }));
|
|
4208
4231
|
try {
|
|
4209
4232
|
for (; ; ) {
|
|
4233
|
+
if (!await gate.checkLive()) return "deny";
|
|
4210
4234
|
const result = await retry(() => this.call("POST", path, { body: { operation: "take", deviceId: assignment.deviceId, id: created.id, digest: created.digest }, schema: response, signal: signal2 }));
|
|
4211
4235
|
if (result.decision !== "pending") return result.decision;
|
|
4212
4236
|
await delay();
|
package/login.js
CHANGED
|
@@ -2544,13 +2544,18 @@ var runReport = z9.object({
|
|
|
2544
2544
|
sha: z9.string().regex(/^[a-f0-9]{40}$/),
|
|
2545
2545
|
readOnly: z9.literal(true)
|
|
2546
2546
|
}).optional(),
|
|
2547
|
+
/** Preview branch created or used by the producing run; descriptive metadata only. */
|
|
2548
|
+
previewDatabaseBranch: z9.string().trim().min(1).max(500).optional(),
|
|
2547
2549
|
/** Acceptance criteria the agent checked, with evidence. */
|
|
2548
2550
|
criteria: z9.array(
|
|
2549
2551
|
z9.object({
|
|
2550
2552
|
criterionId: z9.uuid().optional(),
|
|
2551
2553
|
text: z9.string().max(2e3).optional(),
|
|
2552
2554
|
passed: z9.boolean(),
|
|
2553
|
-
evidence: z9.string().max(1e4).optional()
|
|
2555
|
+
evidence: z9.string().max(1e4).optional(),
|
|
2556
|
+
/** Agent-reported criterion check; the daemon-owned verify remains authoritative. */
|
|
2557
|
+
command: z9.string().trim().min(1).max(2e3).optional(),
|
|
2558
|
+
exitCode: z9.number().int().nullable().optional()
|
|
2554
2559
|
})
|
|
2555
2560
|
).max(200).optional(),
|
|
2556
2561
|
/**
|
|
@@ -2805,7 +2810,7 @@ var heartbeatRunSchema = z13.object({
|
|
|
2805
2810
|
/** Last tool call, turn boundary or file change (not raw output). */
|
|
2806
2811
|
lastProgressAt: isoTime
|
|
2807
2812
|
});
|
|
2808
|
-
var deviceManagementCommand = z13.object({ id: z13.uuid(), kind: z13.enum(["redetect", "restart", "update"]) });
|
|
2813
|
+
var deviceManagementCommand = z13.object({ id: z13.uuid(), kind: z13.enum(["redetect", "restart", "update", "uninstall"]) });
|
|
2809
2814
|
var deviceHeartbeatSchema = z13.object({
|
|
2810
2815
|
completedDeviceCommands: z13.array(z13.uuid()).max(100).optional(),
|
|
2811
2816
|
failedDeviceCommands: z13.array(z13.object({ id: z13.uuid(), error: z13.string().max(500) })).max(100).optional(),
|
|
@@ -3623,7 +3628,7 @@ var ServerUnreachableError = class extends DaemonError {
|
|
|
3623
3628
|
// package.json
|
|
3624
3629
|
var package_default = {
|
|
3625
3630
|
name: "@mikka/daemon",
|
|
3626
|
-
version: "0.0.
|
|
3631
|
+
version: "0.0.4",
|
|
3627
3632
|
description: "Local Mikka daemon: runs agents through the user's own CLIs",
|
|
3628
3633
|
type: "module",
|
|
3629
3634
|
private: true,
|
|
@@ -3680,7 +3685,8 @@ var package_default = {
|
|
|
3680
3685
|
},
|
|
3681
3686
|
engines: {
|
|
3682
3687
|
node: ">=24"
|
|
3683
|
-
}
|
|
3688
|
+
},
|
|
3689
|
+
gitHead: "4c5f80747928d60ea3e03ed6a3de5ca2dc2216df"
|
|
3684
3690
|
};
|
|
3685
3691
|
|
|
3686
3692
|
// src/paths.ts
|