@modootoday/pmcp 0.11.0 → 0.13.0

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.
@@ -0,0 +1,2737 @@
1
+ // src/harness/application/worker.ts
2
+ import { unlinkSync as unlinkSync4 } from "fs";
3
+
4
+ // src/harness/groups/store.ts
5
+ import { randomUUID } from "crypto";
6
+ import {
7
+ closeSync,
8
+ constants,
9
+ fstatSync,
10
+ fsyncSync,
11
+ openSync,
12
+ readFileSync,
13
+ realpathSync,
14
+ renameSync,
15
+ writeFileSync
16
+ } from "fs";
17
+ import { dirname, join } from "path";
18
+
19
+ // src/harness/validation.ts
20
+ function object(value) {
21
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
22
+ throw new Error("invalid_object");
23
+ }
24
+ return value;
25
+ }
26
+ function text(value, name) {
27
+ if (typeof value !== "string" || value.length === 0 || value.includes("\0")) {
28
+ throw new Error(`invalid_${name}`);
29
+ }
30
+ return value;
31
+ }
32
+ function integer(value, name, min, max) {
33
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < min || value > max) {
34
+ throw new Error(`invalid_${name}`);
35
+ }
36
+ return value;
37
+ }
38
+ function strings(value, name) {
39
+ if (!Array.isArray(value) || value.length === 0 || value.length > 64) {
40
+ throw new Error(`invalid_${name}`);
41
+ }
42
+ return value.map((entry) => text(entry, name));
43
+ }
44
+ function id(value, name) {
45
+ const result = text(value, name);
46
+ if (!/^[a-zA-Z0-9-]{1,80}$/.test(result)) throw new Error(`invalid_${name}`);
47
+ return result;
48
+ }
49
+
50
+ // src/harness/runtimes/docker-policy.ts
51
+ import { isAbsolute as isAbsolute3, posix as posix3 } from "path";
52
+
53
+ // src/harness/runtimes/registry.ts
54
+ var runtimeExecutables = {
55
+ "codex-cli": "codex",
56
+ "claude-code": "claude",
57
+ "gemini-cli": "gemini",
58
+ "grok-cli": "grok",
59
+ antigravity: "agy"
60
+ };
61
+
62
+ // src/harness/runtimes/egress-policy.ts
63
+ import { isAbsolute, posix } from "path";
64
+ function egressPolicy(value) {
65
+ const policy = object(value);
66
+ const hosts = strings(policy.hosts, "egress_hosts").map(
67
+ (host) => host.toLowerCase()
68
+ );
69
+ if (hosts.length > 16 || new Set(hosts).size !== hosts.length)
70
+ throw new Error("invalid_egress_hosts");
71
+ for (const host of hosts) {
72
+ if (host.length > 253 || !host.includes(".") || /^[0-9.]+$/.test(host) || !host.split(".").every(
73
+ (label) => /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(label)
74
+ ) || /\.(local|localhost|internal|invalid|test)$/.test(host))
75
+ throw new Error("invalid_egress_host");
76
+ }
77
+ if (policy.bridgeExecutable === void 0) return { hosts };
78
+ const executable = text(policy.bridgeExecutable, "egress_bridge_executable");
79
+ if (!isAbsolute(executable) || posix.normalize(executable) !== executable || /[\r\n\x1b]/.test(executable))
80
+ throw new Error("invalid_egress_bridge_executable");
81
+ return { hosts, bridgeExecutable: executable };
82
+ }
83
+
84
+ // src/harness/runtimes/private-profiles.ts
85
+ import { isAbsolute as isAbsolute2, posix as posix2 } from "path";
86
+ function profileName(value) {
87
+ const name = text(value, "private_profile");
88
+ if (!/^[a-z][a-z0-9-]{0,31}$/.test(name))
89
+ throw new Error("invalid_private_profile_name");
90
+ return name;
91
+ }
92
+ function privateProfiles(value) {
93
+ const entries = Object.entries(object(value));
94
+ if (!entries.length || entries.length > 16)
95
+ throw new Error("invalid_private_profile_grants");
96
+ const result = {};
97
+ for (const [name, entry] of entries) {
98
+ profileName(name);
99
+ const grant = object(entry);
100
+ const runtime = text(grant.runtime, "private_profile_runtime");
101
+ const directory = absolute(grant.directory, "private_profile_directory");
102
+ const lockExecutable = absolute(
103
+ grant.lockExecutable,
104
+ "private_profile_lock_executable"
105
+ );
106
+ const identity = grant.identity === void 0 ? void 0 : text(grant.identity, "private_profile_identity");
107
+ if (identity !== void 0 && !/^\d+:\d+:\d+:\d+$/.test(identity))
108
+ throw new Error("invalid_private_profile_identity");
109
+ result[name] = {
110
+ runtime,
111
+ directory,
112
+ lockExecutable,
113
+ ...identity ? { identity } : {}
114
+ };
115
+ }
116
+ if (new Set(Object.values(result).map((grant) => grant.directory)).size !== entries.length)
117
+ throw new Error("duplicate_private_profile_directory");
118
+ return result;
119
+ }
120
+ function absolute(value, field) {
121
+ const path = text(value, field);
122
+ if (!isAbsolute2(path) || posix2.normalize(path) !== path || /[\r\n\x1b]/.test(path))
123
+ throw new Error("invalid_private_profile_path");
124
+ return path;
125
+ }
126
+ function selectedProfile(policy, name, runtime) {
127
+ if (name === void 0) return;
128
+ const grant = policy.privateProfiles?.[profileName(name)];
129
+ if (!grant || grant.runtime !== runtime || !grant.identity)
130
+ throw new Error("private_profile_not_granted");
131
+ return grant;
132
+ }
133
+
134
+ // src/harness/runtimes/docker-policy.ts
135
+ function dockerPolicy(value) {
136
+ const policy = object(value);
137
+ if (policy.schemaVersion !== 1)
138
+ throw new Error("invalid_docker_policy_version");
139
+ if (!/^sha256:[a-f0-9]{64}$/.test(text(policy.image, "docker_image")))
140
+ throw new Error("docker_image_requires_digest");
141
+ if (policy.network !== "none")
142
+ throw new Error("docker_network_not_qualified");
143
+ if (policy.workspaceAccess !== "read-only" && policy.workspaceAccess !== "read-write")
144
+ throw new Error("invalid_docker_workspace_access");
145
+ const commands = object(policy.commands);
146
+ const entries = Object.entries(commands);
147
+ if (!entries.length || entries.length > 5)
148
+ throw new Error("invalid_docker_runtime_commands");
149
+ const parsed = {};
150
+ for (const [runtime, value2] of entries) {
151
+ if (!Object.hasOwn(runtimeExecutables, runtime))
152
+ throw new Error("unsupported_docker_runtime");
153
+ const command2 = strings(value2, "docker_runtime_command");
154
+ const executable = command2[0];
155
+ if (!isAbsolute3(executable) || posix3.normalize(executable) !== executable || command2.some((argument) => /[\r\n\x1b]/.test(argument)))
156
+ throw new Error("invalid_docker_runtime_command");
157
+ parsed[runtime] = command2;
158
+ }
159
+ return {
160
+ schemaVersion: 1,
161
+ image: text(policy.image, "docker_image"),
162
+ network: "none",
163
+ workspaceAccess: policy.workspaceAccess,
164
+ commands: parsed,
165
+ ...policy.egress === void 0 ? {} : { egress: egressPolicy(policy.egress) },
166
+ ...policy.privateProfiles === void 0 ? {} : { privateProfiles: privateProfiles(policy.privateProfiles) }
167
+ };
168
+ }
169
+
170
+ // src/harness/groups/validation.ts
171
+ function member(value, allowed) {
172
+ if (!allowed.includes(value)) throw new Error("invalid_state_value");
173
+ }
174
+ function records(value) {
175
+ if (!Array.isArray(value) || value.length > 4096)
176
+ throw new Error("invalid_state_collection");
177
+ return value.map(object);
178
+ }
179
+ function unique(values) {
180
+ if (new Set(values).size !== values.length)
181
+ throw new Error("duplicate_state_identity");
182
+ }
183
+ function validateState(value) {
184
+ const state = object(value);
185
+ const group = object(state.group);
186
+ member(group.schemaVersion, [1]);
187
+ for (const field of ["owner", "id", "generation"]) id(group[field], field);
188
+ text(group.projectRoot, "project_root");
189
+ strings(group.allowedRuntimes, "allowed_runtimes");
190
+ member(group.profile, ["native", "docker"]);
191
+ if (group.profile === "docker") dockerPolicy(group.dockerPolicy);
192
+ if (group.profile === "native" && group.dockerPolicy !== void 0)
193
+ throw new Error("docker_policy_requires_docker_profile");
194
+ member(group.state, ["ready", "paused", "stopped"]);
195
+ integer(group.memoryMb, "memory_budget", 128, 4096);
196
+ integer(group.maxActive, "max_active", 1, 5);
197
+ const sessions = records(group.sessions);
198
+ for (const session of sessions) {
199
+ id(session.id, "session_id");
200
+ member(session.role, ["main", "worker"]);
201
+ member(session.stopped, [true, false]);
202
+ }
203
+ unique(sessions.map((session) => session.id));
204
+ if (sessions.filter((s) => s.role === "main" && !s.stopped).length > 1)
205
+ throw new Error("multiple_active_main_sessions");
206
+ const leases = records(state.leases);
207
+ for (const lease of leases) {
208
+ id(lease.token, "control_token");
209
+ id(lease.controller, "controller");
210
+ member(lease.generation, [group.generation]);
211
+ member(lease.mode, ["cli", "native"]);
212
+ member(
213
+ lease.sessionId,
214
+ sessions.map((session) => session.id)
215
+ );
216
+ if (!Number.isFinite(Date.parse(text(lease.expiresAt, "control_expiry"))))
217
+ throw new Error("invalid_control_expiry");
218
+ }
219
+ unique(leases.map((lease) => lease.token));
220
+ unique(leases.map((lease) => lease.sessionId));
221
+ const deliveries = records(state.deliveries);
222
+ for (const delivery of deliveries) {
223
+ if (delivery.controller !== void 0)
224
+ id(delivery.controller, "controller");
225
+ id(delivery.requestId, "request_id");
226
+ id(delivery.sessionId, "session_id");
227
+ id(delivery.generation, "generation");
228
+ member(delivery.operation, ["write", "submit"]);
229
+ member(delivery.state, ["intent", "input_written", "delivery_uncertain"]);
230
+ if (!/^[a-f0-9]{64}$/.test(text(delivery.digest, "delivery_digest")))
231
+ throw new Error("invalid_delivery_digest");
232
+ }
233
+ unique(deliveries.map((delivery) => delivery.requestId));
234
+ return state;
235
+ }
236
+
237
+ // src/harness/groups/store.ts
238
+ function privateJson(path, value) {
239
+ const temporary = `${path}.${randomUUID()}.new`;
240
+ const descriptor = openSync(temporary, "wx", 384);
241
+ try {
242
+ writeFileSync(descriptor, `${JSON.stringify(value, null, 2)}
243
+ `);
244
+ fsyncSync(descriptor);
245
+ } finally {
246
+ closeSync(descriptor);
247
+ }
248
+ renameSync(temporary, path);
249
+ const directory = openSync(dirname(path), "r");
250
+ try {
251
+ fsyncSync(directory);
252
+ } finally {
253
+ closeSync(directory);
254
+ }
255
+ }
256
+ function readPrivateJson(path) {
257
+ const descriptor = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);
258
+ try {
259
+ const stat = fstatSync(descriptor);
260
+ if (!stat.isFile() || (stat.mode & 63) !== 0 || stat.size > 2097152)
261
+ throw new Error("unsafe_state_file");
262
+ if (stat.uid !== process.getuid?.()) throw new Error("foreign_state_file");
263
+ return JSON.parse(readFileSync(descriptor, "utf8"));
264
+ } finally {
265
+ closeSync(descriptor);
266
+ }
267
+ }
268
+ var GroupStore = class {
269
+ path;
270
+ state;
271
+ constructor(path) {
272
+ this.path = realpathSync(path);
273
+ this.state = validateState(readPrivateJson(path));
274
+ const metadata = object(
275
+ readPrivateJson(join(dirname(this.path), "harness.json"))
276
+ );
277
+ if (this.state.group.schemaVersion !== 1 || this.state.group.owner !== metadata.owner) {
278
+ throw new Error("foreign_group");
279
+ }
280
+ }
281
+ save() {
282
+ validateState(this.state);
283
+ privateJson(this.path, this.state);
284
+ }
285
+ session(id2) {
286
+ if (!this.state.group.sessions.some((entry) => entry.id === id2)) {
287
+ throw new Error("foreign_session");
288
+ }
289
+ }
290
+ };
291
+
292
+ // src/harness/control/leases.ts
293
+ import { randomUUID as randomUUID5 } from "crypto";
294
+ import { join as join12 } from "path";
295
+
296
+ // src/harness/adapters/process/command.ts
297
+ import {
298
+ execFileSync
299
+ } from "child_process";
300
+ function command(binary, args, options = {}) {
301
+ return execFileSync(binary, args, {
302
+ encoding: "utf8",
303
+ timeout: 1e4,
304
+ maxBuffer: 256 * 1024,
305
+ stdio: ["pipe", "pipe", "pipe"],
306
+ ...options
307
+ });
308
+ }
309
+ function quote(value) {
310
+ return `'${value.replaceAll("'", "'\\''")}'`;
311
+ }
312
+
313
+ // src/harness/adapters/process/identity.ts
314
+ import { readFileSync as readFileSync2 } from "fs";
315
+ function processIdentity(pid) {
316
+ if (!Number.isSafeInteger(pid) || pid < 1)
317
+ throw new Error("invalid_process_id");
318
+ const stat = readFileSync2(`/proc/${pid}/stat`, "utf8");
319
+ const fields = stat.slice(stat.lastIndexOf(")") + 2).split(" ");
320
+ if (!/^\d+$/.test(fields[19] ?? ""))
321
+ throw new Error("process_identity_unknown");
322
+ return `${pid}:${fields[19]}`;
323
+ }
324
+ function controllerExited(identity) {
325
+ if (!/^\d+:\d+$/.test(identity))
326
+ throw new Error("invalid_controller_identity");
327
+ const [pid] = identity.split(":");
328
+ try {
329
+ return processIdentity(Number(pid)) !== identity;
330
+ } catch (error) {
331
+ if (error.code === "ENOENT") return true;
332
+ throw new Error("controller_liveness_unknown", { cause: error });
333
+ }
334
+ }
335
+
336
+ // src/harness/adapters/docker/claims.ts
337
+ import { createHash } from "crypto";
338
+
339
+ // src/harness/adapters/docker/identity.ts
340
+ var containerLabels = {
341
+ owner: "pmcp.harness.owner",
342
+ nonce: "pmcp.harness.nonce",
343
+ role: "pmcp.harness.role"
344
+ };
345
+ function containerName(owner, sessionId) {
346
+ return `pmcp-harness-${owner.slice(0, 8)}-${sessionId}`;
347
+ }
348
+
349
+ // src/harness/adapters/docker/claims.ts
350
+ function resourceClaim(value, owner) {
351
+ const record = object(value);
352
+ if (record.kind !== "docker" || record.owner !== owner)
353
+ throw new Error("foreign_container_resource");
354
+ if (!/^[a-f0-9]{64}$/.test(text(record.id, "container_id")))
355
+ throw new Error("invalid_container_id");
356
+ if (!/^sha256:[a-f0-9]{64}$/.test(text(record.image, "container_image")))
357
+ throw new Error("invalid_container_image");
358
+ if (!/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(
359
+ text(record.nonce, "container_nonce")
360
+ ))
361
+ throw new Error("invalid_container_nonce");
362
+ if (record.role !== "main" && record.role !== "worker")
363
+ throw new Error("invalid_container_role");
364
+ if (!/^[a-f0-9]{64}$/.test(
365
+ text(record.configurationDigest, "container_configuration")
366
+ ))
367
+ throw new Error("invalid_container_configuration");
368
+ integer(record.memoryMb, "container_memory", 32, 1472);
369
+ integer(record.cpuQuota, "container_cpu", 1, 5e4);
370
+ if (record.managed !== void 0 && record.managed !== true)
371
+ throw new Error("invalid_container_custody");
372
+ if (record.privateProfile !== void 0) {
373
+ profileName(record.privateProfile);
374
+ if (record.managed !== true)
375
+ throw new Error("private_profile_requires_cli_owned_creation");
376
+ }
377
+ return record;
378
+ }
379
+ function assertResourceOwner(resource, actual) {
380
+ const config = object(actual.Config);
381
+ const labels = object(config.Labels);
382
+ if (actual.Id !== resource.id || actual.Image !== resource.image || labels[containerLabels.owner] !== resource.owner || labels[containerLabels.nonce] !== resource.nonce || labels[containerLabels.role] !== resource.role)
383
+ throw new Error("foreign_container_identity");
384
+ }
385
+ function configurationDigest(actual) {
386
+ const host = object(actual.HostConfig);
387
+ if (host.OomKillDisable !== false && host.OomKillDisable !== null)
388
+ throw new Error("container_oom_protection_disabled");
389
+ if (!Array.isArray(actual.Mounts))
390
+ throw new Error("invalid_container_mounts");
391
+ const mounts = actual.Mounts.map(object).sort(
392
+ (left, right) => text(left.Destination, "mount_destination").localeCompare(
393
+ text(right.Destination, "mount_destination")
394
+ )
395
+ );
396
+ return createHash("sha256").update(
397
+ JSON.stringify(
398
+ canonicalValue({
399
+ config: actual.Config,
400
+ host: { ...host, OomKillDisable: false },
401
+ mounts
402
+ })
403
+ )
404
+ ).digest("hex");
405
+ }
406
+ function canonicalValue(value) {
407
+ if (Array.isArray(value)) return value.map(canonicalValue);
408
+ if (value === null || typeof value !== "object") return value;
409
+ return Object.fromEntries(
410
+ Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, canonicalValue(entry)])
411
+ );
412
+ }
413
+
414
+ // src/harness/adapters/docker/observation.ts
415
+ function inspectResource(resource, enforceConfiguration = true) {
416
+ const result = JSON.parse(command("docker", ["inspect", resource.id]));
417
+ if (!Array.isArray(result) || result.length !== 1)
418
+ throw new Error("invalid_container_inspection");
419
+ const actual = object(result[0]);
420
+ assertResourceOwner(resource, actual);
421
+ if (enforceConfiguration && configurationDigest(actual) !== resource.configurationDigest)
422
+ throw new Error("container_configuration_changed");
423
+ return actual;
424
+ }
425
+ function resourceAbsent(error, id2) {
426
+ const failure = error;
427
+ const message = String(failure.stderr).toLowerCase();
428
+ return ["object", "container"].some(
429
+ (kind) => message.includes(`no such ${kind}: ${id2}`)
430
+ );
431
+ }
432
+ function assertResourceFresh(resource) {
433
+ const state = object(inspectResource(resource).State);
434
+ if (state.Status !== "created" || state.Running !== false || state.Pid !== 0)
435
+ throw new Error("container_requires_fresh_creation");
436
+ }
437
+ function resourceRunning(resource) {
438
+ let actual;
439
+ try {
440
+ actual = inspectResource(resource);
441
+ } catch (error) {
442
+ if (resourceAbsent(error, resource.id)) return false;
443
+ throw error;
444
+ }
445
+ const state = object(actual.State);
446
+ if (typeof state.Running !== "boolean")
447
+ throw new Error("unknown_container_lifecycle");
448
+ return state.Running;
449
+ }
450
+
451
+ // src/harness/adapters/tmux/connection.ts
452
+ var Connection = class {
453
+ constructor(records2) {
454
+ this.records = records2;
455
+ }
456
+ records;
457
+ tmux(args, options = {}) {
458
+ return command(
459
+ "tmux",
460
+ ["-S", this.records.socket, "-f", this.records.configPath, ...args],
461
+ options
462
+ );
463
+ }
464
+ alive() {
465
+ try {
466
+ this.tmux(["list-sessions"]);
467
+ return true;
468
+ } catch (error) {
469
+ const failure = error;
470
+ if (/no server running|No such file or directory|no sessions/.test(
471
+ String(failure.stderr ?? failure.message)
472
+ ))
473
+ return false;
474
+ throw error;
475
+ }
476
+ }
477
+ inspect(id2) {
478
+ const record = this.records.read(id2);
479
+ const target = this.tmux([
480
+ "display-message",
481
+ "-p",
482
+ "-t",
483
+ record.paneId,
484
+ "#{pid}|#{pane_id}|#{pane_pid}|#{pane_dead}|#{@pmcp-owner}|#{@pmcp-session}|#{pane_width}|#{pane_height}|#{session_id}|#{window_id}"
485
+ ]).trim().split("|");
486
+ const [
487
+ serverPid,
488
+ paneId,
489
+ panePid,
490
+ dead,
491
+ owner,
492
+ sessionId,
493
+ width,
494
+ height,
495
+ tmuxSessionId,
496
+ windowId
497
+ ] = target;
498
+ if (processIdentity(Number(serverPid)) !== record.serverIdentity)
499
+ throw new Error("stale_server");
500
+ if (paneId !== record.paneId || Number(panePid) !== record.panePid || tmuxSessionId !== record.tmuxSessionId || windowId !== record.windowId)
501
+ throw new Error("stale_pane");
502
+ if (owner !== this.records.owner || sessionId !== id2)
503
+ throw new Error("foreign_pane");
504
+ return {
505
+ ...record,
506
+ alive: dead === "0" && (!record.resource || resourceRunning(record.resource)),
507
+ width: Number(width),
508
+ height: Number(height)
509
+ };
510
+ }
511
+ };
512
+
513
+ // src/harness/adapters/tmux/records.ts
514
+ import { randomUUID as randomUUID2 } from "crypto";
515
+ import {
516
+ lstatSync,
517
+ mkdirSync,
518
+ readdirSync,
519
+ realpathSync as realpathSync2,
520
+ writeFileSync as writeFileSync2
521
+ } from "fs";
522
+ import { homedir } from "os";
523
+ import { join as join2 } from "path";
524
+ function stateDirectory() {
525
+ return join2(
526
+ process.env.XDG_STATE_HOME ?? join2(homedir(), ".local/state"),
527
+ "pmcp/harness"
528
+ );
529
+ }
530
+ function runtimeUnit(id2) {
531
+ if (!/^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}$/.test(id2))
532
+ throw new Error("invalid_session_id");
533
+ return `pmcp-${id2}.scope`;
534
+ }
535
+ function budgetSlice(owner) {
536
+ runtimeUnit(owner);
537
+ return `pmcp${owner.replaceAll("-", "")}.slice`;
538
+ }
539
+ var RecordStore = class _RecordStore {
540
+ directory;
541
+ socket;
542
+ metadataPath;
543
+ configPath;
544
+ owner;
545
+ constructor(directory) {
546
+ const stat = lstatSync(directory);
547
+ if (!stat.isDirectory() || stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
548
+ throw new Error("unsafe_group_directory");
549
+ this.directory = realpathSync2(directory);
550
+ this.socket = join2(this.directory, "s");
551
+ if (Buffer.byteLength(this.socket) > 100)
552
+ throw new Error("socket_path_too_long");
553
+ this.metadataPath = join2(this.directory, "harness.json");
554
+ this.configPath = join2(this.directory, "tmux.conf");
555
+ this.owner = text(
556
+ object(readPrivateJson(this.metadataPath)).owner,
557
+ "owner"
558
+ );
559
+ runtimeUnit(this.owner);
560
+ }
561
+ static create() {
562
+ const root = stateDirectory();
563
+ mkdirSync(root, { recursive: true, mode: 448 });
564
+ const directory = join2(root, randomUUID2().slice(0, 16));
565
+ if (Buffer.byteLength(join2(directory, "s")) > 100)
566
+ throw new Error("socket_path_too_long");
567
+ mkdirSync(directory, { mode: 448 });
568
+ mkdirSync(join2(directory, "sessions"), { mode: 448 });
569
+ privateJson(join2(directory, "harness.json"), {
570
+ owner: randomUUID2(),
571
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
572
+ });
573
+ writeFileSync2(
574
+ join2(directory, "tmux.conf"),
575
+ [
576
+ "set -g remain-on-exit on",
577
+ "set -g history-limit 2000",
578
+ "set -g default-terminal tmux-256color",
579
+ "set -g status off",
580
+ "set -g mouse off",
581
+ "set -g destroy-unattached off",
582
+ ""
583
+ ].join("\n"),
584
+ { flag: "wx", mode: 384 }
585
+ );
586
+ return new _RecordStore(directory);
587
+ }
588
+ path(id2) {
589
+ runtimeUnit(id2);
590
+ return join2(this.directory, "sessions", `${id2}.json`);
591
+ }
592
+ read(id2) {
593
+ const record = object(readPrivateJson(this.path(id2)));
594
+ if (record.id !== id2 || record.owner !== this.owner || record.socket !== this.socket || record.unit !== runtimeUnit(id2))
595
+ throw new Error("foreign_backend_record");
596
+ for (const [field, pattern] of [
597
+ ["paneId", /^%\d+$/],
598
+ ["windowId", /^@\d+$/],
599
+ ["tmuxSessionId", /^\$\d+$/],
600
+ ["serverIdentity", /^\d+:\d+$/]
601
+ ]) {
602
+ if (!pattern.test(text(record[field], field)))
603
+ throw new Error("invalid_terminal_identity");
604
+ }
605
+ if (!Number.isSafeInteger(record.panePid) || Number(record.panePid) < 1)
606
+ throw new Error("invalid_pane_process");
607
+ if (record.resource !== void 0)
608
+ resourceClaim(record.resource, this.owner);
609
+ return record;
610
+ }
611
+ all() {
612
+ return readdirSync(join2(this.directory, "sessions")).filter((name) => name.endsWith(".json")).map((name) => this.read(name.slice(0, -5)));
613
+ }
614
+ save(record) {
615
+ privateJson(this.path(record.id), record);
616
+ }
617
+ };
618
+
619
+ // src/harness/adapters/tmux/lifecycle.ts
620
+ import { randomUUID as randomUUID3 } from "crypto";
621
+ import { existsSync as existsSync4 } from "fs";
622
+ import { setTimeout } from "timers/promises";
623
+
624
+ // src/harness/adapters/process/artifact.ts
625
+ import { fileURLToPath } from "url";
626
+ var sources = {
627
+ worker: "../../application/worker.ts",
628
+ "pane-runner": "./pane-runner.ts",
629
+ "launch-gate": "./launch-gate.ts",
630
+ "egress-bridge": "../egress/bridge-runtime.ts"
631
+ };
632
+ function artifact(name) {
633
+ if (import.meta.url.endsWith(".ts"))
634
+ return fileURLToPath(new URL(sources[name], import.meta.url));
635
+ return fileURLToPath(new URL(`./harness-${name}.js`, import.meta.url));
636
+ }
637
+
638
+ // src/harness/adapters/tmux/lifecycle.ts
639
+ import { join as join10 } from "path";
640
+
641
+ // src/harness/adapters/systemd/units.ts
642
+ function unitActive(unit) {
643
+ let state;
644
+ try {
645
+ state = command("systemctl", [
646
+ "--user",
647
+ "show",
648
+ unit,
649
+ "--property=ActiveState",
650
+ "--value"
651
+ ]).trim();
652
+ } catch (error) {
653
+ const failure = error;
654
+ if (/not found|could not be found|No such/i.test(String(failure.stderr)))
655
+ return false;
656
+ throw error;
657
+ }
658
+ return ["active", "activating", "deactivating"].includes(state);
659
+ }
660
+ function stopUnit(unit) {
661
+ if (!unitActive(unit)) return;
662
+ try {
663
+ command("systemctl", ["--user", "stop", unit]);
664
+ } catch (error) {
665
+ const stderr = String(error.stderr);
666
+ if (!stderr.includes(unit) || !/not loaded|not found|could not be found/i.test(stderr))
667
+ throw error;
668
+ if (unitActive(unit)) throw error;
669
+ }
670
+ if (unitActive(unit)) throw new Error("runtime_stop_unconfirmed");
671
+ }
672
+
673
+ // src/harness/adapters/tmux/launch-identity.ts
674
+ function assertProof(connection, proof) {
675
+ const record = proof.session;
676
+ const fields = connection.tmux([
677
+ "display-message",
678
+ "-p",
679
+ "-t",
680
+ record.paneId,
681
+ "#{pid}|#{session_id}|#{window_id}|#{pane_id}|#{pane_pid}|#{@pmcp-owner}|#{@pmcp-session}|#{@pmcp-launch}"
682
+ ]).trim().split("|");
683
+ if (processIdentity(Number(fields[0])) !== record.serverIdentity)
684
+ throw new Error("stale_launch_server");
685
+ if (fields[1] !== record.tmuxSessionId || fields[2] !== record.windowId || fields[3] !== record.paneId || Number(fields[4]) !== record.panePid)
686
+ throw new Error("stale_launch_pane");
687
+ if (fields[5] !== record.owner || fields[6] !== record.id || fields[7] !== proof.nonce)
688
+ throw new Error("foreign_launch_pane");
689
+ }
690
+ function panePresent(connection, proof) {
691
+ if (!connection.alive()) return false;
692
+ const rows = connection.tmux(["list-panes", "-a", "-F", "#{pid}|#{pane_id}"]).trim().split("\n");
693
+ const server = Number(rows[0]?.split("|")[0]);
694
+ if (processIdentity(server) !== proof.session.serverIdentity)
695
+ throw new Error("stale_launch_server");
696
+ return rows.some((row) => row.split("|")[1] === proof.session.paneId);
697
+ }
698
+
699
+ // src/harness/launch/journal.ts
700
+ import { createHash as createHash2 } from "crypto";
701
+ import { existsSync, readdirSync as readdirSync2 } from "fs";
702
+ import { join as join3 } from "path";
703
+ var LaunchJournal = class {
704
+ constructor(records2, id2) {
705
+ this.records = records2;
706
+ this.id = id2;
707
+ runtimeUnit(id2);
708
+ }
709
+ records;
710
+ id;
711
+ path(kind) {
712
+ if (!["intent", "proof", "grant", "committed", "aborted"].includes(kind))
713
+ throw new Error("invalid_launch_artifact");
714
+ return join3(this.records.directory, `${this.id}.${kind}.json`);
715
+ }
716
+ intent() {
717
+ const value = object(readPrivateJson(this.path("intent")));
718
+ if (value.id !== this.id || value.owner !== this.records.owner || value.socket !== this.records.socket || value.unit !== runtimeUnit(this.id) || value.slice !== budgetSlice(this.records.owner))
719
+ throw new Error("foreign_launch_intent");
720
+ if (!/^\d+:\d+$/.test(text(value.controllerIdentity, "controller")))
721
+ throw new Error("invalid_launch_controller");
722
+ for (const field of ["groupId", "generation", "nonce"])
723
+ runtimeUnit(text(value[field], field));
724
+ if (value.role !== "main" && value.role !== "worker")
725
+ throw new Error("invalid_launch_role");
726
+ strings(value.argv, "argv");
727
+ text(value.cwd, "cwd");
728
+ text(value.runtime, "runtime");
729
+ text(value.createdAt, "created_at");
730
+ integer(value.memoryMb, "session_memory", 32, 1536);
731
+ if (value.resource !== void 0)
732
+ resourceClaim(value.resource, this.records.owner);
733
+ if (value.dockerCreation !== void 0) {
734
+ const creation = object(value.dockerCreation);
735
+ const config = object(creation.configuration);
736
+ const labels = object(config.Labels);
737
+ if (creation.egress !== void 0) egressPolicy(creation.egress);
738
+ const bridge = creation.egress === void 0 ? void 0 : egressPolicy(creation.egress).bridgeExecutable;
739
+ if (bridge && !/^[a-f0-9]{64}$/.test(String(creation.bridgeSha256)))
740
+ throw new Error("invalid_docker_bridge_digest");
741
+ if (!bridge && creation.bridgeSha256 !== void 0)
742
+ throw new Error("ungranted_docker_bridge_digest");
743
+ const policy = new GroupStore(join3(this.records.directory, "group.json")).state.group.dockerPolicy;
744
+ const profile = selectedProfile(
745
+ policy,
746
+ creation.privateProfile,
747
+ text(value.runtime, "runtime")
748
+ );
749
+ const expectedState = profile?.directory ?? join3(
750
+ this.records.directory,
751
+ "containers",
752
+ text(value.nonce, "nonce"),
753
+ "profile"
754
+ );
755
+ if (value.resource !== void 0 && object(value.resource).privateProfile !== creation.privateProfile)
756
+ throw new Error("launch_private_profile_mismatch");
757
+ if (creation.name !== containerName(this.records.owner, this.id) || creation.nonce !== value.nonce || creation.state !== expectedState || labels[containerLabels.owner] !== this.records.owner || labels[containerLabels.role] !== value.role || labels[containerLabels.nonce] !== value.nonce)
758
+ throw new Error("foreign_container_creation");
759
+ }
760
+ return value;
761
+ }
762
+ proof() {
763
+ const intent = this.intent();
764
+ const value = object(readPrivateJson(this.path("proof")));
765
+ const session = object(value.session);
766
+ if (value.nonce !== intent.nonce || session.id !== intent.id || session.owner !== intent.owner || session.socket !== intent.socket || session.unit !== intent.unit || session.cwd !== intent.cwd || session.memoryMb !== intent.memoryMb || session.runtime !== intent.runtime || session.createdAt !== intent.createdAt || JSON.stringify(session.resource) !== JSON.stringify(intent.resource))
767
+ throw new Error("foreign_launch_proof");
768
+ for (const [field, pattern] of [
769
+ ["paneId", /^%\d+$/],
770
+ ["windowId", /^@\d+$/],
771
+ ["tmuxSessionId", /^\$\d+$/],
772
+ ["serverIdentity", /^\d+:\d+$/]
773
+ ]) {
774
+ if (!pattern.test(text(session[field], field)))
775
+ throw new Error("invalid_launch_identity");
776
+ }
777
+ integer(session.panePid, "pane_process", 1, Number.MAX_SAFE_INTEGER);
778
+ if (!/^\d+:\d+$/.test(text(value.runnerIdentity, "runner")))
779
+ throw new Error("invalid_launch_runner");
780
+ return value;
781
+ }
782
+ grant() {
783
+ const intent = this.intent();
784
+ return {
785
+ id: intent.id,
786
+ owner: intent.owner,
787
+ groupId: intent.groupId,
788
+ generation: intent.generation,
789
+ nonce: intent.nonce,
790
+ proofDigest: createHash2("sha256").update(JSON.stringify(this.proof())).digest("hex")
791
+ };
792
+ }
793
+ assertRegistered() {
794
+ const intent = this.intent();
795
+ const group = new GroupStore(join3(this.records.directory, "group.json")).state.group;
796
+ if (group.id !== intent.groupId || group.generation !== intent.generation)
797
+ throw new Error("launch_group_generation_mismatch");
798
+ if (intent.dockerCreation && JSON.stringify(intent.dockerCreation.egress) !== JSON.stringify(group.dockerPolicy?.egress))
799
+ throw new Error("launch_egress_grant_mismatch");
800
+ if (group.state !== "ready" || !group.allowedRuntimes.includes(intent.runtime))
801
+ throw new Error("launch_group_not_ready");
802
+ if (!group.sessions.some(
803
+ (session) => session.id === intent.id && session.role === intent.role && !session.stopped
804
+ ))
805
+ throw new Error("launch_registration_missing");
806
+ const record = this.records.read(this.id);
807
+ if (JSON.stringify(record) !== JSON.stringify(this.proof().session))
808
+ throw new Error("launch_record_mismatch");
809
+ }
810
+ authorize() {
811
+ if (existsSync(this.path("aborted"))) throw new Error("launch_was_aborted");
812
+ this.assertRegistered();
813
+ privateJson(this.path("grant"), this.grant());
814
+ }
815
+ assertGrant() {
816
+ if (existsSync(this.path("aborted"))) throw new Error("launch_was_aborted");
817
+ const grant = object(readPrivateJson(this.path("grant")));
818
+ if (JSON.stringify(grant) !== JSON.stringify(this.grant()))
819
+ throw new Error("launch_grant_mismatch");
820
+ }
821
+ commit() {
822
+ this.assertRegistered();
823
+ this.assertGrant();
824
+ privateJson(this.path("committed"), this.grant());
825
+ }
826
+ assertCommitted() {
827
+ this.assertGrant();
828
+ const committed = object(readPrivateJson(this.path("committed")));
829
+ if (JSON.stringify(committed) !== JSON.stringify(this.grant()))
830
+ throw new Error("launch_commit_mismatch");
831
+ }
832
+ abortRecord() {
833
+ if (!existsSync(this.path("aborted"))) return;
834
+ const value = object(readPrivateJson(this.path("aborted")));
835
+ if (value.id !== this.id || value.owner !== this.records.owner || !["stopping", "stopped"].includes(String(value.state)))
836
+ throw new Error("foreign_launch_abort");
837
+ return value;
838
+ }
839
+ };
840
+ function launchJournals(records2) {
841
+ return readdirSync2(records2.directory).filter((name) => name.endsWith(".intent.json")).map((name) => new LaunchJournal(records2, name.slice(0, -12)));
842
+ }
843
+ function pendingLaunches(records2) {
844
+ return launchJournals(records2).filter((journal) => {
845
+ const aborted = journal.abortRecord();
846
+ if (aborted) return aborted.state !== "stopped";
847
+ if (!existsSync(journal.path("committed"))) return true;
848
+ journal.assertCommitted();
849
+ return false;
850
+ });
851
+ }
852
+
853
+ // src/harness/launch/recovery.ts
854
+ import { existsSync as existsSync3 } from "fs";
855
+
856
+ // src/harness/adapters/docker/lifecycle.ts
857
+ function stopResource(resource) {
858
+ let actual;
859
+ try {
860
+ actual = inspectResource(resource, false);
861
+ } catch (error) {
862
+ if (resourceAbsent(error, resource.id)) return;
863
+ throw error;
864
+ }
865
+ const state = object(actual.State);
866
+ if (state.Running === true)
867
+ command("docker", ["stop", "--timeout", "2", resource.id]);
868
+ if (object(inspectResource(resource, false).State).Running !== false)
869
+ throw new Error("container_stop_unconfirmed");
870
+ if (resource.managed) {
871
+ command("docker", ["rm", resource.id]);
872
+ try {
873
+ inspectResource(resource, false);
874
+ } catch (error) {
875
+ if (resourceAbsent(error, resource.id)) return;
876
+ throw error;
877
+ }
878
+ throw new Error("container_removal_unconfirmed");
879
+ }
880
+ }
881
+
882
+ // src/harness/adapters/docker/creation.ts
883
+ import { mkdirSync as mkdirSync2 } from "fs";
884
+ import { join as join9 } from "path";
885
+
886
+ // src/harness/adapters/docker/admission.ts
887
+ import { lstatSync as lstatSync5, realpathSync as realpathSync6 } from "fs";
888
+ import { join as join6, relative as relative3 } from "path";
889
+
890
+ // src/harness/adapters/docker/profile.ts
891
+ import { homedir as homedir3 } from "os";
892
+ import { lstatSync as lstatSync3, realpathSync as realpathSync4 } from "fs";
893
+ import { relative as relative2 } from "path";
894
+
895
+ // src/harness/adapters/docker/private-profile.ts
896
+ import { homedir as homedir2 } from "os";
897
+ import {
898
+ closeSync as closeSync2,
899
+ constants as constants2,
900
+ existsSync as existsSync2,
901
+ fstatSync as fstatSync2,
902
+ lstatSync as lstatSync2,
903
+ openSync as openSync2,
904
+ realpathSync as realpathSync3,
905
+ statfsSync
906
+ } from "fs";
907
+ import { join as join4, relative } from "path";
908
+ var privateProfileLock = "profile.lock";
909
+ function overlap(left, right) {
910
+ const scope = relative(left, right);
911
+ return scope === "" || scope !== ".." && !scope.startsWith("../");
912
+ }
913
+ function profileIdentity(directory, projectRoot) {
914
+ if (directory === "/" || directory === realpathSync3(homedir2()) || overlap(directory, projectRoot) || overlap(projectRoot, directory) || realpathSync3(directory) !== directory)
915
+ throw new Error("private_profile_scope_not_admitted");
916
+ const stat = lstatSync2(directory);
917
+ if (!stat.isDirectory() || stat.uid !== process.getuid?.() || (stat.mode & 511) !== 448)
918
+ throw new Error("unsafe_private_profile_directory");
919
+ if ([26985, 4283649346, 4266872130].includes(statfsSync(directory).type))
920
+ throw new Error("remote_private_profile_not_admitted");
921
+ const lock = openSync2(
922
+ join4(directory, privateProfileLock),
923
+ constants2.O_RDONLY | constants2.O_NOFOLLOW
924
+ );
925
+ try {
926
+ const value = fstatSync2(lock);
927
+ if (!value.isFile() || value.nlink !== 1 || value.uid !== process.getuid?.() || (value.mode & 511) !== 384)
928
+ throw new Error("unsafe_private_profile_lock");
929
+ return `${stat.dev}:${stat.ino}:${value.dev}:${value.ino}`;
930
+ } finally {
931
+ closeSync2(lock);
932
+ }
933
+ }
934
+ function assertProfileIdentity(grant, projectRoot) {
935
+ if (!grant.identity || profileIdentity(grant.directory, projectRoot) !== grant.identity)
936
+ throw new Error("private_profile_identity_changed");
937
+ }
938
+ function assertProfileAvailable(grant, projectRoot) {
939
+ assertProfileIdentity(grant, projectRoot);
940
+ try {
941
+ command("flock", [
942
+ "--exclusive",
943
+ "--nonblock",
944
+ "--conflict-exit-code",
945
+ "73",
946
+ join4(grant.directory, privateProfileLock),
947
+ "true"
948
+ ]);
949
+ } catch (error) {
950
+ if (error.status === 73)
951
+ throw new Error("private_profile_busy");
952
+ throw error;
953
+ }
954
+ }
955
+
956
+ // src/harness/adapters/docker/profile.ts
957
+ function assertLocalDocker() {
958
+ if (process.env.DOCKER_HOST)
959
+ throw new Error("explicit_docker_host_not_admitted");
960
+ const endpoint = JSON.parse(
961
+ command("docker", [
962
+ "context",
963
+ "inspect",
964
+ "--format",
965
+ "{{json .Endpoints.docker.Host}}"
966
+ ])
967
+ );
968
+ if (new URL(endpoint).protocol !== "unix:")
969
+ throw new Error("remote_docker_context_not_admitted");
970
+ }
971
+
972
+ // src/harness/adapters/docker/mounts.ts
973
+ import { lstatSync as lstatSync4, realpathSync as realpathSync5 } from "fs";
974
+ import { join as join5 } from "path";
975
+ function assertContainerMounts(actual, statePath, projectRoot, directory, nonce, policy, privateProfile, runtime) {
976
+ const state = text(statePath, "container_state_directory");
977
+ const profile = selectedProfile(policy, privateProfile, runtime ?? "");
978
+ if (profile) assertProfileIdentity(profile, projectRoot);
979
+ const expected = profile?.directory ?? join5(directory, "containers", nonce, "profile");
980
+ if (state !== expected || realpathSync5(state) !== expected)
981
+ throw new Error("foreign_container_state_directory");
982
+ const stat = lstatSync4(state);
983
+ if (!stat.isDirectory() || stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
984
+ throw new Error("unsafe_container_state_directory");
985
+ if (!Array.isArray(actual.Mounts) || actual.Mounts.length !== 2)
986
+ throw new Error("ungranted_container_mount");
987
+ if (new Set(actual.Mounts.map((value) => object(value).Destination)).size !== 2)
988
+ throw new Error("ungranted_container_mount");
989
+ const expectedMounts = [
990
+ {
991
+ Source: projectRoot,
992
+ Destination: "/workspace",
993
+ RW: policy.workspaceAccess === "read-write"
994
+ },
995
+ { Source: state, Destination: "/state", RW: true }
996
+ ];
997
+ for (const value of actual.Mounts) {
998
+ const mount = object(value);
999
+ if (mount.Type !== "bind" || mount.Propagation !== "rprivate" || !expectedMounts.some(
1000
+ (expected2) => mount.Source === expected2.Source && mount.Destination === expected2.Destination && mount.RW === expected2.RW
1001
+ ))
1002
+ throw new Error("ungranted_container_mount");
1003
+ }
1004
+ const host = object(actual.HostConfig);
1005
+ if (!Array.isArray(host.Mounts) || host.Mounts.length !== 2 || host.Mounts.some(
1006
+ (value) => object(object(value).BindOptions).NonRecursive !== true
1007
+ ))
1008
+ throw new Error("recursive_container_mount_not_admitted");
1009
+ }
1010
+
1011
+ // src/harness/adapters/docker/security.ts
1012
+ function assertContainerIsolation(host, network) {
1013
+ if (host.ReadonlyRootfs !== true || host.Privileged !== false || host.NetworkMode !== network || host.CgroupnsMode !== "private")
1014
+ throw new Error("invalid_container_isolation_policy");
1015
+ if (JSON.stringify(host.CapDrop) !== '["ALL"]' || JSON.stringify(host.SecurityOpt) !== '["no-new-privileges"]' || object(host.RestartPolicy).Name !== "no")
1016
+ throw new Error("invalid_container_execution_policy");
1017
+ if (host.CapAdd !== null || host.PidMode !== "" || host.UTSMode !== "" || host.UsernsMode !== "" || host.CgroupParent !== "" || host.IpcMode !== "private" || hasDevices(host.Devices) || hasDevices(host.DeviceRequests) || host.AutoRemove !== false || host.VolumesFrom !== null || host.GroupAdd !== null || host.Binds !== null || Object.keys(object(host.PortBindings)).length)
1018
+ throw new Error("ungranted_container_host_authority");
1019
+ }
1020
+ function hasDevices(value) {
1021
+ if (value === null) return false;
1022
+ return !Array.isArray(value) || value.length !== 0;
1023
+ }
1024
+
1025
+ // src/harness/adapters/docker/entrypoint.ts
1026
+ function bridgeName(nonce) {
1027
+ return `.pmcp-egress-${nonce.slice(0, 8)}.mjs`;
1028
+ }
1029
+ function containerEntrypoint(policy, runtime, nonce, privateProfile) {
1030
+ const native = policy.commands[runtime];
1031
+ if (!native) throw new Error("docker_runtime_command_not_granted");
1032
+ const command2 = policy.egress?.bridgeExecutable ? [
1033
+ policy.egress.bridgeExecutable,
1034
+ `/state/${bridgeName(nonce)}`,
1035
+ "--",
1036
+ ...native
1037
+ ] : native;
1038
+ const profile = selectedProfile(policy, privateProfile, runtime);
1039
+ if (!profile) return command2;
1040
+ return [
1041
+ profile.lockExecutable,
1042
+ "--exclusive",
1043
+ "--nonblock",
1044
+ "--close",
1045
+ "--conflict-exit-code",
1046
+ "73",
1047
+ `/state/${privateProfileLock}`,
1048
+ ...command2
1049
+ ];
1050
+ }
1051
+
1052
+ // src/harness/adapters/docker/admission.ts
1053
+ function admitResource(path, group, role, directory, memoryMb, runtime) {
1054
+ if (group.profile !== "docker" || !group.dockerPolicy)
1055
+ throw new Error("container_requires_docker_profile");
1056
+ const { projectRoot } = group;
1057
+ assertLocalDocker();
1058
+ const inputPath = text(path, "container_file");
1059
+ if (lstatSync5(inputPath).isSymbolicLink())
1060
+ throw new Error("symlink_container_file_not_admitted");
1061
+ const source2 = realpathSync6(inputPath);
1062
+ const scope = relative3(projectRoot, source2);
1063
+ if (scope === ".." || scope.startsWith("../"))
1064
+ throw new Error("container_file_outside_project");
1065
+ const claim = object(readPrivateJson(source2));
1066
+ if (claim.privateProfile !== void 0)
1067
+ throw new Error("private_profile_requires_cli_owned_creation");
1068
+ return admitClaim(claim, group, role, directory, memoryMb, runtime);
1069
+ }
1070
+ function admitClaim(value, group, role, directory, memoryMb, runtime, cwd = group.projectRoot) {
1071
+ if (group.profile !== "docker" || !group.dockerPolicy)
1072
+ throw new Error("container_requires_docker_profile");
1073
+ assertLocalDocker();
1074
+ const policy = group.dockerPolicy;
1075
+ const { owner, projectRoot } = group;
1076
+ const claim = object(value);
1077
+ if (claim.owner !== owner || claim.role !== role || claim.runtime !== runtime)
1078
+ throw new Error("foreign_container_resource");
1079
+ const resource = {
1080
+ kind: "docker",
1081
+ id: text(claim.id, "container_id"),
1082
+ owner,
1083
+ nonce: text(claim.nonce, "container_nonce"),
1084
+ role,
1085
+ image: text(claim.image, "container_image"),
1086
+ configurationDigest: "",
1087
+ memoryMb: 0,
1088
+ cpuQuota: 0,
1089
+ ...claim.privateProfile === void 0 ? {} : { privateProfile: profileName(claim.privateProfile) }
1090
+ };
1091
+ if (!/^[a-f0-9]{64}$/.test(resource.id) || !/^sha256:[a-f0-9]{64}$/.test(resource.image) || !/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(
1092
+ resource.nonce
1093
+ ))
1094
+ throw new Error("invalid_container_resource");
1095
+ const actual = inspectResource(resource, false);
1096
+ const state = object(actual.State);
1097
+ const config = object(actual.Config);
1098
+ const host = object(actual.HostConfig);
1099
+ if (resource.image !== policy.image || JSON.stringify(config.Entrypoint) !== JSON.stringify(
1100
+ containerEntrypoint(
1101
+ policy,
1102
+ runtime,
1103
+ resource.nonce,
1104
+ resource.privateProfile
1105
+ )
1106
+ ))
1107
+ throw new Error("container_runtime_image_not_granted");
1108
+ if (config.WorkingDir !== join6("/workspace", relative3(projectRoot, cwd)))
1109
+ throw new Error("container_cwd_not_granted");
1110
+ assertContainerMounts(
1111
+ actual,
1112
+ claim.state,
1113
+ projectRoot,
1114
+ directory,
1115
+ resource.nonce,
1116
+ policy,
1117
+ resource.privateProfile,
1118
+ runtime
1119
+ );
1120
+ if (state.Status !== "created" || state.Pid !== 0 || state.Running !== false)
1121
+ throw new Error("container_requires_fresh_creation");
1122
+ if (config.User !== `${process.getuid?.()}:${process.getgid?.()}` || config.Tty !== true || config.OpenStdin !== true || config.StdinOnce !== false || !Array.isArray(config.Env) || JSON.stringify(
1123
+ config.Env.filter(
1124
+ (value2) => typeof value2 === "string" && value2.startsWith("HOME=")
1125
+ )
1126
+ ) !== '["HOME=/state"]')
1127
+ throw new Error("invalid_container_terminal_policy");
1128
+ assertContainerIsolation(host, policy.network);
1129
+ resource.memoryMb = integer(
1130
+ Number(host.Memory) / 1048576,
1131
+ "container_memory",
1132
+ 32,
1133
+ 1472
1134
+ );
1135
+ if (host.MemorySwap !== host.Memory || memoryMb - resource.memoryMb < 64)
1136
+ throw new Error("container_proxy_memory_unreserved");
1137
+ integer(host.PidsLimit, "container_tasks", 1, 128);
1138
+ if (host.CpuPeriod !== 1e5)
1139
+ throw new Error("invalid_container_cpu_period");
1140
+ resource.cpuQuota = integer(host.CpuQuota, "container_cpu", 1, 5e4);
1141
+ resource.configurationDigest = configurationDigest(actual);
1142
+ return resource;
1143
+ }
1144
+
1145
+ // src/harness/adapters/docker/engine.ts
1146
+ import { request } from "http";
1147
+ var DockerEngine = class {
1148
+ async create(name, configuration) {
1149
+ assertLocalDocker();
1150
+ const endpoint = JSON.parse(
1151
+ command("docker", [
1152
+ "context",
1153
+ "inspect",
1154
+ "--format",
1155
+ "{{json .Endpoints.docker.Host}}"
1156
+ ])
1157
+ );
1158
+ const version = command("docker", [
1159
+ "version",
1160
+ "--format",
1161
+ "{{.Server.APIVersion}}"
1162
+ ]).trim();
1163
+ if (!/^1\.\d+$/.test(version))
1164
+ throw new Error("invalid_docker_api_version");
1165
+ const payload = JSON.stringify(configuration);
1166
+ return new Promise((resolve2, reject) => {
1167
+ const req = request(
1168
+ {
1169
+ socketPath: new URL(endpoint).pathname,
1170
+ path: `/v${version}/containers/create?name=${encodeURIComponent(name)}`,
1171
+ method: "POST",
1172
+ headers: {
1173
+ "Content-Type": "application/json",
1174
+ "Content-Length": Buffer.byteLength(payload)
1175
+ }
1176
+ },
1177
+ (response) => {
1178
+ const chunks = [];
1179
+ let bytes = 0;
1180
+ response.on("data", (chunk) => {
1181
+ bytes += chunk.length;
1182
+ if (bytes > 65536) {
1183
+ req.destroy(new Error("docker_response_too_large"));
1184
+ return;
1185
+ }
1186
+ chunks.push(chunk);
1187
+ });
1188
+ response.once("error", reject);
1189
+ response.once("end", () => {
1190
+ if (response.statusCode !== 201) {
1191
+ reject(new Error(`docker_create_status_${response.statusCode}`));
1192
+ return;
1193
+ }
1194
+ try {
1195
+ const id2 = text(
1196
+ object(JSON.parse(Buffer.concat(chunks).toString("utf8"))).Id,
1197
+ "container_id"
1198
+ );
1199
+ if (!/^[a-f0-9]{64}$/.test(id2))
1200
+ throw new Error("invalid_container_id");
1201
+ resolve2(id2);
1202
+ } catch (error) {
1203
+ reject(error);
1204
+ }
1205
+ });
1206
+ }
1207
+ );
1208
+ req.setTimeout(
1209
+ 1e4,
1210
+ () => req.destroy(new Error("docker_create_timeout"))
1211
+ );
1212
+ req.once("error", reject);
1213
+ req.end(payload);
1214
+ });
1215
+ }
1216
+ };
1217
+
1218
+ // src/harness/adapters/docker/creation-plan.ts
1219
+ import { join as join8, relative as relative4 } from "path";
1220
+
1221
+ // src/harness/adapters/docker/bridge-artifact.ts
1222
+ import { createHash as createHash3 } from "crypto";
1223
+ import {
1224
+ closeSync as closeSync3,
1225
+ constants as constants3,
1226
+ fstatSync as fstatSync3,
1227
+ fsyncSync as fsyncSync2,
1228
+ openSync as openSync3,
1229
+ readFileSync as readFileSync3,
1230
+ writeFileSync as writeFileSync3
1231
+ } from "fs";
1232
+ import { join as join7 } from "path";
1233
+ function source() {
1234
+ const path = artifact("egress-bridge");
1235
+ if (!path.endsWith(".js"))
1236
+ throw new Error("docker_bridge_requires_compiled_cli");
1237
+ return readFileSync3(path);
1238
+ }
1239
+ function digest(value) {
1240
+ return createHash3("sha256").update(value).digest("hex");
1241
+ }
1242
+ function bridgeDigest() {
1243
+ return digest(source());
1244
+ }
1245
+ function prepareBridge(creation) {
1246
+ if (!creation.egress?.bridgeExecutable) return;
1247
+ const content = source();
1248
+ if (digest(content) !== creation.bridgeSha256)
1249
+ throw new Error("docker_bridge_source_changed");
1250
+ const descriptor = openSync3(
1251
+ join7(creation.state, bridgeName(creation.nonce)),
1252
+ "wx",
1253
+ 384
1254
+ );
1255
+ try {
1256
+ writeFileSync3(descriptor, content);
1257
+ fsyncSync2(descriptor);
1258
+ } finally {
1259
+ closeSync3(descriptor);
1260
+ }
1261
+ }
1262
+ function assertBridge(creation) {
1263
+ if (!creation.egress?.bridgeExecutable) return;
1264
+ const descriptor = openSync3(
1265
+ join7(creation.state, bridgeName(creation.nonce)),
1266
+ constants3.O_RDONLY | constants3.O_NOFOLLOW
1267
+ );
1268
+ try {
1269
+ const stat = fstatSync3(descriptor);
1270
+ if (!stat.isFile() || stat.uid !== process.getuid?.() || stat.nlink !== 1 || (stat.mode & 63) !== 0 || stat.size > 2097152 || digest(readFileSync3(descriptor)) !== creation.bridgeSha256)
1271
+ throw new Error("docker_bridge_artifact_changed");
1272
+ } finally {
1273
+ closeSync3(descriptor);
1274
+ }
1275
+ }
1276
+
1277
+ // src/harness/adapters/docker/creation-plan.ts
1278
+ function creationPlan(group, directory, id2, nonce, role, runtime, cwd, preparation) {
1279
+ if (group.profile !== "docker" || !group.dockerPolicy)
1280
+ throw new Error("container_requires_docker_profile");
1281
+ assertLocalDocker();
1282
+ const policy = group.dockerPolicy;
1283
+ const images = JSON.parse(
1284
+ command("docker", ["image", "inspect", policy.image])
1285
+ );
1286
+ if (!Array.isArray(images) || images.length !== 1 || object(images[0]).Id !== policy.image)
1287
+ throw new Error("docker_image_not_available");
1288
+ const imageConfig = object(object(images[0]).Config);
1289
+ const environment = imageConfig.Env;
1290
+ if (!Array.isArray(environment) || environment.some((entry) => typeof entry !== "string"))
1291
+ throw new Error("invalid_container_image_environment");
1292
+ const profile = selectedProfile(policy, preparation.privateProfile, runtime);
1293
+ if (profile) assertProfileAvailable(profile, group.projectRoot);
1294
+ const state = profile?.directory ?? join8(directory, "containers", nonce, "profile");
1295
+ return {
1296
+ name: containerName(group.owner, id2),
1297
+ nonce,
1298
+ state,
1299
+ ...preparation.privateProfile ? { privateProfile: preparation.privateProfile } : {},
1300
+ ...policy.egress ? { egress: policy.egress } : {},
1301
+ ...policy.egress?.bridgeExecutable ? { bridgeSha256: bridgeDigest() } : {},
1302
+ configuration: {
1303
+ Image: policy.image,
1304
+ Entrypoint: containerEntrypoint(
1305
+ policy,
1306
+ runtime,
1307
+ nonce,
1308
+ preparation.privateProfile
1309
+ ),
1310
+ Cmd: preparation.args.length ? preparation.args : null,
1311
+ WorkingDir: join8("/workspace", relative4(group.projectRoot, cwd)),
1312
+ User: `${process.getuid?.()}:${process.getgid?.()}`,
1313
+ Env: [
1314
+ ...environment.filter(
1315
+ (entry) => !/^(HOME|TERM|PMCP_HTTPS_PROXY_SOCKET)=/.test(entry)
1316
+ ),
1317
+ "HOME=/state",
1318
+ "TERM=xterm-256color",
1319
+ ...policy.egress ? [`PMCP_HTTPS_PROXY_SOCKET=/state/e${nonce.slice(0, 8)}`] : []
1320
+ ],
1321
+ Tty: true,
1322
+ OpenStdin: true,
1323
+ StdinOnce: false,
1324
+ AttachStdin: false,
1325
+ AttachStdout: true,
1326
+ AttachStderr: true,
1327
+ Labels: {
1328
+ ...imageConfig.Labels ?? {},
1329
+ [containerLabels.owner]: group.owner,
1330
+ [containerLabels.nonce]: nonce,
1331
+ [containerLabels.role]: role
1332
+ },
1333
+ HostConfig: {
1334
+ NetworkMode: policy.network,
1335
+ CgroupnsMode: "private",
1336
+ ReadonlyRootfs: true,
1337
+ CapDrop: ["ALL"],
1338
+ SecurityOpt: ["no-new-privileges"],
1339
+ Memory: preparation.memoryMb * 1048576,
1340
+ MemorySwap: preparation.memoryMb * 1048576,
1341
+ PidsLimit: 64,
1342
+ CpuPeriod: 1e5,
1343
+ CpuQuota: preparation.cpuQuota,
1344
+ RestartPolicy: { Name: "no" },
1345
+ LogConfig: { Type: "none" },
1346
+ Tmpfs: { "/tmp": "rw,nosuid,noexec,size=16m" },
1347
+ Mounts: [
1348
+ {
1349
+ Type: "bind",
1350
+ Source: group.projectRoot,
1351
+ Target: "/workspace",
1352
+ ...policy.workspaceAccess === "read-only" ? { ReadOnly: true } : {},
1353
+ BindOptions: { NonRecursive: true }
1354
+ },
1355
+ {
1356
+ Type: "bind",
1357
+ Source: state,
1358
+ Target: "/state",
1359
+ BindOptions: { NonRecursive: true }
1360
+ }
1361
+ ]
1362
+ }
1363
+ }
1364
+ };
1365
+ }
1366
+ function assertCreationConfiguration(actual, creation) {
1367
+ if (actual.Name !== `/${creation.name}`)
1368
+ throw new Error("foreign_container_creation");
1369
+ const expected = creation.configuration;
1370
+ const config = object(actual.Config);
1371
+ const host = object(actual.HostConfig);
1372
+ for (const [key, value] of Object.entries(expected)) {
1373
+ if (key === "HostConfig" || key === "Image") continue;
1374
+ if (!matchesFields(config[key], value))
1375
+ throw new Error(`container_creation_configuration_changed_${key}`);
1376
+ }
1377
+ for (const [key, value] of Object.entries(object(expected.HostConfig))) {
1378
+ if (!matchesFields(host[key], value))
1379
+ throw new Error(`container_creation_configuration_changed_${key}`);
1380
+ }
1381
+ }
1382
+ function matchesFields(actual, expected) {
1383
+ if (Array.isArray(expected))
1384
+ return Array.isArray(actual) && actual.length === expected.length && expected.every((value2, index) => matchesFields(actual[index], value2));
1385
+ if (expected === null || typeof expected !== "object")
1386
+ return actual === expected;
1387
+ if (actual === null || typeof actual !== "object" || Array.isArray(actual))
1388
+ return false;
1389
+ const value = actual;
1390
+ return Object.entries(expected).every(
1391
+ ([key, field]) => matchesFields(value[key], field)
1392
+ );
1393
+ }
1394
+
1395
+ // src/harness/adapters/docker/creation.ts
1396
+ async function prepareCreation(journal) {
1397
+ const intent = journal.intent();
1398
+ const creation = intent.dockerCreation;
1399
+ if (!creation) throw new Error("container_creation_missing");
1400
+ const group = new GroupStore(join9(journal.records.directory, "group.json")).state.group;
1401
+ const profile = selectedProfile(
1402
+ group.dockerPolicy,
1403
+ creation.privateProfile,
1404
+ intent.runtime
1405
+ );
1406
+ if (profile) assertProfileAvailable(profile, group.projectRoot);
1407
+ if (!profile) mkdirSync2(creation.state, { recursive: true, mode: 448 });
1408
+ prepareBridge(creation);
1409
+ assertBridge(creation);
1410
+ const id2 = await new DockerEngine().create(
1411
+ creation.name,
1412
+ creation.configuration
1413
+ );
1414
+ const current = new GroupStore(join9(journal.records.directory, "group.json")).state.group;
1415
+ if (current.id !== intent.groupId || current.generation !== intent.generation)
1416
+ throw new Error("launch_group_generation_mismatch");
1417
+ const resource = {
1418
+ ...admitClaim(
1419
+ {
1420
+ id: id2,
1421
+ owner: intent.owner,
1422
+ role: intent.role,
1423
+ runtime: intent.runtime,
1424
+ image: current.dockerPolicy?.image,
1425
+ nonce: creation.nonce,
1426
+ state: creation.state,
1427
+ ...creation.privateProfile ? { privateProfile: creation.privateProfile } : {}
1428
+ },
1429
+ current,
1430
+ intent.role,
1431
+ journal.records.directory,
1432
+ intent.memoryMb,
1433
+ intent.runtime,
1434
+ intent.cwd
1435
+ ),
1436
+ managed: true
1437
+ };
1438
+ assertCreationConfiguration(
1439
+ object(JSON.parse(command("docker", ["inspect", id2]))[0]),
1440
+ creation
1441
+ );
1442
+ privateJson(journal.path("intent"), {
1443
+ ...intent,
1444
+ resource,
1445
+ argv: [intent.argv[0], "start", "--attach", "--interactive", id2]
1446
+ });
1447
+ return resource;
1448
+ }
1449
+ function findCreation(journal) {
1450
+ const intent = journal.intent();
1451
+ const creation = intent.dockerCreation;
1452
+ if (!creation) return intent.resource;
1453
+ assertLocalDocker();
1454
+ let actual;
1455
+ try {
1456
+ const values = JSON.parse(
1457
+ command("docker", ["inspect", creation.name])
1458
+ );
1459
+ if (!Array.isArray(values) || values.length !== 1)
1460
+ throw new Error("invalid_container_inspection");
1461
+ actual = object(values[0]);
1462
+ } catch (error) {
1463
+ if (resourceAbsent(error, creation.name)) return;
1464
+ throw error;
1465
+ }
1466
+ const resource = {
1467
+ kind: "docker",
1468
+ id: text(actual.Id, "container_id"),
1469
+ owner: intent.owner,
1470
+ nonce: creation.nonce,
1471
+ role: intent.role,
1472
+ image: text(creation.configuration.Image, "container_image"),
1473
+ configurationDigest: configurationDigest(actual),
1474
+ memoryMb: Number(object(actual.HostConfig).Memory) / 1048576,
1475
+ cpuQuota: Number(object(actual.HostConfig).CpuQuota),
1476
+ managed: true,
1477
+ ...creation.privateProfile ? { privateProfile: creation.privateProfile } : {}
1478
+ };
1479
+ assertResourceOwner(resource, actual);
1480
+ assertCreationConfiguration(actual, creation);
1481
+ if (!intent.resource) {
1482
+ const group = new GroupStore(join9(journal.records.directory, "group.json")).state.group;
1483
+ return {
1484
+ ...admitClaim(
1485
+ { ...resource, runtime: intent.runtime, state: creation.state },
1486
+ group,
1487
+ intent.role,
1488
+ journal.records.directory,
1489
+ intent.memoryMb,
1490
+ intent.runtime,
1491
+ intent.cwd
1492
+ ),
1493
+ managed: true
1494
+ };
1495
+ }
1496
+ if (intent.resource && (resource.id !== intent.resource.id || resource.configurationDigest !== intent.resource.configurationDigest))
1497
+ throw new Error("container_creation_configuration_changed");
1498
+ return resource;
1499
+ }
1500
+
1501
+ // src/harness/launch/recovery.ts
1502
+ function abortLaunch(connection, journal) {
1503
+ const intent = journal.intent();
1504
+ if (!controllerExited(intent.controllerIdentity))
1505
+ throw new Error("launch_controller_alive");
1506
+ const previous = journal.abortRecord();
1507
+ const resource = intent.dockerCreation ? findCreation(journal) : intent.resource;
1508
+ if (previous?.state === "stopped") {
1509
+ if (resource) stopResource(resource);
1510
+ if (unitActive(intent.unit)) throw new Error("runtime_stop_unconfirmed");
1511
+ return {
1512
+ stopped: true,
1513
+ alreadyStopped: true,
1514
+ adopted: false,
1515
+ inputReplayed: false
1516
+ };
1517
+ }
1518
+ if (!existsSync3(journal.path("proof"))) {
1519
+ const paneUnknown = connection.alive() && (!intent.dockerCreation || connection.tmux(["list-sessions", "-F", "#{session_name}"]).trim().split("\n").includes(`pmcp-${intent.id}`));
1520
+ if (paneUnknown || unitActive(intent.unit))
1521
+ throw new Error("launch_identity_unknown");
1522
+ if (resource) stopResource(resource);
1523
+ privateJson(journal.path("aborted"), {
1524
+ id: intent.id,
1525
+ owner: intent.owner,
1526
+ state: "stopped",
1527
+ noRuntimeBorn: true
1528
+ });
1529
+ return { stopped: true, adopted: false, inputReplayed: false };
1530
+ }
1531
+ const proof = journal.proof();
1532
+ const present = panePresent(connection, proof);
1533
+ if (present) assertProof(connection, proof);
1534
+ if (resource) stopResource(resource);
1535
+ privateJson(journal.path("aborted"), {
1536
+ id: intent.id,
1537
+ owner: intent.owner,
1538
+ state: "stopping"
1539
+ });
1540
+ stopUnit(intent.unit);
1541
+ if (present) {
1542
+ assertProof(connection, proof);
1543
+ connection.tmux(["kill-pane", "-t", proof.session.paneId]);
1544
+ }
1545
+ if (existsSync3(journal.records.path(intent.id)))
1546
+ journal.records.save({
1547
+ ...proof.session,
1548
+ stoppedAt: (/* @__PURE__ */ new Date()).toISOString()
1549
+ });
1550
+ privateJson(journal.path("aborted"), {
1551
+ id: intent.id,
1552
+ owner: intent.owner,
1553
+ state: "stopped"
1554
+ });
1555
+ return { stopped: true, adopted: false, inputReplayed: false };
1556
+ }
1557
+
1558
+ // src/harness/adapters/tmux/lifecycle.ts
1559
+ async function start(connection, spec) {
1560
+ const records2 = connection.records;
1561
+ if (spec.budgetSlice !== budgetSlice(records2.owner))
1562
+ throw new Error("foreign_budget_slice");
1563
+ integer(spec.memoryMb, "session_memory", 32, 1536);
1564
+ runtimeUnit(spec.groupId);
1565
+ runtimeUnit(spec.generation);
1566
+ if (spec.role !== "main" && spec.role !== "worker")
1567
+ throw new Error("invalid_launch_role");
1568
+ const id2 = randomUUID3();
1569
+ const nonce = randomUUID3();
1570
+ const journal = new LaunchJournal(records2, id2);
1571
+ const dockerCreation = spec.dockerPreparation ? creationPlan(
1572
+ new GroupStore(join10(records2.directory, "group.json")).state.group,
1573
+ records2.directory,
1574
+ id2,
1575
+ nonce,
1576
+ spec.role,
1577
+ spec.runtime,
1578
+ spec.cwd,
1579
+ spec.dockerPreparation
1580
+ ) : void 0;
1581
+ privateJson(journal.path("intent"), {
1582
+ id: id2,
1583
+ owner: records2.owner,
1584
+ controllerIdentity: processIdentity(process.pid),
1585
+ groupId: spec.groupId,
1586
+ generation: spec.generation,
1587
+ role: spec.role,
1588
+ nonce,
1589
+ unit: runtimeUnit(id2),
1590
+ slice: spec.budgetSlice,
1591
+ socket: records2.socket,
1592
+ runtime: spec.runtime,
1593
+ memoryMb: spec.memoryMb,
1594
+ argv: spec.argv,
1595
+ cwd: spec.cwd,
1596
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1597
+ ...spec.resource ? { resource: spec.resource } : {},
1598
+ ...dockerCreation ? { dockerCreation } : {}
1599
+ });
1600
+ if (dockerCreation) await prepareCreation(journal);
1601
+ const intent = journal.intent();
1602
+ const argv = [
1603
+ "systemd-run",
1604
+ "--user",
1605
+ "--scope",
1606
+ "--collect",
1607
+ "--quiet",
1608
+ `--unit=${intent.unit}`,
1609
+ `--slice=${intent.slice}`,
1610
+ `--property=MemoryMax=${spec.memoryMb - (intent.resource?.memoryMb ?? 0)}M`,
1611
+ "--property=TasksMax=128",
1612
+ "--property=CPUQuota=100%",
1613
+ process.execPath,
1614
+ artifact("launch-gate"),
1615
+ records2.directory,
1616
+ id2
1617
+ ];
1618
+ connection.tmux([
1619
+ "new-session",
1620
+ "-d",
1621
+ "-x",
1622
+ "160",
1623
+ "-y",
1624
+ "42",
1625
+ "-s",
1626
+ `pmcp-${id2}`,
1627
+ "-c",
1628
+ spec.cwd,
1629
+ `exec ${argv.map(quote).join(" ")}`
1630
+ ]);
1631
+ const deadline = Date.now() + 5e3;
1632
+ while (!existsSync4(journal.path("proof"))) {
1633
+ if (Date.now() >= deadline) throw new Error("launch_proof_timeout");
1634
+ await setTimeout(25);
1635
+ }
1636
+ const proof = journal.proof();
1637
+ assertProof(connection, proof);
1638
+ records2.save(proof.session);
1639
+ return proof.session;
1640
+ }
1641
+ function stop(connection, id2) {
1642
+ const journal = new LaunchJournal(connection.records, id2);
1643
+ if (existsSync4(journal.path("intent"))) {
1644
+ abortLaunch(connection, journal);
1645
+ return;
1646
+ }
1647
+ const record = connection.inspect(id2);
1648
+ if (record.resource) stopResource(record.resource);
1649
+ stopUnit(record.unit);
1650
+ connection.inspect(id2);
1651
+ connection.tmux(["kill-pane", "-t", record.paneId]);
1652
+ connection.records.save({ ...record, stoppedAt: (/* @__PURE__ */ new Date()).toISOString() });
1653
+ }
1654
+ function cleanup(connection) {
1655
+ for (const journal of pendingLaunches(connection.records))
1656
+ abortLaunch(connection, journal);
1657
+ const records2 = connection.records.all();
1658
+ if (connection.alive()) {
1659
+ const panes = connection.tmux(["list-panes", "-a", "-F", "#{@pmcp-owner}|#{@pmcp-session}"]).trim().split("\n");
1660
+ if (panes.some(
1661
+ (pane) => !records2.some((record) => pane === `${record.owner}|${record.id}`)
1662
+ ))
1663
+ throw new Error("cleanup_foreign_pane");
1664
+ for (const record of records2) {
1665
+ if (!record.stoppedAt) connection.inspect(record.id);
1666
+ }
1667
+ }
1668
+ for (const record of records2) {
1669
+ if (record.resource) stopResource(record.resource);
1670
+ if (record.stoppedAt || !existsSync4(
1671
+ new LaunchJournal(connection.records, record.id).path("intent")
1672
+ )) {
1673
+ stopUnit(record.unit);
1674
+ continue;
1675
+ }
1676
+ stop(connection, record.id);
1677
+ }
1678
+ if (connection.alive()) connection.tmux(["kill-server"]);
1679
+ }
1680
+
1681
+ // src/harness/adapters/tmux/input.ts
1682
+ import { randomUUID as randomUUID4 } from "crypto";
1683
+ import { closeSync as closeSync4, openSync as openSync4, unlinkSync, writeFileSync as writeFileSync4 } from "fs";
1684
+ import { join as join11 } from "path";
1685
+ function validateText(text3) {
1686
+ if (typeof text3 !== "string" || Buffer.byteLength(text3) > 16384)
1687
+ throw new Error("invalid_text");
1688
+ if (/[\x00-\x08\x0b-\x1f\x7f]/.test(text3))
1689
+ throw new Error("control_character_rejected");
1690
+ if (/[\r\n\t]/.test(text3))
1691
+ throw new Error("unqualified_terminal_control_input");
1692
+ }
1693
+ function guarded(connection, session, args) {
1694
+ const owner = `#{==:#{@pmcp-owner},${session.owner}}`;
1695
+ const identity = `#{==:#{@pmcp-session},${session.id}}`;
1696
+ const process2 = `#{==:#{pane_pid},${session.panePid}}`;
1697
+ const alive = "#{==:#{pane_dead},0}";
1698
+ const condition = `#{&&:${owner},#{&&:${identity},#{&&:${process2},${alive}}}}`;
1699
+ const output = connection.tmux([
1700
+ "if-shell",
1701
+ "-F",
1702
+ "-t",
1703
+ session.paneId,
1704
+ condition,
1705
+ args.map(quote).join(" "),
1706
+ "display-message -p delivery_uncertain"
1707
+ ]);
1708
+ if (output.includes("delivery_uncertain"))
1709
+ throw new Error("delivery_uncertain");
1710
+ }
1711
+ function write(connection, id2, text3, submit) {
1712
+ validateText(text3);
1713
+ const session = connection.inspect(id2);
1714
+ if (!session.alive) throw new Error("runtime_exited");
1715
+ const lock = join11(connection.records.directory, `${id2}.input.lock`);
1716
+ const descriptor = openSync4(lock, "wx", 384);
1717
+ const buffer = `pmcp-${randomUUID4()}`;
1718
+ try {
1719
+ writeFileSync4(
1720
+ descriptor,
1721
+ JSON.stringify({ id: id2, controller: processIdentity(process.pid) })
1722
+ );
1723
+ if (text3.length > 0) {
1724
+ connection.tmux(["load-buffer", "-b", buffer, "-"], { input: text3 });
1725
+ connection.inspect(id2);
1726
+ guarded(connection, session, [
1727
+ "paste-buffer",
1728
+ "-d",
1729
+ "-p",
1730
+ "-r",
1731
+ "-b",
1732
+ buffer,
1733
+ "-t",
1734
+ session.paneId
1735
+ ]);
1736
+ }
1737
+ if (submit) {
1738
+ connection.inspect(id2);
1739
+ guarded(connection, session, [
1740
+ "send-keys",
1741
+ "-t",
1742
+ session.paneId,
1743
+ "Enter"
1744
+ ]);
1745
+ }
1746
+ return {
1747
+ id: id2,
1748
+ verdict: "input_written",
1749
+ submitted: submit,
1750
+ processingConfirmed: false
1751
+ };
1752
+ } finally {
1753
+ try {
1754
+ connection.tmux(["delete-buffer", "-b", buffer]);
1755
+ } catch {
1756
+ }
1757
+ closeSync4(descriptor);
1758
+ unlinkSync(lock);
1759
+ }
1760
+ }
1761
+ function interrupt(connection, id2) {
1762
+ const session = connection.inspect(id2);
1763
+ if (!session.alive) throw new Error("runtime_exited");
1764
+ guarded(connection, session, ["send-keys", "-t", session.paneId, "C-c"]);
1765
+ }
1766
+
1767
+ // src/harness/adapters/tmux/read.ts
1768
+ function read(connection, id2, options = {}) {
1769
+ const lines = integer(options.lines ?? 100, "lines", 1, 2e3);
1770
+ const maxBytes = integer(options.maxBytes ?? 16384, "max_bytes", 1, 65536);
1771
+ const session = connection.inspect(id2);
1772
+ const flags = options.alternate === true ? ["-a"] : ["-S", `-${lines}`];
1773
+ const output = connection.tmux([
1774
+ "capture-pane",
1775
+ "-p",
1776
+ "-J",
1777
+ "-t",
1778
+ session.paneId,
1779
+ ...flags
1780
+ ]);
1781
+ const bytes = Buffer.from(output);
1782
+ const truncated = bytes.length > maxBytes;
1783
+ const content = truncated ? bytes.subarray(bytes.length - maxBytes).toString("utf8").replace(/^\uFFFD+/, "") : output;
1784
+ return { content, source: "terminal-screen", truncated };
1785
+ }
1786
+
1787
+ // src/harness/adapters/tmux/backend.ts
1788
+ var Backend = class {
1789
+ constructor(recordStore) {
1790
+ this.recordStore = recordStore;
1791
+ this.connection = new Connection(recordStore);
1792
+ this.owner = recordStore.owner;
1793
+ this.socket = recordStore.socket;
1794
+ this.runDirectory = recordStore.directory;
1795
+ this.metadataPath = recordStore.metadataPath;
1796
+ }
1797
+ recordStore;
1798
+ connection;
1799
+ owner;
1800
+ socket;
1801
+ runDirectory;
1802
+ metadataPath;
1803
+ records() {
1804
+ return this.recordStore.all();
1805
+ }
1806
+ start(spec) {
1807
+ return start(this.connection, spec);
1808
+ }
1809
+ inspect(id2) {
1810
+ return this.connection.inspect(id2);
1811
+ }
1812
+ read(id2, options) {
1813
+ return read(this.connection, id2, options);
1814
+ }
1815
+ validateText(text3) {
1816
+ validateText(text3);
1817
+ }
1818
+ write(id2, text3, options = {}) {
1819
+ return write(this.connection, id2, text3, options.submit === true);
1820
+ }
1821
+ interrupt(id2) {
1822
+ interrupt(this.connection, id2);
1823
+ }
1824
+ stop(id2) {
1825
+ stop(this.connection, id2);
1826
+ }
1827
+ cleanup() {
1828
+ cleanup(this.connection);
1829
+ }
1830
+ tmux(args) {
1831
+ return this.connection.tmux(args);
1832
+ }
1833
+ };
1834
+ function openBackend(directory) {
1835
+ return new Backend(new RecordStore(directory));
1836
+ }
1837
+ function assertOwnedRecords(backend) {
1838
+ backend.records();
1839
+ }
1840
+ function writableClients(backend, sessionId) {
1841
+ const clients = backend.tmux(["list-clients", "-F", "#{session_id}|#{client_readonly}"]).trim();
1842
+ if (!clients) return 0;
1843
+ return clients.split("\n").filter((line) => line === `${sessionId}|0`).length;
1844
+ }
1845
+
1846
+ // src/harness/control/leases.ts
1847
+ function resolveLease(context, file, allowExpired = false) {
1848
+ const credential = object(readPrivateJson(file));
1849
+ const lease = context.store.state.leases.find(
1850
+ (entry) => entry.token === credential.token
1851
+ );
1852
+ if (!lease || lease.generation !== context.store.state.group.generation)
1853
+ throw new Error("stale_control");
1854
+ if (!Number.isFinite(Date.parse(lease.expiresAt)))
1855
+ throw new Error("invalid_control_expiry");
1856
+ if (!allowExpired && Date.parse(lease.expiresAt) <= Date.now())
1857
+ throw new Error("expired_control");
1858
+ context.store.session(lease.sessionId);
1859
+ context.backend.inspect(lease.sessionId);
1860
+ return lease;
1861
+ }
1862
+ function acquireControl(context, sessionId, controller, mode) {
1863
+ const { store, backend } = context;
1864
+ if (store.state.group.state === "stopped") throw new Error("group_stopped");
1865
+ store.session(sessionId);
1866
+ const observation = backend.inspect(sessionId);
1867
+ if (!observation.alive) throw new Error("runtime_exited");
1868
+ const current = store.state.leases.find(
1869
+ (entry) => entry.sessionId === sessionId
1870
+ );
1871
+ if (current && Date.parse(current.expiresAt) > Date.now())
1872
+ throw new Error("control_busy");
1873
+ if (writableClients(backend, observation.tmuxSessionId) > 0)
1874
+ throw new Error("native_writer_active");
1875
+ if (mode !== "cli" && mode !== "native")
1876
+ throw new Error("invalid_control_mode");
1877
+ const lease = {
1878
+ token: randomUUID5(),
1879
+ sessionId,
1880
+ generation: store.state.group.generation,
1881
+ controller: id(controller, "controller"),
1882
+ mode,
1883
+ expiresAt: new Date(Date.now() + 6e4).toISOString()
1884
+ };
1885
+ store.state.leases = store.state.leases.filter(
1886
+ (entry) => entry.sessionId !== sessionId
1887
+ );
1888
+ store.state.leases.push(lease);
1889
+ store.save();
1890
+ const leaseFile = join12(backend.runDirectory, `lease-${randomUUID5()}.json`);
1891
+ privateJson(leaseFile, { token: lease.token });
1892
+ return { sessionId, controller, mode, expiresAt: lease.expiresAt, leaseFile };
1893
+ }
1894
+ function controlOperation(context, action, leaseFile) {
1895
+ const lease = resolveLease(context, leaseFile, action === "release");
1896
+ if (action === "renew") {
1897
+ lease.expiresAt = new Date(Date.now() + 6e4).toISOString();
1898
+ context.store.save();
1899
+ return { sessionId: lease.sessionId, expiresAt: lease.expiresAt };
1900
+ }
1901
+ if (action !== "release") throw new Error("unsupported_control_operation");
1902
+ const session = context.backend.inspect(lease.sessionId);
1903
+ if (writableClients(context.backend, session.tmuxSessionId) > 0)
1904
+ throw new Error("native_writer_active");
1905
+ context.store.state.leases = context.store.state.leases.filter(
1906
+ (entry) => entry.token !== lease.token
1907
+ );
1908
+ context.store.save();
1909
+ return { sessionId: lease.sessionId, released: true, inputReplayed: false };
1910
+ }
1911
+ function attachment(context, sessionId, mode, leaseFile) {
1912
+ context.store.session(sessionId);
1913
+ const session = context.backend.inspect(sessionId);
1914
+ if (!session.alive) throw new Error("runtime_exited");
1915
+ if (mode === "observe")
1916
+ return {
1917
+ socket: context.backend.socket,
1918
+ session: session.tmuxSessionId,
1919
+ readOnly: true
1920
+ };
1921
+ if (mode !== "write") throw new Error("invalid_attach_mode");
1922
+ const lease = resolveLease(context, text(leaseFile, "lease_file"));
1923
+ if (lease.sessionId !== sessionId || lease.mode !== "native")
1924
+ throw new Error("native_control_required");
1925
+ if (writableClients(context.backend, session.tmuxSessionId) > 0)
1926
+ throw new Error("native_writer_active");
1927
+ return {
1928
+ socket: context.backend.socket,
1929
+ session: session.tmuxSessionId,
1930
+ readOnly: false
1931
+ };
1932
+ }
1933
+
1934
+ // src/harness/delivery/service.ts
1935
+ import { createHash as createHash4 } from "crypto";
1936
+ function deliver(context, operation, leaseFile, requestId, text3) {
1937
+ const { store, backend } = context;
1938
+ const lease = resolveLease(context, leaseFile);
1939
+ if (lease.mode !== "cli") throw new Error("native_control_held");
1940
+ const session = backend.inspect(lease.sessionId);
1941
+ if (writableClients(backend, session.tmuxSessionId) > 0)
1942
+ throw new Error("native_writer_active");
1943
+ if (operation !== "write" && operation !== "submit")
1944
+ throw new Error("unsupported_input_operation");
1945
+ if (operation === "submit" && text3 !== "")
1946
+ throw new Error("submit_does_not_accept_text");
1947
+ backend.validateText(text3);
1948
+ if (/[\r\n\t]/.test(text3))
1949
+ throw new Error("unqualified_terminal_control_input");
1950
+ id(requestId, "request_id");
1951
+ const digest2 = createHash4("sha256").update(
1952
+ JSON.stringify({
1953
+ operation,
1954
+ text: text3,
1955
+ sessionId: lease.sessionId,
1956
+ generation: lease.generation
1957
+ })
1958
+ ).digest("hex");
1959
+ const previous = store.state.deliveries.find(
1960
+ (entry) => entry.requestId === requestId
1961
+ );
1962
+ if (previous) {
1963
+ if (previous.digest !== digest2) throw new Error("request_conflict");
1964
+ return {
1965
+ ...previous,
1966
+ ok: previous.state === "input_written",
1967
+ duplicate: true,
1968
+ resendAllowed: false,
1969
+ processingConfirmed: false
1970
+ };
1971
+ }
1972
+ if (store.state.deliveries.some(
1973
+ (entry) => entry.sessionId === lease.sessionId && entry.state !== "input_written"
1974
+ )) {
1975
+ throw new Error("session_delivery_uncertain");
1976
+ }
1977
+ const delivery = {
1978
+ controller: lease.controller,
1979
+ requestId,
1980
+ sessionId: lease.sessionId,
1981
+ generation: lease.generation,
1982
+ digest: digest2,
1983
+ operation,
1984
+ state: "intent"
1985
+ };
1986
+ store.state.deliveries.push(delivery);
1987
+ store.save();
1988
+ try {
1989
+ const receipt = backend.write(lease.sessionId, text3, {
1990
+ submit: operation === "submit"
1991
+ });
1992
+ delivery.state = "input_written";
1993
+ store.save();
1994
+ return {
1995
+ ...receipt,
1996
+ requestId,
1997
+ generation: lease.generation,
1998
+ resendAllowed: false
1999
+ };
2000
+ } catch (error) {
2001
+ delivery.state = "delivery_uncertain";
2002
+ store.save();
2003
+ throw error;
2004
+ }
2005
+ }
2006
+ function interrupt2(context, leaseFile) {
2007
+ const lease = resolveLease(context, leaseFile);
2008
+ if (lease.mode !== "cli") throw new Error("native_control_held");
2009
+ const session = context.backend.inspect(lease.sessionId);
2010
+ if (writableClients(context.backend, session.tmuxSessionId) > 0)
2011
+ throw new Error("native_writer_active");
2012
+ context.backend.interrupt(lease.sessionId);
2013
+ return {
2014
+ sessionId: lease.sessionId,
2015
+ signal: "terminal-interrupt",
2016
+ processingConfirmed: false
2017
+ };
2018
+ }
2019
+
2020
+ // src/harness/groups/service.ts
2021
+ import { randomUUID as randomUUID6 } from "crypto";
2022
+ import { realpathSync as realpathSync7, statSync as statSync2, unlinkSync as unlinkSync2 } from "fs";
2023
+ import { join as join15 } from "path";
2024
+
2025
+ // src/harness/adapters/systemd/budget.ts
2026
+ import { join as join13 } from "path";
2027
+ async function budgetOperation(directory, operation) {
2028
+ const backend = openBackend(directory);
2029
+ const path = join13(directory, "runtime-policy.json");
2030
+ const metadata = object(readPrivateJson(backend.metadataPath));
2031
+ const slice = budgetSlice(backend.owner);
2032
+ if (operation.action === "configure") {
2033
+ if (metadata.budgetSlice || backend.records().length)
2034
+ throw new Error("budget_already_initialized");
2035
+ const memoryMb2 = integer(operation.memoryMb, "memory_budget", 128, 4096);
2036
+ const maxActive = integer(operation.maxActive, "max_active", 1, 5);
2037
+ privateJson(backend.metadataPath, { ...metadata, budgetSlice: slice });
2038
+ privateJson(path, { owner: backend.owner, slice, memoryMb: memoryMb2, maxActive });
2039
+ command("systemctl", ["--user", "start", slice]);
2040
+ command("systemctl", [
2041
+ "--user",
2042
+ "set-property",
2043
+ "--runtime",
2044
+ slice,
2045
+ `MemoryMax=${memoryMb2}M`,
2046
+ `MemoryHigh=${Math.floor(memoryMb2 * 0.8)}M`,
2047
+ "TasksMax=256",
2048
+ "CPUQuota=100%"
2049
+ ]);
2050
+ return { ok: true };
2051
+ }
2052
+ const policy = object(readPrivateJson(path));
2053
+ if (policy.owner !== backend.owner || metadata.budgetSlice !== slice || policy.slice !== slice)
2054
+ throw new Error("foreign_budget_policy");
2055
+ if (operation.action === "cleanup") {
2056
+ backend.cleanup();
2057
+ command("systemctl", ["--user", "stop", slice]);
2058
+ command("systemctl", ["--user", "revert", slice]);
2059
+ return { ok: true, budgetStopped: true };
2060
+ }
2061
+ if (operation.action === "stop") {
2062
+ backend.stop(text(operation.id, "session_id"));
2063
+ return { ok: true, stopped: true };
2064
+ }
2065
+ if (operation.action !== "start") throw new Error("invalid_budget_operation");
2066
+ const active = backend.records().filter((record) => {
2067
+ if (record.resource && resourceRunning(record.resource) && !backend.inspect(record.id).alive)
2068
+ throw new Error("container_running_without_proxy");
2069
+ if (record.stoppedAt) {
2070
+ if (unitActive(record.unit)) throw new Error("runtime_stop_unconfirmed");
2071
+ return false;
2072
+ }
2073
+ const observation = backend.inspect(record.id);
2074
+ if (!observation.alive && unitActive(record.unit))
2075
+ throw new Error("runtime_lifecycle_uncertain");
2076
+ return observation.alive;
2077
+ });
2078
+ if (active.length >= integer(policy.maxActive, "max_active", 1, 5))
2079
+ throw new Error("runtime_capacity_exceeded");
2080
+ const spec = object(operation.spec);
2081
+ const memoryMb = integer(spec.memoryMb, "session_memory", 32, 1536);
2082
+ const resource = spec.resource === void 0 ? void 0 : resourceClaim(spec.resource, backend.owner);
2083
+ const dockerPreparation = spec.dockerPreparation;
2084
+ const cpuQuota = resource?.cpuQuota ?? dockerPreparation?.cpuQuota;
2085
+ if (cpuQuota !== void 0) {
2086
+ const reservedCpu = backend.records().filter((record) => !record.stoppedAt).reduce((total, record) => total + (record.resource?.cpuQuota ?? 0), 0);
2087
+ if (reservedCpu + cpuQuota > 5e4)
2088
+ throw new Error("aggregate_container_cpu_budget_exceeded");
2089
+ }
2090
+ if (active.reduce((total, session2) => total + session2.memoryMb, 0) + memoryMb > integer(policy.memoryMb, "memory_budget", 128, 4096))
2091
+ throw new Error("aggregate_memory_budget_exceeded");
2092
+ if (resource || dockerPreparation)
2093
+ command("systemctl", [
2094
+ "--user",
2095
+ "set-property",
2096
+ "--runtime",
2097
+ slice,
2098
+ "CPUQuota=50%"
2099
+ ]);
2100
+ const session = await backend.start({
2101
+ runtime: text(spec.runtime, "runtime"),
2102
+ argv: spec.argv,
2103
+ cwd: text(spec.cwd, "cwd"),
2104
+ memoryMb,
2105
+ budgetSlice: slice,
2106
+ groupId: text(spec.groupId, "group_id"),
2107
+ generation: text(spec.generation, "generation"),
2108
+ role: spec.role,
2109
+ ...resource ? { resource } : {},
2110
+ ...dockerPreparation ? { dockerPreparation } : {}
2111
+ });
2112
+ return { ok: true, session };
2113
+ }
2114
+
2115
+ // src/harness/adapters/systemd/configure.ts
2116
+ import { execFileSync as execFileSync2 } from "child_process";
2117
+ import { join as join14 } from "path";
2118
+ function configureBudget(context, input) {
2119
+ const { store, backend } = context;
2120
+ assertOwnedRecords(backend);
2121
+ const group = store.state.group;
2122
+ const memoryMb = integer(
2123
+ input.memoryMb ?? group.memoryMb,
2124
+ "memory_budget",
2125
+ 128,
2126
+ 4096
2127
+ );
2128
+ const maxActive = integer(
2129
+ input.maxActive ?? group.maxActive,
2130
+ "max_active",
2131
+ 1,
2132
+ 5
2133
+ );
2134
+ const active = backend.records().filter((record) => !record.stoppedAt && backend.inspect(record.id).alive);
2135
+ if (active.length > maxActive)
2136
+ throw new Error("capacity_below_active_sessions");
2137
+ if (active.reduce((total, session) => total + session.memoryMb, 0) > memoryMb)
2138
+ throw new Error("budget_below_reserved_memory");
2139
+ const path = join14(backend.runDirectory, "runtime-policy.json");
2140
+ const policy = object(readPrivateJson(path));
2141
+ const metadata = object(readPrivateJson(backend.metadataPath));
2142
+ const slice = budgetSlice(backend.owner);
2143
+ if (policy.owner !== backend.owner || policy.slice !== slice || metadata.budgetSlice !== slice)
2144
+ throw new Error("foreign_budget_policy");
2145
+ execFileSync2(
2146
+ "systemctl",
2147
+ [
2148
+ "--user",
2149
+ "set-property",
2150
+ "--runtime",
2151
+ slice,
2152
+ `MemoryMax=${memoryMb}M`,
2153
+ `MemoryHigh=${Math.floor(memoryMb * 0.8)}M`
2154
+ ],
2155
+ { timeout: 5e3 }
2156
+ );
2157
+ privateJson(path, {
2158
+ ...policy,
2159
+ memoryMb,
2160
+ maxActive,
2161
+ memoryHighMb: Math.floor(memoryMb * 0.8)
2162
+ });
2163
+ return { memoryMb, maxActive };
2164
+ }
2165
+
2166
+ // src/harness/adapters/process/executable.ts
2167
+ import { accessSync, constants as constants4, statSync } from "fs";
2168
+ import { delimiter, resolve } from "path";
2169
+ function locateExecutable(binary, cwd = process.cwd()) {
2170
+ for (const directory of (process.env.PATH ?? "").split(delimiter)) {
2171
+ if (!directory) continue;
2172
+ const path = resolve(cwd, directory, binary);
2173
+ try {
2174
+ if (!statSync(path).isFile()) continue;
2175
+ accessSync(path, constants4.X_OK);
2176
+ return path;
2177
+ } catch {
2178
+ continue;
2179
+ }
2180
+ }
2181
+ return null;
2182
+ }
2183
+
2184
+ // src/harness/groups/service.ts
2185
+ async function groupOperation(context, action, input = {}) {
2186
+ const { store, backend } = context;
2187
+ if (action === "inspect") return { group: store.state.group };
2188
+ if (action === "configure") {
2189
+ if (store.state.group.state === "stopped") throw new Error("group_stopped");
2190
+ if (input.profile !== void 0 || input.dockerPolicyFile !== void 0)
2191
+ throw new Error("profile_change_requires_new_group");
2192
+ const allowedRuntimes = input.allowedRuntimes === void 0 ? store.state.group.allowedRuntimes : strings(input.allowedRuntimes, "allowed_runtimes");
2193
+ if (allowedRuntimes.some(
2194
+ (runtime) => !store.state.group.allowedRuntimes.includes(runtime)
2195
+ ))
2196
+ throw new Error("runtime_grant_expansion_requires_new_group");
2197
+ Object.assign(store.state.group, configureBudget(context, input), {
2198
+ allowedRuntimes
2199
+ });
2200
+ store.save();
2201
+ return { group: store.state.group, nativePermissionsChanged: false };
2202
+ }
2203
+ if (action === "pause" || action === "resume") {
2204
+ if (store.state.group.state === "stopped") throw new Error("group_stopped");
2205
+ store.state.group.state = action === "pause" ? "paused" : "ready";
2206
+ store.save();
2207
+ return { group: store.state.group, runtimesInterrupted: false };
2208
+ }
2209
+ if (action !== "stop") throw new Error("unsupported_group_operation");
2210
+ if (store.state.group.state !== "stopped") {
2211
+ assertOwnedRecords(backend);
2212
+ await budgetOperation(backend.runDirectory, { action: "cleanup" });
2213
+ store.state.group.state = "stopped";
2214
+ store.state.leases = [];
2215
+ store.state.group.sessions.forEach((session) => {
2216
+ session.stopped = true;
2217
+ });
2218
+ store.save();
2219
+ }
2220
+ return { group: store.state.group, inputReplayed: false };
2221
+ }
2222
+
2223
+ // src/harness/observation/options.ts
2224
+ function readOptions(input) {
2225
+ if (input === void 0) return {};
2226
+ const allowed = ["lines", "maxBytes", "alternate"];
2227
+ if (Object.keys(input).some((key) => !allowed.includes(key)))
2228
+ throw new Error("invalid_read_option");
2229
+ if (input.alternate !== void 0 && typeof input.alternate !== "boolean")
2230
+ throw new Error("invalid_alternate");
2231
+ return {
2232
+ ...input.lines === void 0 ? {} : { lines: integer(input.lines, "lines", 1, 2e3) },
2233
+ ...input.maxBytes === void 0 ? {} : { maxBytes: integer(input.maxBytes, "max_bytes", 1, 65536) },
2234
+ ...input.alternate === void 0 ? {} : { alternate: input.alternate }
2235
+ };
2236
+ }
2237
+
2238
+ // src/harness/observation/service.ts
2239
+ function listSessions(context) {
2240
+ const { store, backend } = context;
2241
+ const sessions = store.state.group.sessions.map((reference) => {
2242
+ if (reference.stopped) return { ...reference, observed: "stopped" };
2243
+ try {
2244
+ return {
2245
+ ...backend.inspect(reference.id),
2246
+ role: reference.role,
2247
+ observed: "terminal-process"
2248
+ };
2249
+ } catch (error) {
2250
+ return {
2251
+ ...reference,
2252
+ observed: "unavailable",
2253
+ reason: error instanceof Error ? error.message : "observation_failed"
2254
+ };
2255
+ }
2256
+ });
2257
+ return {
2258
+ generation: store.state.group.generation,
2259
+ sessions,
2260
+ providerStateInferred: false
2261
+ };
2262
+ }
2263
+ function observeSession(context, action, sessionId, input) {
2264
+ context.store.session(sessionId);
2265
+ if (action === "inspect") {
2266
+ return {
2267
+ session: context.backend.inspect(sessionId),
2268
+ providerStateInferred: false
2269
+ };
2270
+ }
2271
+ if (action !== "read") throw new Error("unsupported_observation_operation");
2272
+ return {
2273
+ sessionId,
2274
+ ...context.backend.read(sessionId, readOptions(input)),
2275
+ providerStateInferred: false
2276
+ };
2277
+ }
2278
+ function inspectDeliveries(context, requestId) {
2279
+ const deliveries = context.store.state.deliveries.filter(
2280
+ (entry) => !requestId || entry.requestId === requestId
2281
+ );
2282
+ if (requestId && deliveries.length === 0)
2283
+ throw new Error("request_not_found");
2284
+ return {
2285
+ generation: context.store.state.group.generation,
2286
+ deliveries,
2287
+ processingConfirmed: false
2288
+ };
2289
+ }
2290
+
2291
+ // src/harness/recovery/service.ts
2292
+ import { randomUUID as randomUUID7 } from "crypto";
2293
+
2294
+ // src/harness/adapters/process/recover-lock.ts
2295
+ import { existsSync as existsSync5, lstatSync as lstatSync6, unlinkSync as unlinkSync3 } from "fs";
2296
+ import { join as join16 } from "path";
2297
+ function recoverInputLock(backend, sessionId) {
2298
+ backend.inspect(sessionId);
2299
+ const path = join16(backend.runDirectory, `${sessionId}.input.lock`);
2300
+ if (!existsSync5(path)) return;
2301
+ const before = lstatSync6(path);
2302
+ const record = object(readPrivateJson(path));
2303
+ if (record.id !== sessionId) throw new Error("foreign_writer_lock");
2304
+ if (!controllerExited(text(record.controller, "controller_identity")))
2305
+ throw new Error("writer_still_alive");
2306
+ if (lstatSync6(path).ino !== before.ino)
2307
+ throw new Error("writer_lock_changed");
2308
+ unlinkSync3(path);
2309
+ }
2310
+
2311
+ // src/harness/sessions/service.ts
2312
+ import { realpathSync as realpathSync8 } from "fs";
2313
+ import { relative as relative5 } from "path";
2314
+
2315
+ // src/harness/launch/service.ts
2316
+ import { existsSync as existsSync6 } from "fs";
2317
+ function assertLaunchAdmission(records2) {
2318
+ for (const journal of launchJournals(records2)) {
2319
+ if (journal.abortRecord()?.state === "stopped" && unitActive(journal.intent().unit))
2320
+ throw new Error("runtime_stop_unconfirmed");
2321
+ }
2322
+ if (pendingLaunches(records2).length)
2323
+ throw new Error("launch_requires_reconciliation");
2324
+ }
2325
+ function authorizeSession(context, sessionId) {
2326
+ const journal = new LaunchJournal(context.backend.recordStore, sessionId);
2327
+ if (journal.intent().controllerIdentity !== processIdentity(process.pid))
2328
+ throw new Error("foreign_launch_controller");
2329
+ assertProof(new Connection(context.backend.recordStore), journal.proof());
2330
+ const resource = journal.intent().resource;
2331
+ if (resource) assertResourceFresh(resource);
2332
+ journal.authorize();
2333
+ journal.commit();
2334
+ }
2335
+ function inspectPendingStarts(context) {
2336
+ return pendingLaunches(context.backend.recordStore).map((journal) => ({
2337
+ sessionId: journal.id,
2338
+ role: journal.intent().role,
2339
+ runtime: journal.intent().runtime,
2340
+ controllerExited: controllerExited(journal.intent().controllerIdentity),
2341
+ proofPresent: existsSync6(journal.path("proof")),
2342
+ recordPresent: existsSync6(journal.records.path(journal.id)),
2343
+ registered: context.store.state.group.sessions.some(
2344
+ (session) => session.id === journal.id
2345
+ ),
2346
+ authorizationPresent: existsSync6(journal.path("grant")),
2347
+ processingConfirmed: false,
2348
+ inputReplayed: false
2349
+ }));
2350
+ }
2351
+
2352
+ // src/harness/sessions/service.ts
2353
+ async function startSession(context, input) {
2354
+ const { store, backend } = context;
2355
+ const group = store.state.group;
2356
+ assertOwnedRecords(backend);
2357
+ assertLaunchAdmission(backend.recordStore);
2358
+ if (backend.records().some(
2359
+ (record) => !record.stoppedAt && !group.sessions.some((session2) => session2.id === record.id)
2360
+ )) {
2361
+ throw new Error("unregistered_session_requires_recovery");
2362
+ }
2363
+ if (group.state !== "ready") throw new Error("group_not_ready");
2364
+ const runtime = text(input.runtime, "runtime");
2365
+ if (!group.allowedRuntimes.includes(runtime))
2366
+ throw new Error("runtime_not_granted");
2367
+ const role = input.role;
2368
+ if (role !== "main" && role !== "worker") throw new Error("invalid_role");
2369
+ if (role === "main" && group.sessions.some(
2370
+ (session2) => session2.role === "main" && !session2.stopped
2371
+ )) {
2372
+ throw new Error("main_already_assigned");
2373
+ }
2374
+ if (role === "worker" && !group.sessions.some(
2375
+ (session2) => session2.role === "main" && !session2.stopped
2376
+ )) {
2377
+ throw new Error("main_required");
2378
+ }
2379
+ if (role === "worker") {
2380
+ const main = group.sessions.find(
2381
+ (session2) => session2.role === "main" && !session2.stopped
2382
+ );
2383
+ if (!backend.inspect(main.id).alive) throw new Error("main_unavailable");
2384
+ }
2385
+ const cwd = realpathSync8(text(input.cwd ?? group.projectRoot, "cwd"));
2386
+ const scope = relative5(group.projectRoot, cwd);
2387
+ if (scope === ".." || scope.startsWith("../"))
2388
+ throw new Error("cwd_outside_project");
2389
+ const memoryMb = integer(input.memoryMb ?? 384, "session_memory", 32, 1536);
2390
+ const executable = runtimeExecutables[runtime];
2391
+ if (!executable) throw new Error("unsupported_runtime");
2392
+ const args = input.args === void 0 || Array.isArray(input.args) && input.args.length === 0 ? [] : strings(input.args, "runtime_args");
2393
+ if (group.profile === "native" && input.containerFile !== void 0)
2394
+ throw new Error("container_requires_docker_profile");
2395
+ if (group.dockerPolicy?.egress && input.containerFile !== void 0)
2396
+ throw new Error("egress_requires_cli_owned_creation");
2397
+ const privateProfile = input.privateProfile === void 0 ? void 0 : profileName(input.privateProfile);
2398
+ if (privateProfile && (group.profile !== "docker" || input.containerFile !== void 0))
2399
+ throw new Error("private_profile_requires_cli_owned_creation");
2400
+ if (privateProfile) {
2401
+ const profile = selectedProfile(
2402
+ group.dockerPolicy,
2403
+ privateProfile,
2404
+ runtime
2405
+ );
2406
+ assertProfileAvailable(profile, group.projectRoot);
2407
+ }
2408
+ const resource = input.containerFile === void 0 ? void 0 : admitResource(
2409
+ input.containerFile,
2410
+ group,
2411
+ role,
2412
+ backend.runDirectory,
2413
+ memoryMb,
2414
+ runtime
2415
+ );
2416
+ if (resource && args.length)
2417
+ throw new Error("container_args_are_fixed_at_creation");
2418
+ if (resource && backend.records().some((record) => record.resource?.id === resource.id))
2419
+ throw new Error("container_already_bound");
2420
+ const dockerPreparation = group.profile === "docker" && !resource ? {
2421
+ args,
2422
+ memoryMb: integer(memoryMb - 64, "container_memory", 32, 1472),
2423
+ cpuQuota: integer(
2424
+ input.containerCpuQuota ?? Math.floor(5e4 / group.maxActive),
2425
+ "container_cpu",
2426
+ 1,
2427
+ 5e4
2428
+ ),
2429
+ ...privateProfile ? { privateProfile } : {}
2430
+ } : void 0;
2431
+ const executablePath = locateExecutable(
2432
+ resource || dockerPreparation ? "docker" : executable,
2433
+ cwd
2434
+ );
2435
+ if (!executablePath) throw new Error("runtime_executable_unavailable");
2436
+ const argv = resource ? [executablePath, "start", "--attach", "--interactive", resource.id] : [executablePath, ...args];
2437
+ const result = await budgetOperation(backend.runDirectory, {
2438
+ action: "start",
2439
+ spec: {
2440
+ runtime,
2441
+ argv,
2442
+ cwd,
2443
+ memoryMb,
2444
+ groupId: group.id,
2445
+ generation: group.generation,
2446
+ role,
2447
+ ...resource ? { resource } : {},
2448
+ ...dockerPreparation ? { dockerPreparation } : {}
2449
+ }
2450
+ });
2451
+ const session = result.session;
2452
+ group.sessions.push({ id: session.id, role, stopped: false });
2453
+ store.save();
2454
+ authorizeSession(context, session.id);
2455
+ return { session, role, generation: group.generation };
2456
+ }
2457
+ async function stopSession(context, sessionId) {
2458
+ const { store, backend } = context;
2459
+ store.session(sessionId);
2460
+ assertOwnedRecords(backend);
2461
+ const reference = store.state.group.sessions.find(
2462
+ (session) => session.id === sessionId
2463
+ );
2464
+ if (!reference.stopped) {
2465
+ await budgetOperation(backend.runDirectory, {
2466
+ action: "stop",
2467
+ id: sessionId
2468
+ });
2469
+ reference.stopped = true;
2470
+ store.state.leases = store.state.leases.filter(
2471
+ (lease) => lease.sessionId !== sessionId
2472
+ );
2473
+ store.save();
2474
+ }
2475
+ return { sessionId, stopped: true };
2476
+ }
2477
+
2478
+ // src/harness/recovery/service.ts
2479
+ function inspectRecovery(context, includeStarts = false) {
2480
+ const pendingStarts = includeStarts ? inspectPendingStarts(context) : [];
2481
+ return {
2482
+ ...listSessions(context),
2483
+ control: context.store.state.leases.map(({ token, ...lease }) => ({
2484
+ ...lease,
2485
+ expired: Date.parse(lease.expiresAt) <= Date.now()
2486
+ })),
2487
+ deliveries: context.store.state.deliveries,
2488
+ unregisteredOwnedSessions: context.backend.records().filter(
2489
+ (record) => !record.stoppedAt && !context.store.state.group.sessions.some(
2490
+ (session) => session.id === record.id
2491
+ )
2492
+ ).map((record) => ({ id: record.id, runtime: record.runtime })),
2493
+ inputReplayed: false,
2494
+ ...includeStarts ? { pendingStarts } : {}
2495
+ };
2496
+ }
2497
+ function abortStart(context, sessionId) {
2498
+ const records2 = context.backend.recordStore;
2499
+ const journal = new LaunchJournal(records2, sessionId);
2500
+ if (!pendingLaunches(records2).some((entry) => entry.id === sessionId) && !journal.abortRecord())
2501
+ throw new Error("start_already_committed");
2502
+ const result = abortLaunch(new Connection(records2), journal);
2503
+ const reference = context.store.state.group.sessions.find(
2504
+ (session) => session.id === sessionId
2505
+ );
2506
+ if (reference) reference.stopped = true;
2507
+ context.store.state.leases = context.store.state.leases.filter(
2508
+ (lease) => lease.sessionId !== sessionId
2509
+ );
2510
+ context.store.save();
2511
+ return { ...result, sessionId };
2512
+ }
2513
+ function reconcile(context) {
2514
+ const { store, backend } = context;
2515
+ for (const delivery of store.state.deliveries) {
2516
+ if (delivery.state === "intent") delivery.state = "delivery_uncertain";
2517
+ }
2518
+ store.save();
2519
+ assertOwnedRecords(backend);
2520
+ for (const session of store.state.group.sessions) {
2521
+ if (!session.stopped) recoverInputLock(backend, session.id);
2522
+ }
2523
+ const retained = [];
2524
+ for (const lease of store.state.leases) {
2525
+ if (Date.parse(lease.expiresAt) > Date.now()) {
2526
+ retained.push(lease);
2527
+ continue;
2528
+ }
2529
+ const session = backend.inspect(lease.sessionId);
2530
+ if (writableClients(backend, session.tmuxSessionId) > 0) {
2531
+ retained.push(lease);
2532
+ }
2533
+ }
2534
+ store.state.leases = retained;
2535
+ store.save();
2536
+ return inspectRecovery(context);
2537
+ }
2538
+ async function stopOrphan(context, sessionId) {
2539
+ if (context.store.state.group.sessions.some(
2540
+ (session) => session.id === sessionId
2541
+ ))
2542
+ throw new Error("session_is_registered");
2543
+ assertOwnedRecords(context.backend);
2544
+ context.backend.inspect(sessionId);
2545
+ await budgetOperation(context.backend.runDirectory, {
2546
+ action: "stop",
2547
+ id: sessionId
2548
+ });
2549
+ return { sessionId, stopped: true, adopted: false };
2550
+ }
2551
+ async function replaceMain(context, input) {
2552
+ const { store, backend } = context;
2553
+ const previous = store.state.group.sessions.find(
2554
+ (session) => session.role === "main" && !session.stopped
2555
+ );
2556
+ if (previous) {
2557
+ const observation = backend.inspect(previous.id);
2558
+ if (observation.alive) throw new Error("main_still_alive");
2559
+ previous.stopped = true;
2560
+ }
2561
+ store.state.group.generation = randomUUID7();
2562
+ store.state.leases = [];
2563
+ store.save();
2564
+ const result = await startSession(context, { ...input, role: "main" });
2565
+ return {
2566
+ ...result,
2567
+ previousMain: previous?.id ?? null,
2568
+ inputReplayed: false
2569
+ };
2570
+ }
2571
+
2572
+ // src/harness/application/context.ts
2573
+ import { dirname as dirname2 } from "path";
2574
+ function openGroup(path) {
2575
+ const store = new GroupStore(path);
2576
+ const backend = openBackend(dirname2(store.path));
2577
+ if (store.state.group.owner !== backend.owner)
2578
+ throw new Error("foreign_group");
2579
+ return { store, backend };
2580
+ }
2581
+
2582
+ // src/harness/application/effects.ts
2583
+ var observations = /* @__PURE__ */ new Set([
2584
+ "group:inspect",
2585
+ "session:list",
2586
+ "session:inspect",
2587
+ "session:read",
2588
+ "session:watch",
2589
+ "delivery:list",
2590
+ "delivery:inspect",
2591
+ "recovery:inspect",
2592
+ "attach:inspect"
2593
+ ]);
2594
+ function isReadOnly(operation) {
2595
+ if (operation.family === "attach" && operation.action === "open")
2596
+ return (operation.mode ?? "observe") === "observe";
2597
+ return observations.has(`${operation.family}:${operation.action}`);
2598
+ }
2599
+
2600
+ // src/harness/adapters/tmux/detach.ts
2601
+ function detachClients(context, sessionId) {
2602
+ context.store.session(sessionId);
2603
+ const session = context.backend.inspect(sessionId);
2604
+ context.backend.tmux(["detach-client", "-s", session.tmuxSessionId]);
2605
+ return { sessionId, clientsDetached: true, runtimeStopRequested: false };
2606
+ }
2607
+
2608
+ // src/harness/adapters/tmux/clients.ts
2609
+ function attachedClients(backend, sessionId) {
2610
+ const session = backend.inspect(sessionId);
2611
+ if (!session.alive) throw new Error("session_unavailable");
2612
+ const output = backend.tmux([
2613
+ "list-clients",
2614
+ "-F",
2615
+ "#{session_id}|#{client_pid}|#{client_readonly}|#{client_tty}"
2616
+ ]).trim();
2617
+ if (!output) return [];
2618
+ return output.split("\n").flatMap((line) => {
2619
+ const [id2, pid, readOnly, tty] = line.split("|");
2620
+ if (id2 !== session.tmuxSessionId) return [];
2621
+ if (!/^\d+$/.test(pid ?? "") || !tty || !["0", "1"].includes(readOnly ?? ""))
2622
+ throw new Error("attachment_observation_unknown");
2623
+ return [{ pid: Number(pid), tty, readOnly: readOnly === "1" }];
2624
+ });
2625
+ }
2626
+
2627
+ // src/harness/observation/attachments.ts
2628
+ function inspectAttachments(context, sessionId) {
2629
+ context.store.session(sessionId);
2630
+ return { sessionId, clients: attachedClients(context.backend, sessionId) };
2631
+ }
2632
+
2633
+ // src/harness/application/dispatch.ts
2634
+ async function runOperation(operation) {
2635
+ const context = openGroup(text(operation.groupFile, "group_file"));
2636
+ if (!isReadOnly(operation) && operation.generation !== context.store.state.group.generation) {
2637
+ throw new Error("stale_group_generation");
2638
+ }
2639
+ const { family, action } = operation;
2640
+ if (family === "group")
2641
+ return groupOperation(context, action, operation.input);
2642
+ if (family === "session") {
2643
+ if (action === "start")
2644
+ return startSession(context, object(operation.input));
2645
+ if (action === "list") return listSessions(context);
2646
+ const sessionId = text(operation.sessionId, "session_id");
2647
+ if (action === "stop") return stopSession(context, sessionId);
2648
+ return observeSession(context, action, sessionId, operation.input);
2649
+ }
2650
+ if (family === "control") {
2651
+ if (action === "acquire") {
2652
+ return acquireControl(
2653
+ context,
2654
+ text(operation.sessionId, "session_id"),
2655
+ text(operation.controller, "controller"),
2656
+ operation.mode ?? "cli"
2657
+ );
2658
+ }
2659
+ return controlOperation(
2660
+ context,
2661
+ action,
2662
+ text(operation.leaseFile, "lease_file")
2663
+ );
2664
+ }
2665
+ if (family === "input") {
2666
+ const leaseFile = text(operation.leaseFile, "lease_file");
2667
+ if (action === "interrupt") return interrupt2(context, leaseFile);
2668
+ return deliver(
2669
+ context,
2670
+ action,
2671
+ leaseFile,
2672
+ text(operation.requestId, "request_id"),
2673
+ operation.text ?? ""
2674
+ );
2675
+ }
2676
+ if (family === "attach") {
2677
+ if (action === "inspect")
2678
+ return inspectAttachments(
2679
+ context,
2680
+ text(operation.sessionId, "session_id")
2681
+ );
2682
+ if (action === "detach")
2683
+ return detachClients(context, text(operation.sessionId, "session_id"));
2684
+ return attachment(
2685
+ context,
2686
+ text(operation.sessionId, "session_id"),
2687
+ operation.mode ?? "observe",
2688
+ operation.leaseFile
2689
+ );
2690
+ }
2691
+ if (family === "delivery")
2692
+ return inspectDeliveries(context, operation.requestId);
2693
+ if (family === "recovery") {
2694
+ if (action === "abort-start")
2695
+ return abortStart(context, text(operation.sessionId, "session_id"));
2696
+ if (action === "inspect")
2697
+ return inspectRecovery(context, operation.includeStarts === true);
2698
+ if (action === "reconcile") return reconcile(context);
2699
+ if (action === "stop-orphan")
2700
+ return stopOrphan(context, text(operation.sessionId, "session_id"));
2701
+ if (action === "replace-main")
2702
+ return replaceMain(context, object(operation.input));
2703
+ }
2704
+ throw new Error("unsupported_operation");
2705
+ }
2706
+
2707
+ // src/harness/application/worker.ts
2708
+ var operationFile = process.argv[2];
2709
+ try {
2710
+ const operation = readPrivateJson(operationFile);
2711
+ const receipt = await runOperation(operation);
2712
+ const group = new GroupStore(text(operation.groupFile, "group_file")).state.group;
2713
+ console.log(
2714
+ JSON.stringify({
2715
+ schemaVersion: 1,
2716
+ ok: true,
2717
+ groupId: group.id,
2718
+ generation: group.generation,
2719
+ effect: `${operation.family}:${operation.action}`,
2720
+ ...receipt
2721
+ })
2722
+ );
2723
+ if (receipt.ok === false) process.exitCode = 1;
2724
+ } catch (error) {
2725
+ console.log(
2726
+ JSON.stringify({
2727
+ schemaVersion: 1,
2728
+ ok: false,
2729
+ error: error instanceof Error ? error.message : "operation_failed",
2730
+ resendAllowed: false
2731
+ })
2732
+ );
2733
+ process.exitCode = 1;
2734
+ } finally {
2735
+ unlinkSync4(operationFile);
2736
+ }
2737
+ //# sourceMappingURL=harness-worker.js.map