@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/mikka-mcp.mjs
CHANGED
|
@@ -137,6 +137,7 @@ const TOOLS = [
|
|
|
137
137
|
},
|
|
138
138
|
spec: SPEC_SCHEMA,
|
|
139
139
|
split: SPLIT_SCHEMA,
|
|
140
|
+
previewDatabaseBranch: { type: "string", description: "Name of the preview database branch you actually created or used; omit when none." },
|
|
140
141
|
criteria: {
|
|
141
142
|
type: "array",
|
|
142
143
|
description:
|
|
@@ -149,6 +150,8 @@ const TOOLS = [
|
|
|
149
150
|
description: "The criterion's id, as given in your brief.",
|
|
150
151
|
},
|
|
151
152
|
passed: { type: "boolean" },
|
|
153
|
+
command: { type: "string", description: "Exact command used to check this criterion, when one was run." },
|
|
154
|
+
exitCode: { type: ["integer", "null"], description: "Observed exit code of that command." },
|
|
152
155
|
evidence: {
|
|
153
156
|
type: "string",
|
|
154
157
|
description:
|
|
@@ -332,6 +335,7 @@ function record(kind, args, toolName) {
|
|
|
332
335
|
: {}),
|
|
333
336
|
...(plan ? { plan } : {}),
|
|
334
337
|
// Kept as sent; the daemon validates and trims each entry.
|
|
338
|
+
...(typeof args.previewDatabaseBranch === "string" ? { previewDatabaseBranch: args.previewDatabaseBranch } : {}),
|
|
335
339
|
...(Array.isArray(args.criteria) ? { criteria: args.criteria } : {}),
|
|
336
340
|
at: new Date().toISOString(),
|
|
337
341
|
}
|
package/mikka.js
CHANGED
|
@@ -2217,7 +2217,7 @@ function closeLogger(logger) {
|
|
|
2217
2217
|
// src/service.ts
|
|
2218
2218
|
import { execFile } from "node:child_process";
|
|
2219
2219
|
import { promisify } from "node:util";
|
|
2220
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
2220
|
+
import { mkdir, writeFile, rm } from "node:fs/promises";
|
|
2221
2221
|
import { homedir } from "node:os";
|
|
2222
2222
|
import { dirname as dirname2, join as join2, resolve } from "node:path";
|
|
2223
2223
|
var exec = promisify(execFile);
|
|
@@ -2285,6 +2285,34 @@ async function restartService(update, beforeRestart, dependencies = {
|
|
|
2285
2285
|
beforeRestart();
|
|
2286
2286
|
dependencies.restart();
|
|
2287
2287
|
}
|
|
2288
|
+
async function uninstallService(clearCredential, dependencies = {
|
|
2289
|
+
manager: process.env.MIKKA_SERVICE,
|
|
2290
|
+
home: homedir(),
|
|
2291
|
+
uid: process.getuid?.() ?? 0,
|
|
2292
|
+
run: async (program, args) => {
|
|
2293
|
+
await exec(program, args, { timeout: 1e4 });
|
|
2294
|
+
},
|
|
2295
|
+
exit: () => {
|
|
2296
|
+
process.exit(0);
|
|
2297
|
+
}
|
|
2298
|
+
}) {
|
|
2299
|
+
try {
|
|
2300
|
+
if (dependencies.manager === "systemd") {
|
|
2301
|
+
await dependencies.run("systemctl", ["--user", "disable", "mikka-daemon.service"]);
|
|
2302
|
+
await rm(join2(dependencies.home, ".config/systemd/user/mikka-daemon.service"), { force: true });
|
|
2303
|
+
await dependencies.run("systemctl", ["--user", "daemon-reload"]);
|
|
2304
|
+
} else if (dependencies.manager === "launchd") {
|
|
2305
|
+
await rm(join2(dependencies.home, "Library/LaunchAgents", `${label}.plist`), { force: true });
|
|
2306
|
+
}
|
|
2307
|
+
} finally {
|
|
2308
|
+
clearCredential();
|
|
2309
|
+
try {
|
|
2310
|
+
if (dependencies.manager === "launchd") await dependencies.run("launchctl", ["bootout", `gui/${dependencies.uid}/${label}`]);
|
|
2311
|
+
} finally {
|
|
2312
|
+
dependencies.exit();
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2288
2316
|
|
|
2289
2317
|
// ../protocol/src/accounts.ts
|
|
2290
2318
|
import { z } from "zod";
|
|
@@ -2972,13 +3000,18 @@ var runReport = z9.object({
|
|
|
2972
3000
|
sha: z9.string().regex(/^[a-f0-9]{40}$/),
|
|
2973
3001
|
readOnly: z9.literal(true)
|
|
2974
3002
|
}).optional(),
|
|
3003
|
+
/** Preview branch created or used by the producing run; descriptive metadata only. */
|
|
3004
|
+
previewDatabaseBranch: z9.string().trim().min(1).max(500).optional(),
|
|
2975
3005
|
/** Acceptance criteria the agent checked, with evidence. */
|
|
2976
3006
|
criteria: z9.array(
|
|
2977
3007
|
z9.object({
|
|
2978
3008
|
criterionId: z9.uuid().optional(),
|
|
2979
3009
|
text: z9.string().max(2e3).optional(),
|
|
2980
3010
|
passed: z9.boolean(),
|
|
2981
|
-
evidence: z9.string().max(1e4).optional()
|
|
3011
|
+
evidence: z9.string().max(1e4).optional(),
|
|
3012
|
+
/** Agent-reported criterion check; the daemon-owned verify remains authoritative. */
|
|
3013
|
+
command: z9.string().trim().min(1).max(2e3).optional(),
|
|
3014
|
+
exitCode: z9.number().int().nullable().optional()
|
|
2982
3015
|
})
|
|
2983
3016
|
).max(200).optional(),
|
|
2984
3017
|
/**
|
|
@@ -3322,7 +3355,7 @@ var heartbeatRunSchema = z13.object({
|
|
|
3322
3355
|
/** Last tool call, turn boundary or file change (not raw output). */
|
|
3323
3356
|
lastProgressAt: isoTime
|
|
3324
3357
|
});
|
|
3325
|
-
var deviceManagementCommand = z13.object({ id: z13.uuid(), kind: z13.enum(["redetect", "restart", "update"]) });
|
|
3358
|
+
var deviceManagementCommand = z13.object({ id: z13.uuid(), kind: z13.enum(["redetect", "restart", "update", "uninstall"]) });
|
|
3326
3359
|
var deviceHeartbeatSchema = z13.object({
|
|
3327
3360
|
completedDeviceCommands: z13.array(z13.uuid()).max(100).optional(),
|
|
3328
3361
|
failedDeviceCommands: z13.array(z13.object({ id: z13.uuid(), error: z13.string().max(500) })).max(100).optional(),
|
|
@@ -4249,7 +4282,7 @@ import { join as join3 } from "node:path";
|
|
|
4249
4282
|
// package.json
|
|
4250
4283
|
var package_default = {
|
|
4251
4284
|
name: "@mikka/daemon",
|
|
4252
|
-
version: "0.0.
|
|
4285
|
+
version: "0.0.4",
|
|
4253
4286
|
description: "Local Mikka daemon: runs agents through the user's own CLIs",
|
|
4254
4287
|
type: "module",
|
|
4255
4288
|
private: true,
|
|
@@ -4306,7 +4339,8 @@ var package_default = {
|
|
|
4306
4339
|
},
|
|
4307
4340
|
engines: {
|
|
4308
4341
|
node: ">=24"
|
|
4309
|
-
}
|
|
4342
|
+
},
|
|
4343
|
+
gitHead: "4c5f80747928d60ea3e03ed6a3de5ca2dc2216df"
|
|
4310
4344
|
};
|
|
4311
4345
|
|
|
4312
4346
|
// src/paths.ts
|
|
@@ -4945,12 +4979,28 @@ var HttpServerLink = class {
|
|
|
4945
4979
|
const liveness = new AbortController();
|
|
4946
4980
|
const gate = new ToolApprovalGate(assignment.runId, {
|
|
4947
4981
|
permission: (request) => toolApprovalDecision(request, assignment.policy, worktree),
|
|
4982
|
+
// Keep the callback pending at the tool boundary. The adapter's current
|
|
4983
|
+
// session and checkpoint remain intact; handback resolves this same call.
|
|
4948
4984
|
isLive: async () => {
|
|
4949
4985
|
try {
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4986
|
+
for (; ; ) {
|
|
4987
|
+
check();
|
|
4988
|
+
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 });
|
|
4989
|
+
check();
|
|
4990
|
+
if (!current.live || !current.paused) return current.live;
|
|
4991
|
+
await new Promise((resolve10, reject) => {
|
|
4992
|
+
const stop = () => {
|
|
4993
|
+
clearTimeout(timer);
|
|
4994
|
+
reject(new Error("cancelled"));
|
|
4995
|
+
};
|
|
4996
|
+
const timer = setTimeout(() => {
|
|
4997
|
+
liveness.signal.removeEventListener("abort", stop);
|
|
4998
|
+
resolve10();
|
|
4999
|
+
}, 1e3);
|
|
5000
|
+
liveness.signal.addEventListener("abort", stop, { once: true });
|
|
5001
|
+
if (liveness.signal.aborted) stop();
|
|
5002
|
+
});
|
|
5003
|
+
}
|
|
4954
5004
|
} catch {
|
|
4955
5005
|
return false;
|
|
4956
5006
|
}
|
|
@@ -4979,9 +5029,11 @@ var HttpServerLink = class {
|
|
|
4979
5029
|
}
|
|
4980
5030
|
}
|
|
4981
5031
|
};
|
|
5032
|
+
if (!await gate.checkLive()) return "deny";
|
|
4982
5033
|
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 }));
|
|
4983
5034
|
try {
|
|
4984
5035
|
for (; ; ) {
|
|
5036
|
+
if (!await gate.checkLive()) return "deny";
|
|
4985
5037
|
const result = await retry(() => this.call("POST", path, { body: { operation: "take", deviceId: assignment.deviceId, id: created.id, digest: created.digest }, schema: response, signal: signal2 }));
|
|
4986
5038
|
if (result.decision !== "pending") return result.decision;
|
|
4987
5039
|
await delay3();
|
|
@@ -6194,6 +6246,7 @@ var RunContext = class {
|
|
|
6194
6246
|
nextStep: file.nextStep ?? null,
|
|
6195
6247
|
...file.blockedOn ? { blockedOn: file.blockedOn } : {},
|
|
6196
6248
|
...plan ? { plan } : {},
|
|
6249
|
+
...typeof file.previewDatabaseBranch === "string" ? { previewDatabaseBranch: file.previewDatabaseBranch } : {},
|
|
6197
6250
|
...Array.isArray(file.criteria) ? { criteria: file.criteria } : {},
|
|
6198
6251
|
...runQuestion.safeParse(file.question).success ? { question: runQuestion.parse(file.question) } : {}
|
|
6199
6252
|
};
|
|
@@ -6636,6 +6689,7 @@ import {
|
|
|
6636
6689
|
existsSync as existsSync6,
|
|
6637
6690
|
mkdirSync as mkdirSync15,
|
|
6638
6691
|
readFileSync as readFileSync11,
|
|
6692
|
+
rmSync as rmSync16,
|
|
6639
6693
|
realpathSync as realpathSync11
|
|
6640
6694
|
} from "node:fs";
|
|
6641
6695
|
import { arch, hostname, platform as platform2 } from "node:os";
|
|
@@ -12303,7 +12357,7 @@ var RunSupervisor = class {
|
|
|
12303
12357
|
const current = this.deps.journal.get(runId);
|
|
12304
12358
|
assertMailboxRunAuthority({ held: this.active.get(runId) === run2, state: current?.state, stopped: this.stopping || run2.cancelRequested || run2.abort.signal.aborted, lease });
|
|
12305
12359
|
};
|
|
12306
|
-
|
|
12360
|
+
let mailbox = await this.deps.prepareRunMailbox?.(assignment, run2.abort.signal, checkMailbox);
|
|
12307
12361
|
run2.mailbox = mailbox;
|
|
12308
12362
|
if (this.stopping) return;
|
|
12309
12363
|
if (run2.cancelRequested) {
|
|
@@ -12313,6 +12367,14 @@ var RunSupervisor = class {
|
|
|
12313
12367
|
if (mailbox) checkMailbox();
|
|
12314
12368
|
const toolApproval = await this.deps.prepareRunToolApproval?.(assignment, run2.abort.signal, checkMailbox, worktree);
|
|
12315
12369
|
run2.toolApproval = toolApproval;
|
|
12370
|
+
if (mailbox && toolApproval) {
|
|
12371
|
+
const original = mailbox;
|
|
12372
|
+
mailbox = { tools: original.tools, close: () => original.close(), request: async (body, signal) => {
|
|
12373
|
+
if (!await toolApproval.checkLive()) throw new Error("Run tool approval unavailable");
|
|
12374
|
+
return original.request(body, signal);
|
|
12375
|
+
} };
|
|
12376
|
+
run2.mailbox = mailbox;
|
|
12377
|
+
}
|
|
12316
12378
|
if (this.stopping) {
|
|
12317
12379
|
toolApproval?.revoke();
|
|
12318
12380
|
return;
|
|
@@ -12606,18 +12668,21 @@ function pickAgentReport(agent) {
|
|
|
12606
12668
|
const question = runQuestion.safeParse(agent.question);
|
|
12607
12669
|
if (question.success) picked.question = question.data;
|
|
12608
12670
|
if (agent.plan) picked.plan = agent.plan;
|
|
12671
|
+
if (typeof agent.previewDatabaseBranch === "string" && agent.previewDatabaseBranch.trim())
|
|
12672
|
+
picked.previewDatabaseBranch = agent.previewDatabaseBranch.trim().slice(0, 500);
|
|
12609
12673
|
if (Array.isArray(agent.criteria)) {
|
|
12610
12674
|
const criteria = [];
|
|
12611
12675
|
for (const entry of agent.criteria) {
|
|
12612
12676
|
if (criteria.length >= MAX_REPORTED_CRITERIA) break;
|
|
12613
12677
|
if (!entry || typeof entry !== "object") continue;
|
|
12614
|
-
const { criterionId, passed, evidence } = entry;
|
|
12678
|
+
const { criterionId, passed, evidence, command, exitCode } = entry;
|
|
12615
12679
|
if (typeof criterionId !== "string" || !UUID_RE.test(criterionId))
|
|
12616
12680
|
continue;
|
|
12617
12681
|
if (typeof passed !== "boolean") continue;
|
|
12618
12682
|
criteria.push({
|
|
12619
12683
|
criterionId,
|
|
12620
12684
|
passed,
|
|
12685
|
+
...typeof command === "string" && command.trim() ? { command: command.trim().slice(0, 2e3), ...exitCode === null || typeof exitCode === "number" && Number.isSafeInteger(exitCode) ? { exitCode } : {} } : {},
|
|
12621
12686
|
...typeof evidence === "string" ? { evidence: evidence.slice(0, 1e4) } : {}
|
|
12622
12687
|
});
|
|
12623
12688
|
}
|
|
@@ -12790,7 +12855,7 @@ import { promisify as promisify4 } from "node:util";
|
|
|
12790
12855
|
|
|
12791
12856
|
// src/agents/public-egress.ts
|
|
12792
12857
|
import { lookup } from "node:dns/promises";
|
|
12793
|
-
import { chmod, mkdtemp, rm } from "node:fs/promises";
|
|
12858
|
+
import { chmod, mkdtemp, rm as rm2 } from "node:fs/promises";
|
|
12794
12859
|
import { createServer as createServer3, request as httpRequest } from "node:http";
|
|
12795
12860
|
import { connect, isIP as isIP3 } from "node:net";
|
|
12796
12861
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
@@ -12972,7 +13037,7 @@ async function startPublicEgress(options) {
|
|
|
12972
13037
|
for (const socket of sockets) socket.destroy();
|
|
12973
13038
|
closing = new Promise((resolve10, reject) => server.close((error) => {
|
|
12974
13039
|
options.signal.removeEventListener("abort", onAbort);
|
|
12975
|
-
void
|
|
13040
|
+
void rm2(directory, { recursive: true, force: true }).then(() => error && error.code !== "ERR_SERVER_NOT_RUNNING" ? reject(error) : resolve10(), reject);
|
|
12976
13041
|
}));
|
|
12977
13042
|
return closing;
|
|
12978
13043
|
};
|
|
@@ -14778,7 +14843,7 @@ var Daemon = class {
|
|
|
14778
14843
|
}
|
|
14779
14844
|
const deviceId = this.device.deviceId;
|
|
14780
14845
|
const quotas = this.quota?.snapshot().quotas;
|
|
14781
|
-
const
|
|
14846
|
+
const heartbeat = {
|
|
14782
14847
|
completedDeviceCommands: this.device.completedDeviceCommands,
|
|
14783
14848
|
failedDeviceCommands: this.device.failedDeviceCommands,
|
|
14784
14849
|
harnesses: this.harnesses,
|
|
@@ -14786,7 +14851,8 @@ var Daemon = class {
|
|
|
14786
14851
|
runs: this.supervisor.heartbeatRuns(),
|
|
14787
14852
|
worktreeDiskBytes: await this.worktrees.diskUsage(),
|
|
14788
14853
|
...quotas ? { quotas } : {}
|
|
14789
|
-
}
|
|
14854
|
+
};
|
|
14855
|
+
const { leases, revoked, cloudCredential, deviceCommands } = await link.heartbeat(deviceId, heartbeat);
|
|
14790
14856
|
this.supervisor.renewLeases(leases);
|
|
14791
14857
|
if (revoked) this.supervisor.revokeLeases(revoked);
|
|
14792
14858
|
if (this.options.cloudComputer && cloudCredential && this.device.credential === credential) {
|
|
@@ -14795,6 +14861,26 @@ var Daemon = class {
|
|
|
14795
14861
|
this.registered = false;
|
|
14796
14862
|
}
|
|
14797
14863
|
const command = deviceCommands?.[0];
|
|
14864
|
+
if (command?.kind === "uninstall") {
|
|
14865
|
+
this.draining = true;
|
|
14866
|
+
if (this.supervisor.heartbeatRuns().length === 0) {
|
|
14867
|
+
this.saveDevice({ completedDeviceCommands: [command.id], failedDeviceCommands: [] });
|
|
14868
|
+
try {
|
|
14869
|
+
await link.heartbeat(deviceId, { ...heartbeat, runs: [], completedDeviceCommands: [command.id], failedDeviceCommands: [] });
|
|
14870
|
+
} catch {
|
|
14871
|
+
this.log.warn("Could not confirm uninstall receipt");
|
|
14872
|
+
}
|
|
14873
|
+
setImmediate(() => {
|
|
14874
|
+
void this.stop().then(() => uninstallService(() => {
|
|
14875
|
+
this.saveDevice({ credential: void 0 });
|
|
14876
|
+
rmSync16(this.paths.secret, { force: true });
|
|
14877
|
+
})).catch(() => {
|
|
14878
|
+
this.options.onDrained?.();
|
|
14879
|
+
});
|
|
14880
|
+
});
|
|
14881
|
+
}
|
|
14882
|
+
return;
|
|
14883
|
+
}
|
|
14798
14884
|
if (command && !this.device.completedDeviceCommands?.includes(command.id) && !this.device.failedDeviceCommands?.some((failure) => failure.id === command.id)) {
|
|
14799
14885
|
if (command.kind === "redetect" || this.supervisor.heartbeatRuns().length === 0) {
|
|
14800
14886
|
try {
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aspectlylabs/mikka",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Local Mikka daemon: runs agents through the user's own CLIs",
|
|
5
|
+
"gitHead": "4c5f80747928d60ea3e03ed6a3de5ca2dc2216df",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"private": false,
|
|
7
8
|
"license": "AGPL-3.0-only",
|
package/paths.js
CHANGED
|
@@ -6,7 +6,7 @@ import { join } from "node:path";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@mikka/daemon",
|
|
9
|
-
version: "0.0.
|
|
9
|
+
version: "0.0.4",
|
|
10
10
|
description: "Local Mikka daemon: runs agents through the user's own CLIs",
|
|
11
11
|
type: "module",
|
|
12
12
|
private: true,
|
|
@@ -63,7 +63,8 @@ var package_default = {
|
|
|
63
63
|
},
|
|
64
64
|
engines: {
|
|
65
65
|
node: ">=24"
|
|
66
|
-
}
|
|
66
|
+
},
|
|
67
|
+
gitHead: "4c5f80747928d60ea3e03ed6a3de5ca2dc2216df"
|
|
67
68
|
};
|
|
68
69
|
|
|
69
70
|
// src/paths.ts
|