@cotal-ai/manager 0.106.1 → 0.108.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.
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +30 -13
- package/dist/commands.js.map +1 -1
- package/dist/manager-service-contract.d.ts.map +1 -1
- package/dist/manager-service-contract.js +1 -0
- package/dist/manager-service-contract.js.map +1 -1
- package/dist/manager.d.ts +16 -0
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +83 -34
- package/dist/manager.js.map +1 -1
- package/dist/service-adapter.d.ts.map +1 -1
- package/dist/service-adapter.js +2 -1
- package/dist/service-adapter.js.map +1 -1
- package/package.json +12 -12
package/dist/manager.js
CHANGED
|
@@ -376,6 +376,12 @@ export class Manager {
|
|
|
376
376
|
/** See {@link ManagerOptions.installedExtensions}. */
|
|
377
377
|
installedExtensions;
|
|
378
378
|
executionState;
|
|
379
|
+
/** One backend per kind a seat has asked for, beside {@link runtime}. The manager's own runtime
|
|
380
|
+
* stays the default and is never replaced by a later seat's choice. */
|
|
381
|
+
runtimes = new Map();
|
|
382
|
+
/** Hosted pooled control, recorded so a later seat cannot add a custodial runtime the constructor
|
|
383
|
+
* already refused for the manager's own. */
|
|
384
|
+
pooled;
|
|
379
385
|
/** Internal test seam. Production leaves this undefined and uses the scoped delivery-admin evictor. */
|
|
380
386
|
staticLifecycleEvict;
|
|
381
387
|
preserveStopTimeoutMs;
|
|
@@ -715,6 +721,7 @@ export class Manager {
|
|
|
715
721
|
if (opts.secretStore)
|
|
716
722
|
this.secretStoreIdentity = injectedSecretStoreIdentity(opts.secretStore);
|
|
717
723
|
this.installedExtensions = opts.installedExtensions ?? false;
|
|
724
|
+
this.pooled = opts.pooled === true;
|
|
718
725
|
this.executionState = opts.execution === "none" ? { kind: "none" } : { kind: "runtime" };
|
|
719
726
|
if (!this.remoteAuthority) {
|
|
720
727
|
const local = loadManagerInstanceIdentity(this.workspaceRoot, this.space);
|
|
@@ -772,6 +779,30 @@ export class Manager {
|
|
|
772
779
|
throw new EpEnvelopeError("unimplemented", this.executionRefusal());
|
|
773
780
|
return this.runtime;
|
|
774
781
|
}
|
|
782
|
+
/** The backend one seat launches, restarts, and is reaped through. An omitted or blank choice is
|
|
783
|
+
* this manager's own runtime. A named one is created once, cached by its resolved kind, and reused
|
|
784
|
+
* for every later seat of that kind. The manager's own runtime is never replaced. An unknown or
|
|
785
|
+
* unreachable runtime throws, and pooled control refuses a custodial one by the same rule the
|
|
786
|
+
* constructor applied to the manager's own. */
|
|
787
|
+
runtimeFor(kind) {
|
|
788
|
+
if (this.executionState.kind === "none")
|
|
789
|
+
throw new EpEnvelopeError("unimplemented", this.executionRefusal());
|
|
790
|
+
const asked = kind?.trim();
|
|
791
|
+
if (!asked)
|
|
792
|
+
return this.runtime;
|
|
793
|
+
if (asked === "auto")
|
|
794
|
+
throw new Error(`runtime "auto" chooses the manager's runtime, not one seat; omit runtime to use ${this.runtime.kind}`);
|
|
795
|
+
if (asked === this.runtime.kind)
|
|
796
|
+
return this.runtime;
|
|
797
|
+
const cached = this.runtimes.get(asked);
|
|
798
|
+
if (cached)
|
|
799
|
+
return cached;
|
|
800
|
+
const runtime = createRuntime(asked, `cotal-${this.space}`);
|
|
801
|
+
if (this.pooled && isCustodialRuntime(runtime))
|
|
802
|
+
throw new Error(`pooled control refuses custodial runtime "${runtime.kind}" before starting agents`);
|
|
803
|
+
this.runtimes.set(runtime.kind, runtime);
|
|
804
|
+
return runtime;
|
|
805
|
+
}
|
|
775
806
|
/** What a default process stop does with this manager's seats. `release` drops manager-local
|
|
776
807
|
* custody and leaves every seat running. `stop` means this runtime keeps its PTYs inside the
|
|
777
808
|
* manager process, so those seats close with it: the stop stops and deprovisions them, and still
|
|
@@ -4546,10 +4577,11 @@ export class Manager {
|
|
|
4546
4577
|
.reduce((max, p) => Math.max(max, p.ts), 0) + 1;
|
|
4547
4578
|
// Same ordering as the spawn path: the replacement seat's reference is recorded on the
|
|
4548
4579
|
// still-active slot before its processes exist, so a crash here never strands it.
|
|
4549
|
-
const
|
|
4580
|
+
const runtime = this.runtimeFor(a.launch.runtime);
|
|
4581
|
+
const custody = this.reserveCustody(runtime);
|
|
4550
4582
|
if (custody)
|
|
4551
4583
|
await this.recordSlotCustody(a, custody);
|
|
4552
|
-
const handle = await this.spawnCustodied(a.name, spec, a.launch.cwd, custody);
|
|
4584
|
+
const handle = await this.spawnCustodied(runtime, a.name, spec, a.launch.cwd, custody);
|
|
4553
4585
|
replacement = handle;
|
|
4554
4586
|
restart.sessionStatePath = spec.sessionStatePath ?? restart.sessionStatePath;
|
|
4555
4587
|
if (continueSession !== undefined) {
|
|
@@ -4727,6 +4759,8 @@ export class Manager {
|
|
|
4727
4759
|
// scalar/array (the CLI never does). Core doesn't interpret the keys; the connector validates them.
|
|
4728
4760
|
if (args.launchOptions !== undefined && (typeof args.launchOptions !== "object" || args.launchOptions === null || Array.isArray(args.launchOptions)))
|
|
4729
4761
|
return Promise.resolve({ ok: false, error: "launchOptions: expected a key:value mapping" });
|
|
4762
|
+
if (args.runtime !== undefined && (typeof args.runtime !== "string" || !args.runtime.trim()))
|
|
4763
|
+
return Promise.resolve({ ok: false, error: "runtime: expected a non-empty runtime name" });
|
|
4730
4764
|
let supervise;
|
|
4731
4765
|
if (args.supervise !== undefined) {
|
|
4732
4766
|
const raw = args.supervise;
|
|
@@ -4815,6 +4849,7 @@ export class Manager {
|
|
|
4815
4849
|
allowPublish,
|
|
4816
4850
|
shareTools,
|
|
4817
4851
|
...(supervise !== undefined ? { supervise } : {}),
|
|
4852
|
+
...(typeof args.runtime === "string" ? { runtime: args.runtime.trim() } : {}),
|
|
4818
4853
|
route,
|
|
4819
4854
|
}, caller, hooks, authenticatedCaller);
|
|
4820
4855
|
}
|
|
@@ -5234,6 +5269,13 @@ export class Manager {
|
|
|
5234
5269
|
// Before the first await, so the grant, the launch, the retained form and the restart slot all read
|
|
5235
5270
|
// the lists and the restart policy as admitted.
|
|
5236
5271
|
opts = ownLists(opts);
|
|
5272
|
+
let runtime;
|
|
5273
|
+
try {
|
|
5274
|
+
runtime = this.runtimeFor(opts.runtime);
|
|
5275
|
+
}
|
|
5276
|
+
catch (e) {
|
|
5277
|
+
return { ok: false, error: rejectionText(e) };
|
|
5278
|
+
}
|
|
5237
5279
|
if (opts.resolved)
|
|
5238
5280
|
opts.resolved = ownLists(opts.resolved);
|
|
5239
5281
|
if (opts.supervise)
|
|
@@ -5312,8 +5354,8 @@ export class Manager {
|
|
|
5312
5354
|
// exit, so a name cannot be respawned in place. User-mode seats have no static slot that
|
|
5313
5355
|
// keeps the incarnation owned across a process death, so the same refusal applies there.
|
|
5314
5356
|
if (opts.supervise !== undefined) {
|
|
5315
|
-
if (
|
|
5316
|
-
return { ok: false, error: `supervise is a restart policy this host cannot enforce: runtime "${
|
|
5357
|
+
if (runtime.kind !== "pty")
|
|
5358
|
+
return { ok: false, error: `supervise is a restart policy this host cannot enforce: runtime "${runtime.kind}" cannot respawn a name in place` };
|
|
5317
5359
|
if (this.userMode)
|
|
5318
5360
|
return { ok: false, error: "supervise is a restart policy this host cannot enforce: a user-mode seat has no static slot to keep the incarnation owned across a process death" };
|
|
5319
5361
|
}
|
|
@@ -5330,8 +5372,8 @@ export class Manager {
|
|
|
5330
5372
|
}
|
|
5331
5373
|
// A delegated seat starts outside this host from values alone, so a choice only this host can
|
|
5332
5374
|
// honour is refused here, before enrollment, and named rather than dropped.
|
|
5333
|
-
if (
|
|
5334
|
-
const delegatedBy = `runtime "${
|
|
5375
|
+
if (runtime.spawnDelegated) {
|
|
5376
|
+
const delegatedBy = `runtime "${runtime.kind}" starts seats outside this host`;
|
|
5335
5377
|
if (!this.remoteAuthority?.enrollManagedAgent)
|
|
5336
5378
|
return { ok: false, error: `${delegatedBy}, which needs a host that enrolls managed agents (remoteAuthority.enrollManagedAgent); a delegated seat has no local grant path` };
|
|
5337
5379
|
try {
|
|
@@ -5508,9 +5550,9 @@ export class Manager {
|
|
|
5508
5550
|
}
|
|
5509
5551
|
}
|
|
5510
5552
|
// The child takes launch options as `--opt k=v`, so only string values can cross to it.
|
|
5511
|
-
const unportable =
|
|
5553
|
+
const unportable = runtime.spawnDelegated ? Object.keys(launchOptions ?? {}).filter((k) => typeof launchOptions[k] !== "string") : [];
|
|
5512
5554
|
if (unportable.length)
|
|
5513
|
-
return { ok: false, error: `runtime "${
|
|
5555
|
+
return { ok: false, error: `runtime "${runtime.kind}" starts seats outside this host, so it cannot pass non-string launch options (${unportable.join(", ")})` };
|
|
5514
5556
|
// The AG-UI event plane is on unless the launch explicitly opted out. Refused HERE, before
|
|
5515
5557
|
// anything is minted: a connector that cannot
|
|
5516
5558
|
// emit must fail before provisioning rather than after, exactly as an unsupported `resume` does.
|
|
@@ -5599,7 +5641,7 @@ export class Manager {
|
|
|
5599
5641
|
// launch. Minting it inside `runtime.spawn` (as it used to be) put the processes on disk
|
|
5600
5642
|
// before anything recorded how to address them, so a crash in that window left a live seat
|
|
5601
5643
|
// outside every manager and the successor retired the slot over it.
|
|
5602
|
-
const custody = this.reserveCustody();
|
|
5644
|
+
const custody = this.reserveCustody(runtime);
|
|
5603
5645
|
// ACCEPT SEAM (spawn-as-action): the incarnation identity is minted and NOTHING has
|
|
5604
5646
|
// been provisioned yet — the action serve path binds the goal + replies the acceptance HERE. A
|
|
5605
5647
|
// throw (bind conflict / duplicate goalId) aborts the spawn before provisioning: the catch below
|
|
@@ -5820,12 +5862,12 @@ export class Manager {
|
|
|
5820
5862
|
// manager path is produced for it, only the handoff its runtime writes into the child.
|
|
5821
5863
|
let spec;
|
|
5822
5864
|
let handle;
|
|
5823
|
-
if (
|
|
5865
|
+
if (runtime.spawnDelegated) {
|
|
5824
5866
|
const handoff = this.composeManagedHandoff(enrolled.material, enrolled.actorToken);
|
|
5825
5867
|
if (this.delegatedLaunched.has(lifecycleUid))
|
|
5826
|
-
throw new Error(`lifecycle ${lifecycleUid} was already handed to runtime "${
|
|
5868
|
+
throw new Error(`lifecycle ${lifecycleUid} was already handed to runtime "${runtime.kind}"; a lifecycle is handed off at most once`);
|
|
5827
5869
|
this.delegatedLaunched.add(lifecycleUid);
|
|
5828
|
-
handle =
|
|
5870
|
+
handle = runtime.spawnDelegated({ agent, persona: readFileSync(configPath, "utf8"), managerInstanceId: this.managerInstanceId, role, model, variant, prompt, launchOptions: launchOptions, events }, handoff);
|
|
5829
5871
|
}
|
|
5830
5872
|
else {
|
|
5831
5873
|
if (carried) {
|
|
@@ -5837,7 +5879,7 @@ export class Manager {
|
|
|
5837
5879
|
if (carried)
|
|
5838
5880
|
this.transcripts.consume(opts.resumeClaim, opts.resume);
|
|
5839
5881
|
spec.env = { ...spec.env, COTAL_MANAGER_INSTANCE: this.managerInstanceId };
|
|
5840
|
-
handle = await this.spawnCustodied(name, spec, cwd, custody);
|
|
5882
|
+
handle = await this.spawnCustodied(runtime, name, spec, cwd, custody);
|
|
5841
5883
|
}
|
|
5842
5884
|
hooks?.onLaunched?.(); // The "launched" progress edge (process spawned, pre-presence)
|
|
5843
5885
|
const managed = {
|
|
@@ -5860,6 +5902,7 @@ export class Manager {
|
|
|
5860
5902
|
control: spec?.control,
|
|
5861
5903
|
...(spec ? {} : { handedOff: true }),
|
|
5862
5904
|
launch: {
|
|
5905
|
+
runtime: runtime.kind,
|
|
5863
5906
|
source: opts.resolved
|
|
5864
5907
|
? {
|
|
5865
5908
|
kind: "manifest",
|
|
@@ -6027,7 +6070,7 @@ export class Manager {
|
|
|
6027
6070
|
// "no role", so dropping the key preserves the reply (surfaced by readiness:live).
|
|
6028
6071
|
// A host that granted other channels than this spawn asked for: the receipt carries both.
|
|
6029
6072
|
const acl = enrolled ? enrolledAcl({ allowSubscribe, allowPublish }, enrolled.material) : undefined;
|
|
6030
|
-
const okData = { name, agent, id: managed.id, mode: handle.kind, streamsTerminal:
|
|
6073
|
+
const okData = { name, agent, id: managed.id, mode: handle.kind, streamsTerminal: runtime.streamsTerminal, lifecycleUid, ...(role !== undefined ? { role } : {}), ...(opts.eventsNotice !== undefined ? { eventsNotice: opts.eventsNotice } : {}), ...(acl ? { acl } : {}), ...(readiness.operator !== undefined ? { waitingFor: readiness.operator } : {}) };
|
|
6031
6074
|
await hooks?.onOutcome?.({ kind: "succeeded", data: okData });
|
|
6032
6075
|
return { ok: true, data: okData };
|
|
6033
6076
|
}
|
|
@@ -6371,7 +6414,8 @@ export class Manager {
|
|
|
6371
6414
|
async orphanedResumeSeat(entry, principal, liveRoster) {
|
|
6372
6415
|
if (!this.auth || this.userMode || entry.identity.mode !== "static")
|
|
6373
6416
|
return undefined;
|
|
6374
|
-
|
|
6417
|
+
const runtime = this.runtimeFor(entry.launch.runtime);
|
|
6418
|
+
if (typeof runtime.reap !== "function")
|
|
6375
6419
|
return undefined;
|
|
6376
6420
|
if (liveRoster.some((p) => p.card.id === principal && p.lifecycleUid !== entry.identity.lifecycleUid))
|
|
6377
6421
|
return undefined;
|
|
@@ -6380,14 +6424,14 @@ export class Manager {
|
|
|
6380
6424
|
return undefined;
|
|
6381
6425
|
if (ownedBySibling(slot, this.managerInstanceId))
|
|
6382
6426
|
return undefined;
|
|
6383
|
-
return slot.runtime?.kind ===
|
|
6427
|
+
return slot.runtime?.kind === runtime.kind ? slot.runtime : undefined;
|
|
6384
6428
|
}
|
|
6385
6429
|
/** Reap a seat {@link orphanedResumeSeat} found, then wait for its principal to leave presence so
|
|
6386
6430
|
* the relaunch's readiness cannot match the dead seat's row. Returns the refusal when the reap
|
|
6387
6431
|
* proves nothing or the principal stays live, which means another process holds it. */
|
|
6388
6432
|
async reapOrphanedResumeSeat(principal, reference) {
|
|
6389
6433
|
try {
|
|
6390
|
-
const evidence = await requireRuntimeReap(this.
|
|
6434
|
+
const evidence = await requireRuntimeReap(this.runtimeFor(reference.kind), reference);
|
|
6391
6435
|
console.error(`resume: reaped orphaned seat ${reference.kind}:${reference.id} of retained principal "${principal}" (${evidence.detail})`);
|
|
6392
6436
|
}
|
|
6393
6437
|
catch (e) {
|
|
@@ -6413,8 +6457,8 @@ export class Manager {
|
|
|
6413
6457
|
try {
|
|
6414
6458
|
if (entry.space !== this.space)
|
|
6415
6459
|
return { ok: false, error: `retained agent ${entry.name} belongs to space "${entry.space}", not "${this.space}"` };
|
|
6416
|
-
if (entry.launch.runtime !== this.
|
|
6417
|
-
return { ok: false, error: `retained agent ${entry.name} requires runtime "${entry.launch.runtime}",
|
|
6460
|
+
if (entry.launch.runtime !== this.runtimeFor(entry.launch.runtime).kind)
|
|
6461
|
+
return { ok: false, error: `retained agent ${entry.name} requires runtime "${entry.launch.runtime}", which this manager cannot resolve` };
|
|
6418
6462
|
const nameErr = this.nameError(entry.name);
|
|
6419
6463
|
if (nameErr)
|
|
6420
6464
|
return { ok: false, error: nameErr };
|
|
@@ -6586,11 +6630,12 @@ export class Manager {
|
|
|
6586
6630
|
if (!Number.isSafeInteger(readinessTimeoutMs) || readinessTimeoutMs <= 0)
|
|
6587
6631
|
return { ok: false, error: `connector ${connector.name} declares invalid readinessTimeoutMs ${JSON.stringify(connector.readinessTimeoutMs)}; expected a positive safe integer` };
|
|
6588
6632
|
const resumeId = entry.identity.mode === "user" ? principalKey(entry.identity.owner, entry.identity.actor).key : entry.identity.id;
|
|
6589
|
-
const
|
|
6633
|
+
const runtime = this.runtimeFor(entry.launch.runtime);
|
|
6634
|
+
const custody = this.reserveCustody(runtime);
|
|
6590
6635
|
if (custody)
|
|
6591
6636
|
await this.recordSlotCustody({ name: entry.name, id: resumeId, lifecycleUid: entry.identity.lifecycleUid }, custody);
|
|
6592
6637
|
prepared.spawned = true;
|
|
6593
|
-
const handle = await this.spawnCustodied(entry.name, prepared.spec, entry.launch.cwd, custody);
|
|
6638
|
+
const handle = await this.spawnCustodied(runtime, entry.name, prepared.spec, entry.launch.cwd, custody);
|
|
6594
6639
|
const managed = {
|
|
6595
6640
|
name: entry.name,
|
|
6596
6641
|
role: entry.role,
|
|
@@ -6615,6 +6660,7 @@ export class Manager {
|
|
|
6615
6660
|
handle,
|
|
6616
6661
|
control: prepared.spec.control,
|
|
6617
6662
|
launch: {
|
|
6663
|
+
runtime: entry.launch.runtime,
|
|
6618
6664
|
source: entry.launch.source,
|
|
6619
6665
|
cwd: entry.launch.cwd,
|
|
6620
6666
|
model: entry.launch.model,
|
|
@@ -9220,14 +9266,14 @@ export class Manager {
|
|
|
9220
9266
|
/** Mint the custody reference for a seat this manager is about to spawn, BEFORE the processes
|
|
9221
9267
|
* exist. Absent for a runtime with no durable custody (there is nothing a successor could reap
|
|
9222
9268
|
* by reference), which is the only case that still spawns unreserved. */
|
|
9223
|
-
reserveCustody() {
|
|
9224
|
-
return isCustodialRuntime(
|
|
9269
|
+
reserveCustody(runtime) {
|
|
9270
|
+
return isCustodialRuntime(runtime) ? runtime.reserve() : undefined;
|
|
9225
9271
|
}
|
|
9226
9272
|
/** Spawn under a reserved reference and prove the runtime honoured it. A runtime that minted its
|
|
9227
9273
|
* own id instead would leave every durable record addressing a seat that does not exist, so the
|
|
9228
9274
|
* mismatch tears the new seat down and throws rather than returning an unaddressable handle. */
|
|
9229
|
-
async spawnCustodied(name, spec, cwd, reserved) {
|
|
9230
|
-
const handle =
|
|
9275
|
+
async spawnCustodied(runtime, name, spec, cwd, reserved) {
|
|
9276
|
+
const handle = runtime.spawn(name, spec, cwd, reserved);
|
|
9231
9277
|
if (reserved === undefined)
|
|
9232
9278
|
return handle;
|
|
9233
9279
|
const got = handle.reference;
|
|
@@ -9249,7 +9295,7 @@ export class Manager {
|
|
|
9249
9295
|
}
|
|
9250
9296
|
else {
|
|
9251
9297
|
try {
|
|
9252
|
-
const evidence = await requireRuntimeReap(
|
|
9298
|
+
const evidence = await requireRuntimeReap(runtime, got);
|
|
9253
9299
|
disposal = `the spawned seat was reaped (${evidence.detail})`;
|
|
9254
9300
|
}
|
|
9255
9301
|
catch (e) {
|
|
@@ -9263,7 +9309,7 @@ export class Manager {
|
|
|
9263
9309
|
: `the spawned seat could NOT be reaped: ${rejectionText(e)}`;
|
|
9264
9310
|
}
|
|
9265
9311
|
}
|
|
9266
|
-
throw new Error(`runtime "${
|
|
9312
|
+
throw new Error(`runtime "${runtime.kind}" reserved custody ${reserved.kind}:${reserved.id} for "${name}" but spawned ` +
|
|
9267
9313
|
`${got ? `${got.kind}:${got.id}` : "a handle with no reference"}; the recorded reference would address no seat, so ${disposal}`);
|
|
9268
9314
|
}
|
|
9269
9315
|
/** Persist what a successor needs to take this seat back if this process ends without stopping
|
|
@@ -9276,7 +9322,8 @@ export class Manager {
|
|
|
9276
9322
|
if (!this.auth || this.userMode)
|
|
9277
9323
|
return;
|
|
9278
9324
|
const policy = a.restart?.policy;
|
|
9279
|
-
const
|
|
9325
|
+
const runtime = this.runtimeFor(a.handle.kind);
|
|
9326
|
+
const adoptable = a.handle.reference !== undefined && typeof runtime.adopt === "function";
|
|
9280
9327
|
if (!policy && !adoptable)
|
|
9281
9328
|
return;
|
|
9282
9329
|
const agent = this.resumeEntryOf(a);
|
|
@@ -9325,8 +9372,8 @@ export class Manager {
|
|
|
9325
9372
|
return undefined;
|
|
9326
9373
|
if (record.instanceId !== this.managerInstanceId || record.agent.space !== this.space)
|
|
9327
9374
|
return undefined;
|
|
9328
|
-
if (record.agent.launch.runtime !==
|
|
9329
|
-
console.error(`! ${row.alias}: its seat ran on runtime "${record.agent.launch.runtime}" and
|
|
9375
|
+
if (record.agent.launch.runtime !== row.runtime?.kind) {
|
|
9376
|
+
console.error(`! ${row.alias}: its seat ran on runtime "${record.agent.launch.runtime}" and its slot names "${row.runtime?.kind ?? "none"}"; the lifecycle is retired, not restarted`);
|
|
9330
9377
|
return undefined;
|
|
9331
9378
|
}
|
|
9332
9379
|
return record;
|
|
@@ -9341,7 +9388,7 @@ export class Manager {
|
|
|
9341
9388
|
return "its record is not a static identity";
|
|
9342
9389
|
if (row.runtime === undefined)
|
|
9343
9390
|
return "its slot names no seat";
|
|
9344
|
-
const runtime = this.
|
|
9391
|
+
const runtime = this.runtimeFor(row.runtime.kind);
|
|
9345
9392
|
if (typeof runtime.adopt !== "function")
|
|
9346
9393
|
return `runtime "${runtime.kind}" cannot adopt a seat`;
|
|
9347
9394
|
// The credential is the manager's own lifecycle-keyed file, and its seed renews it.
|
|
@@ -9383,6 +9430,7 @@ export class Manager {
|
|
|
9383
9430
|
// The runtime names an adopted handle by what it holds; the record names the seat.
|
|
9384
9431
|
handle: { ...adopted, name: entry.name },
|
|
9385
9432
|
launch: {
|
|
9433
|
+
runtime: entry.launch.runtime,
|
|
9386
9434
|
source: entry.launch.source,
|
|
9387
9435
|
cwd: entry.launch.cwd,
|
|
9388
9436
|
model: entry.launch.model,
|
|
@@ -9425,7 +9473,7 @@ export class Manager {
|
|
|
9425
9473
|
// names is reaped first. A runtime that cannot prove it gone refuses, and the terminal retires it.
|
|
9426
9474
|
if (row.runtime !== undefined) {
|
|
9427
9475
|
try {
|
|
9428
|
-
const evidence = await requireRuntimeReap(this.
|
|
9476
|
+
const evidence = await requireRuntimeReap(this.runtimeFor(row.runtime.kind), row.runtime);
|
|
9429
9477
|
console.error(`${row.alias}: the seat its previous manager left ${evidence.detail}`);
|
|
9430
9478
|
}
|
|
9431
9479
|
catch (error) {
|
|
@@ -9470,7 +9518,8 @@ export class Manager {
|
|
|
9470
9518
|
// An unproven reap throws from here rather than printing, so it propagates into
|
|
9471
9519
|
// driveStaticRetirement's catch, which records the failure and HOLDS the name. That is the whole
|
|
9472
9520
|
// point of refusing: the alias must not be freed while a seat nobody proved gone may still run.
|
|
9473
|
-
const
|
|
9521
|
+
const runtime = this.runtimeFor(a.runtime.kind);
|
|
9522
|
+
const evidence = await requireRuntimeReap(runtime, a.runtime);
|
|
9474
9523
|
console.error(`static retirement ${a.name}: orphan seat process ${evidence.detail}`);
|
|
9475
9524
|
}
|
|
9476
9525
|
/** The static F1 terminal for one departed incarnation (Unit B): delegates the gate/head CAS
|
|
@@ -10667,7 +10716,7 @@ export class Manager {
|
|
|
10667
10716
|
// carried through verbatim, and the namespaced detail lets a caller act on the one fact
|
|
10668
10717
|
// without reading the wording. This is the same answer `input` gives a runtime that cannot
|
|
10669
10718
|
// write, for the same reason.
|
|
10670
|
-
if (!this.streamsTerminal)
|
|
10719
|
+
if (!this.runtimeFor(a.handle.kind).streamsTerminal)
|
|
10671
10720
|
throw new EpEnvelopeError("unimplemented", `the ${a.handle.kind} runtime streams no terminal, so agent "${a.name}" has none to attach: ${rejectionText(e)}`, [{ kind: RUNTIME_NO_TERMINAL_DETAIL, runtime: a.handle.kind }], "not-executed");
|
|
10672
10721
|
throw new EpEnvelopeError("failed-precondition", rejectionText(e), undefined, "not-executed");
|
|
10673
10722
|
}
|