@cotal-ai/manager 0.70.1 → 0.72.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/launch.js +2 -2
- package/dist/launch.js.map +1 -1
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +202 -165
- package/dist/manager.js.map +1 -1
- package/dist/resume.d.ts.map +1 -1
- package/dist/resume.js +17 -41
- package/dist/resume.js.map +1 -1
- package/dist/roster.d.ts +2 -0
- package/dist/roster.d.ts.map +1 -1
- package/dist/roster.js +9 -0
- package/dist/roster.js.map +1 -1
- package/dist/runtime/pty.d.ts +1 -1
- package/dist/runtime/pty.d.ts.map +1 -1
- package/dist/runtime/pty.js +11 -3
- package/dist/runtime/pty.js.map +1 -1
- package/dist/static-lifecycle.d.ts +13 -2
- package/dist/static-lifecycle.d.ts.map +1 -1
- package/dist/static-lifecycle.js +21 -25
- package/dist/static-lifecycle.js.map +1 -1
- package/package.json +12 -12
package/dist/manager.js
CHANGED
|
@@ -4,7 +4,7 @@ import { credsAuthenticator } from "@nats-io/transport-node";
|
|
|
4
4
|
import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
5
5
|
import { isAbsolute, join, dirname, resolve } from "node:path";
|
|
6
6
|
import Headless from "@xterm/headless";
|
|
7
|
-
import { CotalEndpoint, MANAGED_HANDOFF_KIND, accountFromCreds, credsClaims, DEFAULT_SERVER, DEV_OWNER, MANAGER_LEASE_RENEW_MS, STANDING_RENEWABLE_TTL_SEC, assertLifecycleToken, discardLaunchArtifacts, divergentSecretStoreNotice, parseDaemonStoreAnswer, parseSecretStoreIdentity, sameSecretStoreIdentity, agentFilePath, clearSpaceHistory, dialerFor, connectorServers, spawnEnvAllow, deprovisionAgent, DeprovisionError, isConcreteChannel, deprovisionTargetPrincipal, firstFreeName, spawnNameError, idFromCreds, inspectCredHealth, credsRenewalDelayMs, composeWirePersona, loadAgentFile, listPersonaCatalog, personaCatalogDescription, personaCatalogReadable, loadCotalConfig, modelPolicyRefusal, mintCreds, mintGeneration, mintAcceptedToken, openIssuedStore, acceptedBucket, issuedBucket, mintLifecycleUid, managedRetirementOpId, mkSecretDir, newIdentity, actionContext, parsePrincipalKey, principalKey, probeConnect, provisionAgent, provisionAgentDurables, registry, resolveAuthProvider, resolveReadAcl, runAgentBearer, saveAgentFile, subjectMatches, AUTH_ENDPOINT, EP_CMD_RETIRE_LIFECYCLE, controlServiceSubject, eventChannelPrincipal, resolveService, invokeCommand, } from "@cotal-ai/core";
|
|
7
|
+
import { CotalEndpoint, canonicalJson, MANAGED_HANDOFF_KIND, accountFromCreds, credsClaims, DEFAULT_SERVER, DEV_OWNER, MANAGER_LEASE_RENEW_MS, STANDING_RENEWABLE_TTL_SEC, assertLifecycleToken, discardLaunchArtifacts, divergentSecretStoreNotice, parseDaemonStoreAnswer, parseSecretStoreIdentity, sameSecretStoreIdentity, agentFilePath, clearSpaceHistory, dialerFor, connectorServers, spawnEnvAllow, deprovisionAgent, DeprovisionError, isConcreteChannel, deprovisionTargetPrincipal, firstFreeName, spawnNameError, idFromCreds, inspectCredHealth, credsRenewalDelayMs, composeWirePersona, loadAgentFile, listPersonaCatalog, personaCatalogDescription, personaCatalogReadable, loadCotalConfig, modelPolicyRefusal, mintCreds, mintGeneration, mintAcceptedToken, openIssuedStore, acceptedBucket, issuedBucket, mintLifecycleUid, managedRetirementOpId, mkSecretDir, newIdentity, actionContext, parsePrincipalKey, principalKey, probeConnect, provisionAgent, provisionAgentDurables, registry, resolveAuthProvider, resolveReadAcl, runAgentBearer, saveAgentFile, subjectMatches, AUTH_ENDPOINT, EP_CMD_RETIRE_LIFECYCLE, controlServiceSubject, eventChannelPrincipal, resolveService, invokeCommand, } from "@cotal-ai/core";
|
|
8
8
|
import { agentAuthState, agentCredsDir, agentLifecycleSecretFilePaths, agentSecretFilePaths, agentSecretKeyForFile, authDir, claimManagerSiblingIdentities, connectorInstallHint, DELIVERY_CREDS_KIND, extensionConnectors, findCotalRoot, getSpaceAuth, hasUserAuthState, loadExtensionsManifest, loadManagerInstanceIdentity, loadMeshes, localTrustOfSpace, manifestExtensionNames, materializeFromManifest, materializeSecretToFile, MEMBERSHIP_RW_CREDS_KIND, mergeLaunchOptions, remintDaemonCreds, resolveAgentType, resolveOnPath, createManagerInstanceIdentity, spaceMaterialKey, SYSTEM_CREDS_FILES, userAuthStateDir, workspaceSecretStore, writeRenewalRecord } from "@cotal-ai/workspace";
|
|
9
9
|
import { createRuntime, isCustodialRuntime, requireRuntimeAdopt, requireRuntimeReap, RuntimeReapUnproven, } from "./runtime/index.js";
|
|
10
10
|
import { AttachEndpoint } from "./attach-endpoint.js";
|
|
@@ -22,7 +22,7 @@ import { TranscriptReceiver } from "./transcript-receive.js";
|
|
|
22
22
|
// manager-side adapter (transport + slot orchestration + the F1 terminal) — see static-lifecycle.ts.
|
|
23
23
|
import { jetstream, jetstreamManager } from "@nats-io/jetstream";
|
|
24
24
|
import { Kvm } from "@nats-io/kv";
|
|
25
|
-
import { recordsBucket, epAuthBucket, ensureAuthorityStores, ensureContractStore, createEndpointStreams, contractStoreContext, publishContractArtifact, contractArtifactCanonicalBytes, standaloneConnectOpts,
|
|
25
|
+
import { recordsBucket, epAuthBucket, ensureAuthorityStores, ensureContractStore, createEndpointStreams, contractStoreContext, publishContractArtifact, contractArtifactCanonicalBytes, standaloneConnectOpts, rawDigest, STANDING_RENEWABLE_TTL_SEC as MANAGED_STATIC_TTL_SEC, newArtifactSigner, RotatingSigner, generationAnchor, sessionsBucket, SESSION_GRANT_MAX_TTL_MS, REMOTE_MANAGER_IDENTITY_NAMES, } from "@cotal-ai/core";
|
|
26
26
|
// P2 item 6: the manager's ONE §13.6 session plane — offer mint + one-use redeem + PTY-bridge
|
|
27
27
|
// standup for `attach`, over a dedicated standing session-LEDGER connection (the byte rails ride
|
|
28
28
|
// per-session credentials on their own short-lived connections).
|
|
@@ -32,7 +32,7 @@ import { ManagerSessionPlane, openSessionLedgerKv } from "./session/index.js";
|
|
|
32
32
|
// the register/authorize/serve seams, all driven over a scoped one-shot executor connection.
|
|
33
33
|
import { provisionEndpointGateOpen, endpointRegistrationBarrier, serveIssuanceGateKv, commitSiblingIssuance, markLedgerRowRevoked, epcredRowKey, epgateKey, parseEndpointGate, readEndpointGateGeneration, registerServingInstance, deregisterServiceInstance, serveEndpoint, bindGoal, createGoal, transitionGoal, commitGoalResult, requestGoalCancel, goalAlreadyTerminal, settleGoalUncertain, readGoalResult, readGoalStatus, readGoalSpec, recordGoalIndex, readGoalIndex, clearGoalIndex, listGoalIndex, mintCheckpoint, resumeCheckpoint, readCheckpointSettle, readCheckpointSpec, expireCheckpoint, GOAL_TERMINAL_STATES, goalRefOf, goalProgressTopic, epeSubject, submissionFingerprint, EpEnvelopeError, lifecycleBlocked, lifecycleBlockedFrom, renderLifecycleBlocked, } from "@cotal-ai/core";
|
|
34
34
|
import { MANAGER_ENDPOINT, managerClusterArtifacts, managerCommandDefs, managerContractArtifactValues } from "./manager-service-contract.js";
|
|
35
|
-
import { staticLifecycleTransport, activateStaticLifecycle, runStaticTerminal, readStaticSlot, casStaticSlot, recordSlotCredential, appendStaticCredentialRow, planStaticSlotResume, ownedBySibling, observeStaticSlot, listStaticSlotObservations, renderStaticSlotObservation, StaticSlotReadError, STATIC_SLOT_READ_FAILED_DETAIL, } from "./static-lifecycle.js";
|
|
35
|
+
import { staticLifecycleTransport, activateStaticLifecycle, runStaticTerminal, readStaticSlot, casStaticSlot, recordSlotCredential, appendStaticCredentialRow, planStaticSlotResume, ownedBySibling, observeStaticSlot, listStaticSlotObservations, walkStaticSlots, renderStaticSlotObservation, StaticSlotReadError, STATIC_SLOT_READ_FAILED_DETAIL, } from "./static-lifecycle.js";
|
|
36
36
|
/** Minimum slot lifetime for rate-flooring (P4c). A slot freed (by despawn OR natural exit/reap)
|
|
37
37
|
* before living this long leaves a cooling stamp that still counts toward the ceiling until it
|
|
38
38
|
* expires — so churn (spawn↔despawn or spawn↔fast-exit) can't outrun the concurrency bound. */
|
|
@@ -126,9 +126,11 @@ function retireOpId(lifecycleUid) {
|
|
|
126
126
|
* dash) — what {@link Manager.psOwnerFilter} returns for an unparseable caller so a malformed
|
|
127
127
|
* principal fail-closes to an empty `ps` instead of an unbounded one. */
|
|
128
128
|
const NO_OWNER_MATCHES = "-no-owner-";
|
|
129
|
-
/** A caught value's text for a refusal. A host-supplied store or callback may
|
|
130
|
-
* including one whose `message` is a Symbol or whose `message`
|
|
131
|
-
*
|
|
129
|
+
/** A caught value's text for a refusal or a log line. A host-supplied store, runtime or callback may
|
|
130
|
+
* reject with any value, including `null` or one whose `message` is a Symbol or whose `message`
|
|
131
|
+
* getter or `toString` throws. A handler that throws while building its text skips the work after
|
|
132
|
+
* it, and on a detached chain ends the manager with an unhandled rejection, so the coercion to text
|
|
133
|
+
* runs inside the guard. */
|
|
132
134
|
function rejectionText(e) {
|
|
133
135
|
try {
|
|
134
136
|
return String(e?.message ?? e);
|
|
@@ -137,6 +139,34 @@ function rejectionText(e) {
|
|
|
137
139
|
return "an unreadable rejection";
|
|
138
140
|
}
|
|
139
141
|
}
|
|
142
|
+
/** A caught value as a lifecycle envelope, or undefined when it is not one. A thrown Proxy can throw
|
|
143
|
+
* from `instanceof` itself, so the test runs inside the guard. */
|
|
144
|
+
function caughtEnvelope(e) {
|
|
145
|
+
try {
|
|
146
|
+
return e instanceof EpEnvelopeError ? e : undefined;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/** The failed terminal a post-accept fallback commits for `error` and `source`'s optional details.
|
|
153
|
+
* `commitGoalResult` refuses a payload that is not interchangeable JSON, and this terminal must commit
|
|
154
|
+
* whatever failed, so a lone surrogate in the text becomes U+FFFD and details it cannot read or carry
|
|
155
|
+
* (a Proxy's throwing getter, an accessor, a cycle) are dropped. A Proxy can answer the check and the
|
|
156
|
+
* serializer differently, so the detached copy is checked again before it commits. */
|
|
157
|
+
function failedTerminal(error, source) {
|
|
158
|
+
const text = error.replace(/\p{Cs}/gu, "\uFFFD");
|
|
159
|
+
try {
|
|
160
|
+
const details = source?.details;
|
|
161
|
+
if (details) {
|
|
162
|
+
const copy = JSON.parse(canonicalJson(details));
|
|
163
|
+
canonicalJson(copy);
|
|
164
|
+
return { error: text, details: copy };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch { /* unreadable or not interchangeable */ }
|
|
168
|
+
return { error: text };
|
|
169
|
+
}
|
|
140
170
|
/** Run one cleanup step, recording its failure in `failed` as `<what>: <reason>`. A step that threw
|
|
141
171
|
* would otherwise skip every step after it, and a swallowed one would leave nothing to report. */
|
|
142
172
|
async function attemptCleanup(failed, what, step) {
|
|
@@ -159,6 +189,18 @@ function withTimeout(p, ms, msg) {
|
|
|
159
189
|
function sameStrings(a, b) {
|
|
160
190
|
return JSON.stringify([...(a ?? [])].sort()) === JSON.stringify([...(b ?? [])].sort());
|
|
161
191
|
}
|
|
192
|
+
/** The caller keeps the arrays it passed, so a launch form is admitted with its own copies: a later
|
|
193
|
+
* write to the caller's array cannot change what the manager grants, shares or preserves. */
|
|
194
|
+
function ownLists(form) {
|
|
195
|
+
return {
|
|
196
|
+
...form,
|
|
197
|
+
...(form.subscribe && { subscribe: [...form.subscribe] }),
|
|
198
|
+
...(form.allowSubscribe && { allowSubscribe: [...form.allowSubscribe] }),
|
|
199
|
+
...(form.allowPublish && { allowPublish: [...form.allowPublish] }),
|
|
200
|
+
...(form.capabilities && { capabilities: [...form.capabilities] }),
|
|
201
|
+
...(form.shareTools && { shareTools: [...form.shareTools] }),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
162
204
|
/** Operator-facing phrasing per cause. Kept beside the union so adding a member without a sentence
|
|
163
205
|
* is a type error rather than a blank in the log. The stop family's sentences carry the principal
|
|
164
206
|
* from the cause, so they render through {@link STOP_CAUSE_TEXT} under the same exhaustive-Record
|
|
@@ -899,7 +941,7 @@ export class Manager {
|
|
|
899
941
|
await this.attach.stop();
|
|
900
942
|
throw new Error(held
|
|
901
943
|
? `manager instance ${this.managerInstanceId} already serves space "${this.space}" from ${held.root === this.leaseInfo.root ? "this" : "another"} workspace root (${held.runtime}, pid ${held.pid}, root ${held.root}) - stop it first before restarting the same instance`
|
|
902
|
-
: `could not acquire the manager lease for space "${this.space}": ${e
|
|
944
|
+
: `could not acquire the manager lease for space "${this.space}": ${rejectionText(e)}`);
|
|
903
945
|
}
|
|
904
946
|
this.leaseTimer = setInterval(() => { void this.renewLease(); }, MANAGER_LEASE_RENEW_MS);
|
|
905
947
|
this.leaseTimer.unref?.();
|
|
@@ -936,7 +978,7 @@ export class Manager {
|
|
|
936
978
|
// attempt returns.
|
|
937
979
|
const startupReconcile = this.auth && !this.userMode ? this.reconcileStaticLifecycles() : undefined;
|
|
938
980
|
if (startupReconcile)
|
|
939
|
-
void startupReconcile.catch((e) => console.error(`! ${STARTUP_RECONCILING}: ${e
|
|
981
|
+
void startupReconcile.catch((e) => console.error(`! ${STARTUP_RECONCILING}: ${rejectionText(e)} - no per-alias retry could be planned; a later manager start re-reads unfinished durable terminals`));
|
|
940
982
|
// P2 item 1 (1d): the manager serves NO ctl tiers - its whole control surface is the v0.4
|
|
941
983
|
// service endpoint registered below. The old three-tier rail (self/manager/admin) is deleted;
|
|
942
984
|
// `ctl.delivery`/`ctl.delivery-admin` (the delivery daemon) and `ctl.auth-admin` (the auth
|
|
@@ -987,13 +1029,13 @@ export class Manager {
|
|
|
987
1029
|
await this.renewRemoteExecutor();
|
|
988
1030
|
}
|
|
989
1031
|
catch (e) {
|
|
990
|
-
console.error(`! remote manager renewal pass failed: ${e
|
|
1032
|
+
console.error(`! remote manager renewal pass failed: ${rejectionText(e)}`);
|
|
991
1033
|
}
|
|
992
1034
|
try {
|
|
993
1035
|
await this.runHosting?.renew();
|
|
994
1036
|
}
|
|
995
1037
|
catch (e) {
|
|
996
|
-
console.error(`! remote run-hosting renewal pass failed: ${e
|
|
1038
|
+
console.error(`! remote run-hosting renewal pass failed: ${rejectionText(e)}`);
|
|
997
1039
|
}
|
|
998
1040
|
}, intervalMs);
|
|
999
1041
|
this.credRenewTimer.unref?.();
|
|
@@ -1104,7 +1146,7 @@ export class Manager {
|
|
|
1104
1146
|
reply = await this.ep.requestDeliveryAdmin("reloadStoreIdentity", {}, timeoutMs);
|
|
1105
1147
|
}
|
|
1106
1148
|
catch (e) {
|
|
1107
|
-
const msg = e
|
|
1149
|
+
const msg = rejectionText(e);
|
|
1108
1150
|
if (isAbsentDeliveryAdmin(msg))
|
|
1109
1151
|
return this.absentByLeaseRow(isUnansweredDeliveryAdmin(e));
|
|
1110
1152
|
const failure = `could not challenge the delivery daemon's SecretStore: ${msg}`;
|
|
@@ -1117,7 +1159,7 @@ export class Manager {
|
|
|
1117
1159
|
answer = parseDaemonStoreAnswer(reply.data);
|
|
1118
1160
|
}
|
|
1119
1161
|
catch (e) {
|
|
1120
|
-
throw new Error(`delivery daemon named an unreadable SecretStore: ${e
|
|
1162
|
+
throw new Error(`delivery daemon named an unreadable SecretStore: ${rejectionText(e)}. A daemon older ` +
|
|
1121
1163
|
`than #1694 replies with a bare store identity and no answerer binding; this manager ` +
|
|
1122
1164
|
`cannot establish which process answered, so nothing reminted - upgrade the delivery daemon`);
|
|
1123
1165
|
}
|
|
@@ -1173,7 +1215,7 @@ export class Manager {
|
|
|
1173
1215
|
}
|
|
1174
1216
|
catch (e) {
|
|
1175
1217
|
throw new Error(`could not read the delivery lease row to settle whether the delivery daemon is absent ` +
|
|
1176
|
-
`(${e
|
|
1218
|
+
`(${rejectionText(e)}) - absence is undetermined, nothing reminted`);
|
|
1177
1219
|
}
|
|
1178
1220
|
const holder = entry?.info.holder;
|
|
1179
1221
|
if (holder !== undefined && holder !== "") {
|
|
@@ -1198,7 +1240,7 @@ export class Manager {
|
|
|
1198
1240
|
this.daemonRenewalOwner = held;
|
|
1199
1241
|
}
|
|
1200
1242
|
catch (e) {
|
|
1201
|
-
console.error(`! could not refresh the daemon renewal lease: ${e
|
|
1243
|
+
console.error(`! could not refresh the daemon renewal lease: ${rejectionText(e)} - ownership is re-decided on the next pass`);
|
|
1202
1244
|
}
|
|
1203
1245
|
}
|
|
1204
1246
|
/** Decide whether THIS manager owns the daemon's credential renewal (#1634). Both conditions are
|
|
@@ -1284,7 +1326,7 @@ export class Manager {
|
|
|
1284
1326
|
return true;
|
|
1285
1327
|
}
|
|
1286
1328
|
catch (e) {
|
|
1287
|
-
console.error(`! manager ${label} re-dial attempt failed: ${e
|
|
1329
|
+
console.error(`! manager ${label} re-dial attempt failed: ${rejectionText(e)}`);
|
|
1288
1330
|
}
|
|
1289
1331
|
}
|
|
1290
1332
|
return false;
|
|
@@ -1337,7 +1379,7 @@ export class Manager {
|
|
|
1337
1379
|
: { ok: false, error: reply.error, detail: reply.data };
|
|
1338
1380
|
}
|
|
1339
1381
|
catch (e) {
|
|
1340
|
-
adoption = { ok: false, error: `no delivery-admin responder (${e
|
|
1382
|
+
adoption = { ok: false, error: `no delivery-admin responder (${rejectionText(e)}) - the daemon's 75% re-read backstop adopts the re-signed file` };
|
|
1341
1383
|
}
|
|
1342
1384
|
}
|
|
1343
1385
|
for (const r of results.filter((x) => !x.ok && !x.skipped))
|
|
@@ -1380,7 +1422,7 @@ export class Manager {
|
|
|
1380
1422
|
await this.renewManagedStaticCred(a);
|
|
1381
1423
|
}
|
|
1382
1424
|
catch (e) {
|
|
1383
|
-
console.error(`! managed cred renewal ${a.name}: ${e
|
|
1425
|
+
console.error(`! managed cred renewal ${a.name}: ${rejectionText(e)} - the agent dies loud at this cred's expiry unless it is reminted`);
|
|
1384
1426
|
}
|
|
1385
1427
|
}
|
|
1386
1428
|
}
|
|
@@ -1408,7 +1450,7 @@ export class Manager {
|
|
|
1408
1450
|
}
|
|
1409
1451
|
}
|
|
1410
1452
|
catch (e) {
|
|
1411
|
-
console.error(`! endpoint-serve renewal: ${e
|
|
1453
|
+
console.error(`! endpoint-serve renewal: ${rejectionText(e)} - the manager's service endpoint dies loud at this cred's expiry unless it is re-registered`);
|
|
1412
1454
|
}
|
|
1413
1455
|
}
|
|
1414
1456
|
// The manager is also the goal-writer's renewal owner — re-mint the SAME
|
|
@@ -1427,7 +1469,7 @@ export class Manager {
|
|
|
1427
1469
|
}
|
|
1428
1470
|
}
|
|
1429
1471
|
catch (e) {
|
|
1430
|
-
console.error(`! goal-writer renewal: ${e
|
|
1472
|
+
console.error(`! goal-writer renewal: ${rejectionText(e)} - spawn-as-action stops accepting at this cred's expiry unless the manager restarts`);
|
|
1431
1473
|
}
|
|
1432
1474
|
}
|
|
1433
1475
|
// P2 item 6: the manager is also the session-ledger's renewal owner — re-mint the SAME nkey
|
|
@@ -1449,12 +1491,12 @@ export class Manager {
|
|
|
1449
1491
|
}
|
|
1450
1492
|
}
|
|
1451
1493
|
catch (e) {
|
|
1452
|
-
console.error(`! session-ledger renewal: ${e
|
|
1494
|
+
console.error(`! session-ledger renewal: ${rejectionText(e)} - attach stops establishing sessions at this cred's expiry unless the manager restarts`);
|
|
1453
1495
|
}
|
|
1454
1496
|
}
|
|
1455
1497
|
}
|
|
1456
1498
|
catch (e) {
|
|
1457
|
-
console.error(`! credential renewal pass failed: ${e
|
|
1499
|
+
console.error(`! credential renewal pass failed: ${rejectionText(e)}`);
|
|
1458
1500
|
}
|
|
1459
1501
|
finally {
|
|
1460
1502
|
release();
|
|
@@ -1472,7 +1514,7 @@ export class Manager {
|
|
|
1472
1514
|
this.remoteExecutorCreds = await this.remoteAuthority.renewExecutor();
|
|
1473
1515
|
}
|
|
1474
1516
|
catch (e) {
|
|
1475
|
-
console.error(`! remote manager executor renewal: ${e
|
|
1517
|
+
console.error(`! remote manager executor renewal: ${rejectionText(e)} - registration maintenance and clean deregistration remain unavailable until renewal succeeds`);
|
|
1476
1518
|
if (force)
|
|
1477
1519
|
throw e;
|
|
1478
1520
|
}
|
|
@@ -1543,7 +1585,7 @@ export class Manager {
|
|
|
1543
1585
|
// endpoint's own reconnect loop retries with the adopted credential, not unadopted debt.
|
|
1544
1586
|
this.remoteRenewalDebt = undefined;
|
|
1545
1587
|
await Promise.all([
|
|
1546
|
-
this.ep.reconnect().catch((e) => console.error(`! remote manager supervisor reconnect after renewal: ${e
|
|
1588
|
+
this.ep.reconnect().catch((e) => console.error(`! remote manager supervisor reconnect after renewal: ${rejectionText(e)}`)),
|
|
1547
1589
|
this.pushRenewedCreds(this.serviceServe.nc),
|
|
1548
1590
|
...(this.goalWriter ? [this.pushRenewedCreds(this.goalWriter.nc)] : []),
|
|
1549
1591
|
...(this.sessionLedgerConn ? [this.pushRenewedCreds(this.sessionLedgerConn.nc)] : []),
|
|
@@ -1558,8 +1600,8 @@ export class Manager {
|
|
|
1558
1600
|
return [];
|
|
1559
1601
|
} })
|
|
1560
1602
|
: [];
|
|
1561
|
-
this.remoteRenewalDebt = { at: Date.now(), processEpoch, reason: e
|
|
1562
|
-
console.error(`! remote manager all-duty renewal: ${e
|
|
1603
|
+
this.remoteRenewalDebt = { at: Date.now(), processEpoch, reason: rejectionText(e), unadoptedSubjects };
|
|
1604
|
+
console.error(`! remote manager all-duty renewal: ${rejectionText(e)} - no unsigned or local replacement is available`);
|
|
1563
1605
|
if (force)
|
|
1564
1606
|
throw e;
|
|
1565
1607
|
}
|
|
@@ -1631,7 +1673,7 @@ export class Manager {
|
|
|
1631
1673
|
trackDeprovision(a, context = "") {
|
|
1632
1674
|
this.lifecycleInFlight++;
|
|
1633
1675
|
void this.deprovision(a)
|
|
1634
|
-
.catch((e) => console.error(`deprovision${context ? ` ${context}` : ""} ${a.name} (${a.id}): ${e
|
|
1676
|
+
.catch((e) => console.error(`deprovision${context ? ` ${context}` : ""} ${a.name} (${a.id}): ${rejectionText(e)}`))
|
|
1635
1677
|
.finally(() => this.releaseLifecycle());
|
|
1636
1678
|
}
|
|
1637
1679
|
async awaitLifecycleDrain() {
|
|
@@ -1736,7 +1778,7 @@ export class Manager {
|
|
|
1736
1778
|
parseResumeControlArgs({ attemptId, inventory });
|
|
1737
1779
|
}
|
|
1738
1780
|
catch (e) {
|
|
1739
|
-
failures.push({ name: "<inventory>", id: attemptId, error: `prepared inventory would be rejected at resume: ${e
|
|
1781
|
+
failures.push({ name: "<inventory>", id: attemptId, error: `prepared inventory would be rejected at resume: ${rejectionText(e)}` });
|
|
1740
1782
|
}
|
|
1741
1783
|
this.preservationInventory = inventory;
|
|
1742
1784
|
this.preservationFailures = failures;
|
|
@@ -1821,7 +1863,7 @@ export class Manager {
|
|
|
1821
1863
|
a.handle.stop({ graceful: false });
|
|
1822
1864
|
}
|
|
1823
1865
|
catch (e) {
|
|
1824
|
-
failures.push({ name: a.name, id: a.id, error: `stop failed: ${e
|
|
1866
|
+
failures.push({ name: a.name, id: a.id, error: `stop failed: ${rejectionText(e)}` });
|
|
1825
1867
|
return;
|
|
1826
1868
|
}
|
|
1827
1869
|
try {
|
|
@@ -1830,7 +1872,7 @@ export class Manager {
|
|
|
1830
1872
|
this.agents.delete(a.name);
|
|
1831
1873
|
}
|
|
1832
1874
|
catch (e) {
|
|
1833
|
-
failures.push({ name: a.name, id: a.id, error: e
|
|
1875
|
+
failures.push({ name: a.name, id: a.id, error: rejectionText(e) });
|
|
1834
1876
|
}
|
|
1835
1877
|
}));
|
|
1836
1878
|
if (failures.length === 0)
|
|
@@ -1875,7 +1917,7 @@ export class Manager {
|
|
|
1875
1917
|
return `retained reference is not a regular non-symlink file: ${path}`;
|
|
1876
1918
|
}
|
|
1877
1919
|
catch (e) {
|
|
1878
|
-
return `retained reference unavailable: ${path} (${e
|
|
1920
|
+
return `retained reference unavailable: ${path} (${rejectionText(e)})`;
|
|
1879
1921
|
}
|
|
1880
1922
|
}
|
|
1881
1923
|
if (process.platform !== "win32") {
|
|
@@ -1904,7 +1946,7 @@ export class Manager {
|
|
|
1904
1946
|
}
|
|
1905
1947
|
}
|
|
1906
1948
|
catch (e) {
|
|
1907
|
-
return `retained reference cannot be hashed: ${e
|
|
1949
|
+
return `retained reference cannot be hashed: ${rejectionText(e)}`;
|
|
1908
1950
|
}
|
|
1909
1951
|
return undefined;
|
|
1910
1952
|
}
|
|
@@ -2019,11 +2061,11 @@ export class Manager {
|
|
|
2019
2061
|
await this.awaitHandleExit(a.handle);
|
|
2020
2062
|
}
|
|
2021
2063
|
catch (e) {
|
|
2022
|
-
failures.push(`${a.name}: ${e
|
|
2064
|
+
failures.push(`${a.name}: ${rejectionText(e)}`);
|
|
2023
2065
|
}
|
|
2024
2066
|
}));
|
|
2025
2067
|
// Deprovision EVERY snapshot entry regardless of whether its stop failed (allSettled + a loud log).
|
|
2026
|
-
await Promise.allSettled(managed.filter((a) => !a.suppressCleanup).map((a) => this.deprovision({ ...a, ...(a.handedOff ? { delegatedHandle: a.handle } : {}) }).catch((e) => console.error(`deprovision ${a.name} (${a.id}) on shutdown: ${e
|
|
2068
|
+
await Promise.allSettled(managed.filter((a) => !a.suppressCleanup).map((a) => this.deprovision({ ...a, ...(a.handedOff ? { delegatedHandle: a.handle } : {}) }).catch((e) => console.error(`deprovision ${a.name} (${a.id}) on shutdown: ${rejectionText(e)}`))));
|
|
2027
2069
|
if (failures.length)
|
|
2028
2070
|
throw new Error(`manager shutdown could not prove every seat exited: ${failures.join("; ")}`);
|
|
2029
2071
|
}
|
|
@@ -2040,7 +2082,7 @@ export class Manager {
|
|
|
2040
2082
|
this.agents.delete(a.name);
|
|
2041
2083
|
}
|
|
2042
2084
|
catch (e) {
|
|
2043
|
-
failures.push(`${a.name}: ${e
|
|
2085
|
+
failures.push(`${a.name}: ${rejectionText(e)}`);
|
|
2044
2086
|
}
|
|
2045
2087
|
}
|
|
2046
2088
|
return failures;
|
|
@@ -2059,7 +2101,7 @@ export class Manager {
|
|
|
2059
2101
|
a.handle.stop({ graceful: false });
|
|
2060
2102
|
}
|
|
2061
2103
|
catch (e) {
|
|
2062
|
-
failures.push(`${a.name}: stop failed: ${e
|
|
2104
|
+
failures.push(`${a.name}: stop failed: ${rejectionText(e)}`);
|
|
2063
2105
|
}
|
|
2064
2106
|
try {
|
|
2065
2107
|
await this.awaitHandleExit(a.handle);
|
|
@@ -2067,7 +2109,7 @@ export class Manager {
|
|
|
2067
2109
|
this.agents.delete(a.name);
|
|
2068
2110
|
}
|
|
2069
2111
|
catch (e) {
|
|
2070
|
-
failures.push(`${a.name}: ${e
|
|
2112
|
+
failures.push(`${a.name}: ${rejectionText(e)}`);
|
|
2071
2113
|
}
|
|
2072
2114
|
}));
|
|
2073
2115
|
if (failures.length)
|
|
@@ -2132,7 +2174,7 @@ export class Manager {
|
|
|
2132
2174
|
}
|
|
2133
2175
|
}
|
|
2134
2176
|
catch (e) {
|
|
2135
|
-
seatFailure = e;
|
|
2177
|
+
seatFailure = rejectionText(e);
|
|
2136
2178
|
}
|
|
2137
2179
|
// Every step below runs even when an earlier one fails, so a failed stop still closes this
|
|
2138
2180
|
// process's connections and listener (#2290). Failures are collected and thrown at the end.
|
|
@@ -2142,12 +2184,12 @@ export class Manager {
|
|
|
2142
2184
|
await run();
|
|
2143
2185
|
}
|
|
2144
2186
|
catch (e) {
|
|
2145
|
-
failures.push(`${name}: ${e
|
|
2187
|
+
failures.push(`${name}: ${rejectionText(e)}`);
|
|
2146
2188
|
}
|
|
2147
2189
|
};
|
|
2148
2190
|
// A seat that may still be alive keeps this instance's leases and registration (see
|
|
2149
2191
|
// teardownManagedAgents): they lapse on their TTL instead of being handed to a successor.
|
|
2150
|
-
if (
|
|
2192
|
+
if (seatFailure === undefined) {
|
|
2151
2193
|
await step("release manager lease", () => this.releaseOwnManagerLease());
|
|
2152
2194
|
// #1634: hand the renewal lease back on a clean stop so a sibling picks it up on its next pass
|
|
2153
2195
|
// rather than waiting out the bucket TTL. A non-owner holds no revision and this is a no-op.
|
|
@@ -2163,15 +2205,15 @@ export class Manager {
|
|
|
2163
2205
|
// released run's status write is the last thing this incarnation says about it.
|
|
2164
2206
|
await step("stop run hosting", () => this.runHosting?.stop());
|
|
2165
2207
|
this.runHosting = undefined;
|
|
2166
|
-
if (registrationRevision !== undefined &&
|
|
2208
|
+
if (registrationRevision !== undefined && seatFailure === undefined)
|
|
2167
2209
|
await step("deregister service", () => this.deregisterServiceOnStop(registrationRevision));
|
|
2168
2210
|
await step("stop goal writer", () => this.stopGoalWriter());
|
|
2169
2211
|
await step("stop session plane", () => this.stopSessionPlane());
|
|
2170
2212
|
await step("stop endpoint", () => this.ep.stop());
|
|
2171
2213
|
await step("stop attach endpoint", () => this.attach.stop());
|
|
2172
2214
|
const also = failures.length ? `; teardown also failed: ${failures.join("; ")}` : "";
|
|
2173
|
-
if (seatFailure)
|
|
2174
|
-
throw new Error(`${seatFailure
|
|
2215
|
+
if (seatFailure !== undefined)
|
|
2216
|
+
throw new Error(`${seatFailure}${also}`);
|
|
2175
2217
|
if (releaseFailures.length)
|
|
2176
2218
|
throw new Error(`manager shutdown could not release every detachable seat: ${releaseFailures.join("; ")}${also}`);
|
|
2177
2219
|
if (failures.length)
|
|
@@ -2246,7 +2288,7 @@ export class Manager {
|
|
|
2246
2288
|
// `absent` is silent: there was nothing registered to remove, which is not news at shutdown.
|
|
2247
2289
|
}
|
|
2248
2290
|
catch (e) {
|
|
2249
|
-
console.error(`! could not deregister manager instance ${iid}: ${e
|
|
2291
|
+
console.error(`! could not deregister manager instance ${iid}: ${rejectionText(e)}\n` +
|
|
2250
2292
|
` Its registration now outlives this process and will be frozen into every class scatter in space "${this.space}", each paying the full deadline.\n` +
|
|
2251
2293
|
` NEXT: remove it with \`cotal deregister-instance --instance ${iid}\` once this process is gone.`);
|
|
2252
2294
|
}
|
|
@@ -2321,7 +2363,7 @@ export class Manager {
|
|
|
2321
2363
|
return;
|
|
2322
2364
|
}
|
|
2323
2365
|
catch (renewError) {
|
|
2324
|
-
const why = renewError
|
|
2366
|
+
const why = rejectionText(renewError);
|
|
2325
2367
|
const verdict = await this.reconcileLease();
|
|
2326
2368
|
switch (verdict.kind) {
|
|
2327
2369
|
case "held":
|
|
@@ -2346,7 +2388,7 @@ export class Manager {
|
|
|
2346
2388
|
}
|
|
2347
2389
|
catch (e) {
|
|
2348
2390
|
this.leaseState = before;
|
|
2349
|
-
this.noteLease("gone", `found its liveness lease key gone (renew: ${why}) and could not re-acquire it yet (${e
|
|
2391
|
+
this.noteLease("gone", `found its liveness lease key gone (renew: ${why}) and could not re-acquire it yet (${rejectionText(e)}); serving, retrying`);
|
|
2350
2392
|
}
|
|
2351
2393
|
return;
|
|
2352
2394
|
}
|
|
@@ -2385,7 +2427,7 @@ export class Manager {
|
|
|
2385
2427
|
current = await this.ep.readOwnManagerLease(this.managerInstanceId);
|
|
2386
2428
|
}
|
|
2387
2429
|
catch (e) {
|
|
2388
|
-
return { kind: "unknown", why: e
|
|
2430
|
+
return { kind: "unknown", why: rejectionText(e) };
|
|
2389
2431
|
}
|
|
2390
2432
|
if (current === undefined)
|
|
2391
2433
|
return { kind: "gone" };
|
|
@@ -2402,7 +2444,7 @@ export class Manager {
|
|
|
2402
2444
|
args = parseResumeFinalizeArgs(rawArgs);
|
|
2403
2445
|
}
|
|
2404
2446
|
catch (e) {
|
|
2405
|
-
return { ok: false, error: e
|
|
2447
|
+
return { ok: false, error: rejectionText(e) };
|
|
2406
2448
|
}
|
|
2407
2449
|
if (!this.resumeAttemptId || this.resumeAttemptId !== args.attemptId)
|
|
2408
2450
|
return { ok: false, error: `manager expects resume attempt ${this.resumeAttemptId ?? "<none>"}, not ${args.attemptId}` };
|
|
@@ -2420,7 +2462,7 @@ export class Manager {
|
|
|
2420
2462
|
inactive = this.resumeLivenessErrors(inventory, this.ep.getRoster());
|
|
2421
2463
|
}
|
|
2422
2464
|
catch (e) {
|
|
2423
|
-
return { ok: false, error: `resume attempt ${args.attemptId} cannot verify live principals at finalize: ${e
|
|
2465
|
+
return { ok: false, error: `resume attempt ${args.attemptId} cannot verify live principals at finalize: ${rejectionText(e)}` };
|
|
2424
2466
|
}
|
|
2425
2467
|
if (inactive.length)
|
|
2426
2468
|
return { ok: false, error: `resume attempt ${args.attemptId} is not live at finalize: ${inactive.join("; ")}` };
|
|
@@ -2439,7 +2481,7 @@ export class Manager {
|
|
|
2439
2481
|
// retiredPrincipals, so a copied JWT is refused). Best-effort + loud: a sweep failure must
|
|
2440
2482
|
// not fail the finalize (the next non-resume boot re-drives it), but it is never swallowed.
|
|
2441
2483
|
if (this.auth && !this.userMode)
|
|
2442
|
-
await this.reconcileStaticLifecycles(true).catch((e) => console.error(`! post-resume static reconcile: ${e
|
|
2484
|
+
await this.reconcileStaticLifecycles(true).catch((e) => console.error(`! post-resume static reconcile: ${rejectionText(e)} - no per-alias retry could be planned; a later manager start re-reads unfinished durable terminals`));
|
|
2443
2485
|
this.resumeFinalized = true;
|
|
2444
2486
|
this.resumeRequired = false;
|
|
2445
2487
|
return { ok: true, data: { attemptId: args.attemptId, state: "active" } };
|
|
@@ -2452,7 +2494,7 @@ export class Manager {
|
|
|
2452
2494
|
attemptId = parseResumeCommitArgs(rawArgs).attemptId;
|
|
2453
2495
|
}
|
|
2454
2496
|
catch (e) {
|
|
2455
|
-
return { ok: false, error: e
|
|
2497
|
+
return { ok: false, error: rejectionText(e) };
|
|
2456
2498
|
}
|
|
2457
2499
|
if (!this.resumeAttemptId || this.resumeAttemptId !== attemptId)
|
|
2458
2500
|
return { ok: false, error: `manager expects resume attempt ${this.resumeAttemptId ?? "<none>"}, not ${attemptId}` };
|
|
@@ -2509,7 +2551,7 @@ export class Manager {
|
|
|
2509
2551
|
: { ok: false, data, error: result.error ?? "retained-agent resume failed" };
|
|
2510
2552
|
}
|
|
2511
2553
|
catch (e) {
|
|
2512
|
-
return { ok: false, error: e
|
|
2554
|
+
return { ok: false, error: rejectionText(e) };
|
|
2513
2555
|
}
|
|
2514
2556
|
}
|
|
2515
2557
|
}
|
|
@@ -2536,7 +2578,7 @@ export class Manager {
|
|
|
2536
2578
|
};
|
|
2537
2579
|
}
|
|
2538
2580
|
catch (e) {
|
|
2539
|
-
return { ok: false, error: e
|
|
2581
|
+
return { ok: false, error: rejectionText(e) };
|
|
2540
2582
|
}
|
|
2541
2583
|
}
|
|
2542
2584
|
/** The ONE shared control-admission chokepoint (P2 item 1, checklist 3/8) BOTH dispatch doors
|
|
@@ -2767,7 +2809,7 @@ export class Manager {
|
|
|
2767
2809
|
observed = await observeStaticSlot(recordsKv, DEV_OWNER, name, this.managerInstanceId);
|
|
2768
2810
|
}
|
|
2769
2811
|
catch (error) {
|
|
2770
|
-
throw new EpEnvelopeError("unavailable", `the durable static slot state for "${name}" could not be read: ${error
|
|
2812
|
+
throw new EpEnvelopeError("unavailable", `the durable static slot state for "${name}" could not be read: ${rejectionText(error)}`, [
|
|
2771
2813
|
{ kind: STATIC_SLOT_READ_FAILED_DETAIL, name, record: error instanceof StaticSlotReadError ? error.record : "slot-or-head", operation: "read" },
|
|
2772
2814
|
]);
|
|
2773
2815
|
}
|
|
@@ -2804,7 +2846,7 @@ export class Manager {
|
|
|
2804
2846
|
observed = await listStaticSlotObservations(recordsKv, DEV_OWNER, this.managerInstanceId);
|
|
2805
2847
|
}
|
|
2806
2848
|
catch (error) {
|
|
2807
|
-
throw new EpEnvelopeError("unavailable", `the durable static slot state could not be scanned: ${error
|
|
2849
|
+
throw new EpEnvelopeError("unavailable", `the durable static slot state could not be scanned: ${rejectionText(error)}`, [
|
|
2808
2850
|
{ kind: STATIC_SLOT_READ_FAILED_DETAIL, name: "*", record: error instanceof StaticSlotReadError ? error.record : "slot-or-head", operation: "scan" },
|
|
2809
2851
|
]);
|
|
2810
2852
|
}
|
|
@@ -2942,7 +2984,7 @@ export class Manager {
|
|
|
2942
2984
|
return undefined;
|
|
2943
2985
|
}
|
|
2944
2986
|
catch (e) {
|
|
2945
|
-
return `${entry.name}: ${e
|
|
2987
|
+
return `${entry.name}: ${rejectionText(e)}`;
|
|
2946
2988
|
}
|
|
2947
2989
|
}));
|
|
2948
2990
|
const drift = authority.filter((error) => error !== undefined);
|
|
@@ -2953,7 +2995,7 @@ export class Manager {
|
|
|
2953
2995
|
inactive = this.resumeLivenessErrors(inventory, this.ep.getRoster());
|
|
2954
2996
|
}
|
|
2955
2997
|
catch (e) {
|
|
2956
|
-
return { ok: false, error: `resume attempt ${attemptId} cannot verify live principals: ${e
|
|
2998
|
+
return { ok: false, error: `resume attempt ${attemptId} cannot verify live principals: ${rejectionText(e)}` };
|
|
2957
2999
|
}
|
|
2958
3000
|
if (inactive.length)
|
|
2959
3001
|
return { ok: false, error: `resume attempt ${attemptId} is not live at commit: ${inactive.join("; ")}` };
|
|
@@ -3046,7 +3088,7 @@ export class Manager {
|
|
|
3046
3088
|
}
|
|
3047
3089
|
}
|
|
3048
3090
|
catch (e) {
|
|
3049
|
-
inactive.push(`${entry.name} runtime status failed: ${e
|
|
3091
|
+
inactive.push(`${entry.name} runtime status failed: ${rejectionText(e)}`);
|
|
3050
3092
|
continue;
|
|
3051
3093
|
}
|
|
3052
3094
|
if (!roster.some((presence) => presence.card.id === expectedPrincipal && presence.card.name === entry.name && presence.status !== "offline" &&
|
|
@@ -3102,7 +3144,7 @@ export class Manager {
|
|
|
3102
3144
|
a.handle.stop({ graceful });
|
|
3103
3145
|
}
|
|
3104
3146
|
catch (e) {
|
|
3105
|
-
console.error(`stop ${a.name} (${a.id}): ${e
|
|
3147
|
+
console.error(`stop ${a.name} (${a.id}): ${rejectionText(e)}`);
|
|
3106
3148
|
}
|
|
3107
3149
|
}
|
|
3108
3150
|
/** Keep an accepted stop inside the lifecycle drain until the runtime proves the child is gone,
|
|
@@ -3145,7 +3187,7 @@ export class Manager {
|
|
|
3145
3187
|
id: a.id,
|
|
3146
3188
|
handle: a.handle,
|
|
3147
3189
|
authoritative: true,
|
|
3148
|
-
error: `accepted stop could not prove exit: ${e
|
|
3190
|
+
error: `accepted stop could not prove exit: ${rejectionText(e)}`,
|
|
3149
3191
|
});
|
|
3150
3192
|
})
|
|
3151
3193
|
.finally(() => this.releaseLifecycle());
|
|
@@ -3185,7 +3227,7 @@ export class Manager {
|
|
|
3185
3227
|
provider = resolveAuthProvider();
|
|
3186
3228
|
}
|
|
3187
3229
|
catch (e) {
|
|
3188
|
-
return { error: e
|
|
3230
|
+
return { error: rejectionText(e) };
|
|
3189
3231
|
}
|
|
3190
3232
|
const dir = userAuthStateDir(this.workspaceRoot, this.space);
|
|
3191
3233
|
// The agent's capability scope rides its ledger row (act.scope in every bearer) — same
|
|
@@ -3293,7 +3335,7 @@ export class Manager {
|
|
|
3293
3335
|
provider = resolveAuthProvider();
|
|
3294
3336
|
}
|
|
3295
3337
|
catch (e) {
|
|
3296
|
-
return { error: e
|
|
3338
|
+
return { error: rejectionText(e) };
|
|
3297
3339
|
}
|
|
3298
3340
|
const secrets = this.secrets;
|
|
3299
3341
|
// The token the agent will present to `POST /exchange` for the rest of its life. Generated
|
|
@@ -3451,7 +3493,7 @@ export class Manager {
|
|
|
3451
3493
|
catch (e) {
|
|
3452
3494
|
// A runtime that throws while being asked has told us something real; it must not take the
|
|
3453
3495
|
// log line (or the free path it sits on) down with it.
|
|
3454
|
-
detail = `exit detail unreadable from runtime "${a.handle.kind}": ${e
|
|
3496
|
+
detail = `exit detail unreadable from runtime "${a.handle.kind}": ${rejectionText(e)}`;
|
|
3455
3497
|
}
|
|
3456
3498
|
console.error(`seat reaped: ${a.name} (${a.id}, uid ${a.lifecycleUid}${a.handle.pid !== undefined ? `, pid ${a.handle.pid}` : ""}) - ${causeText}; ${detail}`);
|
|
3457
3499
|
}
|
|
@@ -3671,8 +3713,8 @@ export class Manager {
|
|
|
3671
3713
|
catch (e) {
|
|
3672
3714
|
const h = this.retiring.get(a.name);
|
|
3673
3715
|
if (h && h.lifecycleUid === a.lifecycleUid)
|
|
3674
|
-
h.lastError = `the agent's standing mint authority could not be revoked (${e
|
|
3675
|
-
console.error(`revoke agent grant ${a.name}: ${e
|
|
3716
|
+
h.lastError = `the agent's standing mint authority could not be revoked (${rejectionText(e)}); the name stays held so a copied actor token cannot mint fresh credentials. NEXT: a same-name spawn re-drives the full teardown (including the revoke), or recover the auth state.`;
|
|
3717
|
+
console.error(`revoke agent grant ${a.name}: ${rejectionText(e)}`);
|
|
3676
3718
|
}
|
|
3677
3719
|
}
|
|
3678
3720
|
const shredFailure = unshredded.length ? `could not shred "${a.name}": ${unshredded.join("; ")}` : undefined;
|
|
@@ -3685,7 +3727,7 @@ export class Manager {
|
|
|
3685
3727
|
catch (e) {
|
|
3686
3728
|
const h = this.retiring.get(a.name);
|
|
3687
3729
|
if (h && h.lifecycleUid === a.lifecycleUid) {
|
|
3688
|
-
h.lastError = e
|
|
3730
|
+
h.lastError = rejectionText(e);
|
|
3689
3731
|
if (e instanceof DeprovisionError)
|
|
3690
3732
|
h.lastResources = e.accounting;
|
|
3691
3733
|
}
|
|
@@ -3831,7 +3873,7 @@ export class Manager {
|
|
|
3831
3873
|
}
|
|
3832
3874
|
}
|
|
3833
3875
|
catch (e) {
|
|
3834
|
-
const copy = uncertain(e
|
|
3876
|
+
const copy = uncertain(rejectionText(e));
|
|
3835
3877
|
if (held)
|
|
3836
3878
|
held.lastError = copy;
|
|
3837
3879
|
console.error(`despawn ${a.name}: ${copy}`);
|
|
@@ -3925,7 +3967,7 @@ export class Manager {
|
|
|
3925
3967
|
return { complete: true, channels: data.channels };
|
|
3926
3968
|
}
|
|
3927
3969
|
catch (e) {
|
|
3928
|
-
return { complete: false, channels: [], reason: e
|
|
3970
|
+
return { complete: false, channels: [], reason: rejectionText(e) };
|
|
3929
3971
|
}
|
|
3930
3972
|
}
|
|
3931
3973
|
/** Reap a parent's children on its exit (P4b). Every descendant remains managed until the runtime's
|
|
@@ -3947,7 +3989,7 @@ export class Manager {
|
|
|
3947
3989
|
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
3948
3990
|
}
|
|
3949
3991
|
catch (error) {
|
|
3950
|
-
throw new Error(`cannot read connector session state ${path}: ${error
|
|
3992
|
+
throw new Error(`cannot read connector session state ${path}: ${rejectionText(error)}`);
|
|
3951
3993
|
}
|
|
3952
3994
|
const state = parsed;
|
|
3953
3995
|
if (state.version !== 1 || typeof state.sessionId !== "string" || !state.sessionId.trim() || state.sessionId.length > 4096 ||
|
|
@@ -3974,7 +4016,7 @@ export class Manager {
|
|
|
3974
4016
|
}
|
|
3975
4017
|
catch (error) {
|
|
3976
4018
|
throw new Error(`retained ${connector.name} agent ${entry.name} has no sessionId in its older inventory and no usable upgrade state at ${path} ` +
|
|
3977
|
-
`(${error
|
|
4019
|
+
`(${rejectionText(error)}). Reload the live Pi seat before the preservation cut; refusing to resume fresh and lose its context.`);
|
|
3978
4020
|
}
|
|
3979
4021
|
}
|
|
3980
4022
|
/** A resumed seat's fork provenance (#1500). The seat forks after it launches, so this reads the
|
|
@@ -4059,7 +4101,7 @@ export class Manager {
|
|
|
4059
4101
|
this.recordContinuity(a, this.readManagedSession(a));
|
|
4060
4102
|
}
|
|
4061
4103
|
catch (error) {
|
|
4062
|
-
console.error(`! ${a.name}: continuity: exact assignment not updated at ${boundary}: ${error
|
|
4104
|
+
console.error(`! ${a.name}: continuity: exact assignment not updated at ${boundary}: ${rejectionText(error)}`);
|
|
4063
4105
|
}
|
|
4064
4106
|
}
|
|
4065
4107
|
async awaitManagedSessionState(a) {
|
|
@@ -4072,7 +4114,7 @@ export class Manager {
|
|
|
4072
4114
|
return this.readManagedSessionState(a);
|
|
4073
4115
|
}
|
|
4074
4116
|
catch (error) {
|
|
4075
|
-
last = error
|
|
4117
|
+
last = rejectionText(error);
|
|
4076
4118
|
}
|
|
4077
4119
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4078
4120
|
}
|
|
@@ -4105,7 +4147,7 @@ export class Manager {
|
|
|
4105
4147
|
return;
|
|
4106
4148
|
}
|
|
4107
4149
|
catch (error) {
|
|
4108
|
-
last = error
|
|
4150
|
+
last = rejectionText(error);
|
|
4109
4151
|
}
|
|
4110
4152
|
}
|
|
4111
4153
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
@@ -4210,7 +4252,7 @@ export class Manager {
|
|
|
4210
4252
|
tail = await this.tail((replacement ?? a.handle).attach());
|
|
4211
4253
|
}
|
|
4212
4254
|
catch { /* runtime has no readable tail */ }
|
|
4213
|
-
console.error(`! ${a.name}: ${supervised ? "supervised restart" : "Pi session recovery"} failed: ${error
|
|
4255
|
+
console.error(`! ${a.name}: ${supervised ? "supervised restart" : "Pi session recovery"} failed: ${rejectionText(error)}${tail ? ` - last output: ${tail}` : ""} - retiring the managed seat`);
|
|
4214
4256
|
// The replacement may be alive but unable to prove readiness. Stop it BEFORE
|
|
4215
4257
|
// retiring credentials/durables; otherwise an untracked process survives under torn auth.
|
|
4216
4258
|
try {
|
|
@@ -4250,7 +4292,7 @@ export class Manager {
|
|
|
4250
4292
|
}
|
|
4251
4293
|
}
|
|
4252
4294
|
catch (error) {
|
|
4253
|
-
console.error(`! ${a.name}: cannot classify Pi process exit for recovery: ${error
|
|
4295
|
+
console.error(`! ${a.name}: cannot classify Pi process exit for recovery: ${rejectionText(error)} - retiring the seat`);
|
|
4254
4296
|
}
|
|
4255
4297
|
}
|
|
4256
4298
|
this.freeSlot(a, true, "process-exit");
|
|
@@ -4335,6 +4377,8 @@ export class Manager {
|
|
|
4335
4377
|
// but a raw control message could otherwise slip an empty value through and silently start fresh.
|
|
4336
4378
|
if (args.resume !== undefined && !String(args.resume).trim())
|
|
4337
4379
|
return Promise.resolve({ ok: false, error: "resume: session id must not be empty" });
|
|
4380
|
+
if (args.model !== undefined && !String(args.model).trim())
|
|
4381
|
+
return Promise.resolve({ ok: false, error: "model: must not be empty" });
|
|
4338
4382
|
if (args.variant !== undefined && !String(args.variant).trim())
|
|
4339
4383
|
return Promise.resolve({ ok: false, error: "variant: must not be empty" });
|
|
4340
4384
|
if (args.defaultAgent !== undefined && !String(args.defaultAgent).trim())
|
|
@@ -4375,7 +4419,7 @@ export class Manager {
|
|
|
4375
4419
|
shareTools = strList(args.shareTools, "shareTools");
|
|
4376
4420
|
}
|
|
4377
4421
|
catch (e) {
|
|
4378
|
-
return Promise.resolve({ ok: false, error: e
|
|
4422
|
+
return Promise.resolve({ ok: false, error: rejectionText(e) });
|
|
4379
4423
|
}
|
|
4380
4424
|
// #373: the event-plane admission gate. `startAgent` resolves `eventsRequired || opts.events
|
|
4381
4425
|
// !== false`, so omission ARMS the plane — a gate on the explicit bit alone is bypassed by
|
|
@@ -4436,14 +4480,14 @@ export class Manager {
|
|
|
4436
4480
|
cwd = realpathSync(resolved);
|
|
4437
4481
|
}
|
|
4438
4482
|
catch (error) {
|
|
4439
|
-
return { refusal: `path cannot be resolved: ${error
|
|
4483
|
+
return { refusal: `path cannot be resolved: ${rejectionText(error)}` };
|
|
4440
4484
|
}
|
|
4441
4485
|
try {
|
|
4442
4486
|
if (!statSync(cwd).isDirectory())
|
|
4443
4487
|
return { refusal: "path is not a directory" };
|
|
4444
4488
|
}
|
|
4445
4489
|
catch (error) {
|
|
4446
|
-
return { refusal: error
|
|
4490
|
+
return { refusal: rejectionText(error) };
|
|
4447
4491
|
}
|
|
4448
4492
|
return { cwd, host: hostname() };
|
|
4449
4493
|
}
|
|
@@ -4491,7 +4535,7 @@ export class Manager {
|
|
|
4491
4535
|
declared = loadExtensionsManifest().extensions.flatMap((ext) => extensionConnectors(ext));
|
|
4492
4536
|
}
|
|
4493
4537
|
catch (error) {
|
|
4494
|
-
const reason = error
|
|
4538
|
+
const reason = rejectionText(error);
|
|
4495
4539
|
console.error(`! manager boot: connector inventory unavailable - ${reason}`);
|
|
4496
4540
|
this.connectorStatuses = [{ agent: "(inventory)", state: "unavailable", binaries: {}, reason }];
|
|
4497
4541
|
console.error("! manager boot: no connector available - spawn and launch stay on this instance rail only so a sibling that can launch them can take the class queue");
|
|
@@ -4575,7 +4619,7 @@ export class Manager {
|
|
|
4575
4619
|
return { agent: connector.name, supported: true, ...catalog };
|
|
4576
4620
|
}
|
|
4577
4621
|
catch (e) {
|
|
4578
|
-
return { agent: connector.name, supported: true, models: [], error: e
|
|
4622
|
+
return { agent: connector.name, supported: true, models: [], error: rejectionText(e) };
|
|
4579
4623
|
}
|
|
4580
4624
|
};
|
|
4581
4625
|
if (requested) {
|
|
@@ -4584,7 +4628,7 @@ export class Manager {
|
|
|
4584
4628
|
connector = await this.resolveConnector(requested);
|
|
4585
4629
|
}
|
|
4586
4630
|
catch (e) {
|
|
4587
|
-
return { ok: false, error: e
|
|
4631
|
+
return { ok: false, error: rejectionText(e) };
|
|
4588
4632
|
}
|
|
4589
4633
|
const result = await one(connector);
|
|
4590
4634
|
return result.error ? { ok: false, error: result.error } : { ok: true, data: result };
|
|
@@ -4598,7 +4642,7 @@ export class Manager {
|
|
|
4598
4642
|
connector = await this.resolveConnector(name);
|
|
4599
4643
|
}
|
|
4600
4644
|
catch (e) {
|
|
4601
|
-
return { agent: name, supported: false, models: [], error: e
|
|
4645
|
+
return { agent: name, supported: false, models: [], error: rejectionText(e) };
|
|
4602
4646
|
}
|
|
4603
4647
|
return one(connector);
|
|
4604
4648
|
}));
|
|
@@ -4660,7 +4704,7 @@ export class Manager {
|
|
|
4660
4704
|
persistLaunchSpec(this.workspaceRoot, spec);
|
|
4661
4705
|
}
|
|
4662
4706
|
catch (e) {
|
|
4663
|
-
return { ok: false, error: e
|
|
4707
|
+
return { ok: false, error: rejectionText(e) };
|
|
4664
4708
|
}
|
|
4665
4709
|
}
|
|
4666
4710
|
else {
|
|
@@ -4668,7 +4712,7 @@ export class Manager {
|
|
|
4668
4712
|
spec = launchSpecForRun(this.workspaceRoot, runId);
|
|
4669
4713
|
}
|
|
4670
4714
|
catch (e) {
|
|
4671
|
-
return { ok: false, error: e
|
|
4715
|
+
return { ok: false, error: rejectionText(e) };
|
|
4672
4716
|
}
|
|
4673
4717
|
}
|
|
4674
4718
|
const la = spec.agents.find((a) => a.name === name);
|
|
@@ -4691,7 +4735,7 @@ export class Manager {
|
|
|
4691
4735
|
configPath = materializePersona(this.workspaceRoot, runId, la);
|
|
4692
4736
|
}
|
|
4693
4737
|
catch (e) {
|
|
4694
|
-
return { ok: false, error: e
|
|
4738
|
+
return { ok: false, error: rejectionText(e) };
|
|
4695
4739
|
}
|
|
4696
4740
|
const reply = await this.startAgent({ ...launchAgentToStartOpts(la, configPath, spec.owner, runId), route }, caller, hooks);
|
|
4697
4741
|
if (reply.ok)
|
|
@@ -4718,9 +4762,10 @@ export class Manager {
|
|
|
4718
4762
|
}
|
|
4719
4763
|
}
|
|
4720
4764
|
async startAgentActive(opts, spawner, hooks) {
|
|
4721
|
-
//
|
|
4722
|
-
|
|
4723
|
-
|
|
4765
|
+
// Before the first await, so the grant, the launch and the retained form all read the lists as admitted.
|
|
4766
|
+
opts = ownLists(opts);
|
|
4767
|
+
if (opts.resolved)
|
|
4768
|
+
opts.resolved = ownLists(opts.resolved);
|
|
4724
4769
|
if (opts.delegatedIntent) {
|
|
4725
4770
|
if (!this.remoteAuthority?.executeDelegatedUserIntent)
|
|
4726
4771
|
return { ok: false, error: `"${opts.name}" names a delegated user intent, and this manager has no host execution for one` };
|
|
@@ -4774,7 +4819,7 @@ export class Manager {
|
|
|
4774
4819
|
def = loadAgentFile(configPath);
|
|
4775
4820
|
}
|
|
4776
4821
|
catch (e) {
|
|
4777
|
-
return { ok: false, error: e
|
|
4822
|
+
return { ok: false, error: rejectionText(e) };
|
|
4778
4823
|
}
|
|
4779
4824
|
}
|
|
4780
4825
|
const agent = resolveAgentType({ flag: opts.agent, pin: def?.agent, callerDefault: opts.defaultAgent });
|
|
@@ -4788,7 +4833,7 @@ export class Manager {
|
|
|
4788
4833
|
connector = await this.resolveConnector(agent);
|
|
4789
4834
|
}
|
|
4790
4835
|
catch (e) {
|
|
4791
|
-
return { ok: false, error: e
|
|
4836
|
+
return { ok: false, error: rejectionText(e) };
|
|
4792
4837
|
}
|
|
4793
4838
|
const readinessTimeoutMs = connector.readinessTimeoutMs ?? this.readinessTimeoutMs;
|
|
4794
4839
|
if (!Number.isSafeInteger(readinessTimeoutMs) || readinessTimeoutMs <= 0)
|
|
@@ -4827,7 +4872,7 @@ export class Manager {
|
|
|
4827
4872
|
carried = this.transcripts.peek(opts.resumeClaim, opts.resume);
|
|
4828
4873
|
}
|
|
4829
4874
|
catch (e) {
|
|
4830
|
-
return { ok: false, error: e
|
|
4875
|
+
return { ok: false, error: rejectionText(e) };
|
|
4831
4876
|
}
|
|
4832
4877
|
}
|
|
4833
4878
|
// A restart policy this host cannot honour is refused at accept, never accepted and ignored.
|
|
@@ -4850,7 +4895,7 @@ export class Manager {
|
|
|
4850
4895
|
this.delegatedMeshRecord();
|
|
4851
4896
|
}
|
|
4852
4897
|
catch (e) {
|
|
4853
|
-
return { ok: false, error: e
|
|
4898
|
+
return { ok: false, error: rejectionText(e) };
|
|
4854
4899
|
}
|
|
4855
4900
|
if (opts.resume)
|
|
4856
4901
|
return { ok: false, error: `${delegatedBy}, so it cannot resume a session held on this host (resume)` };
|
|
@@ -4858,7 +4903,7 @@ export class Manager {
|
|
|
4858
4903
|
return { ok: false, error: `${delegatedBy}, so it cannot reopen a session held on this host (continuity: exact)` };
|
|
4859
4904
|
if (typeof opts.cwd === "string" && opts.cwd !== "")
|
|
4860
4905
|
return { ok: false, error: `${delegatedBy}, so it cannot run in a directory on this host's filesystem (cwd); the seat runs in its runtime resource's own directory` };
|
|
4861
|
-
const shared = Object.keys(connectorServers(loadCotalConfig(this.workspaceRoot), agent, shareTools));
|
|
4906
|
+
const shared = Object.keys(connectorServers(loadCotalConfig(this.workspaceRoot), agent, opts.shareTools));
|
|
4862
4907
|
if (shared.length)
|
|
4863
4908
|
return { ok: false, error: `${delegatedBy}, so it cannot share MCP servers that run on this host (${shared.join(", ")}); pass --share-tools none` };
|
|
4864
4909
|
}
|
|
@@ -4894,7 +4939,7 @@ export class Manager {
|
|
|
4894
4939
|
if (opts.resolved) {
|
|
4895
4940
|
// A manifest launch is the access + identity authority: imperative overrides arriving
|
|
4896
4941
|
// alongside `resolved` are a caller contract error, not something to merge (no fallbacks).
|
|
4897
|
-
if (opts.subscribe || opts.allowSubscribe || opts.allowPublish || opts.prompt || shareTools || opts.identity)
|
|
4942
|
+
if (opts.subscribe || opts.allowSubscribe || opts.allowPublish || opts.prompt || opts.shareTools || opts.identity)
|
|
4898
4943
|
return { ok: false, error: "a manifest launch (resolved) rejects imperative overrides (identity/subscribe/allow*/prompt/shareTools)" };
|
|
4899
4944
|
const r = opts.resolved;
|
|
4900
4945
|
identityName = r.name;
|
|
@@ -4939,14 +4984,14 @@ export class Manager {
|
|
|
4939
4984
|
allowSubscribe = resolveReadAcl(subscribe ?? [], allowSubscribe);
|
|
4940
4985
|
}
|
|
4941
4986
|
catch (e) {
|
|
4942
|
-
return { ok: false, error: opts.resolved ? `launch agent: ${e
|
|
4943
|
-
}
|
|
4944
|
-
//
|
|
4945
|
-
//
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
if (
|
|
4949
|
-
|
|
4987
|
+
return { ok: false, error: opts.resolved ? `launch agent: ${rejectionText(e)}` : `persona ${configPath}: ${rejectionText(e)}` };
|
|
4988
|
+
}
|
|
4989
|
+
// Checked after every path has resolved its selectors: a direct `startAgent` call skips the
|
|
4990
|
+
// `start` op's checks, and no connector may receive a blank one (#2862).
|
|
4991
|
+
if (model !== undefined && !model.trim())
|
|
4992
|
+
return { ok: false, error: "model: must not be empty" };
|
|
4993
|
+
if (variant !== undefined && !variant.trim())
|
|
4994
|
+
return { ok: false, error: "variant: must not be empty" };
|
|
4950
4995
|
const idErr = this.nameError(identityName);
|
|
4951
4996
|
if (idErr)
|
|
4952
4997
|
return { ok: false, error: opts.resolved ? `launch agent: ${idErr}` : `persona ${configPath}: ${idErr}` };
|
|
@@ -4990,7 +5035,7 @@ export class Manager {
|
|
|
4990
5035
|
});
|
|
4991
5036
|
}
|
|
4992
5037
|
catch (e) {
|
|
4993
|
-
return { ok: false, error: e
|
|
5038
|
+
return { ok: false, error: rejectionText(e) };
|
|
4994
5039
|
}
|
|
4995
5040
|
if (policyRefusal)
|
|
4996
5041
|
return { ok: false, error: policyRefusal };
|
|
@@ -5021,7 +5066,7 @@ export class Manager {
|
|
|
5021
5066
|
reopenSession = readContinuityAssignment(this.workspaceRoot, { space: this.space, name: identityName, connector: agent, cwd: resolvedCwd ?? this.workspaceRoot });
|
|
5022
5067
|
}
|
|
5023
5068
|
catch (e) {
|
|
5024
|
-
return { ok: false, error: e
|
|
5069
|
+
return { ok: false, error: rejectionText(e) };
|
|
5025
5070
|
}
|
|
5026
5071
|
}
|
|
5027
5072
|
// The child takes launch options as `--opt k=v`, so only string values can cross to it.
|
|
@@ -5283,7 +5328,7 @@ export class Manager {
|
|
|
5283
5328
|
// (cotal config; default none → isolated, the memory-safe default this guards), narrowed by
|
|
5284
5329
|
// an optional --share-tools selection (absent → all declared, the pre-merge behavior).
|
|
5285
5330
|
const cotalConfig = loadCotalConfig(this.workspaceRoot);
|
|
5286
|
-
const mcpServers = connectorServers(cotalConfig, agent, shareTools);
|
|
5331
|
+
const mcpServers = connectorServers(cotalConfig, agent, opts.shareTools);
|
|
5287
5332
|
// The operator's spawn-env policy travels the same route: absent means no extras (the OS
|
|
5288
5333
|
// allow-list + operator knobs + connector-declared inputs), present means those names too.
|
|
5289
5334
|
// A connector never reads the config itself.
|
|
@@ -5410,7 +5455,7 @@ export class Manager {
|
|
|
5410
5455
|
allowPublish,
|
|
5411
5456
|
capabilities,
|
|
5412
5457
|
events,
|
|
5413
|
-
shareTools,
|
|
5458
|
+
shareTools: opts.shareTools,
|
|
5414
5459
|
forkSource: opts.resume,
|
|
5415
5460
|
...(opts.resume !== undefined && spec?.resumeRecordPath ? { resumeRecordPath: spec.resumeRecordPath } : {}),
|
|
5416
5461
|
...(carried ? { carried: { transcriptSha256: carried.sha256, host: carried.sourceHost, transferredAt: carried.stagedAt } } : {}),
|
|
@@ -5514,7 +5559,7 @@ export class Manager {
|
|
|
5514
5559
|
}
|
|
5515
5560
|
}
|
|
5516
5561
|
catch (error) {
|
|
5517
|
-
const detail = `${managed.name} joined, but its exact host session could not be bound for supervised recovery: ${error
|
|
5562
|
+
const detail = `${managed.name} joined, but its exact host session could not be bound for supervised recovery: ${rejectionText(error)}`;
|
|
5518
5563
|
this.stopHandle(managed, false);
|
|
5519
5564
|
this.freeSlot(managed, true, "session-bind-failed");
|
|
5520
5565
|
await hooks?.onOutcome?.({ kind: "failed", data: { error: detail } });
|
|
@@ -5587,9 +5632,9 @@ export class Manager {
|
|
|
5587
5632
|
return { ok: false, agents: [], error: `unsupported manager resume inventory version ${String(inventory.version)}` };
|
|
5588
5633
|
if (inventory.space !== this.space)
|
|
5589
5634
|
return { ok: false, agents: [], error: `resume inventory belongs to space "${inventory.space}", not "${this.space}"` };
|
|
5590
|
-
// The caller keeps its inventory, so
|
|
5591
|
-
//
|
|
5592
|
-
const entries = inventory.agents
|
|
5635
|
+
// The caller keeps its inventory, so it is copied before the first await: a later write to it
|
|
5636
|
+
// cannot change what a resumed seat launches with or what the next preservation retains.
|
|
5637
|
+
const entries = structuredClone(inventory.agents);
|
|
5593
5638
|
const seen = new Set();
|
|
5594
5639
|
const principals = new Set();
|
|
5595
5640
|
const orphans = [];
|
|
@@ -5631,7 +5676,7 @@ export class Manager {
|
|
|
5631
5676
|
: principalKey(DEV_OWNER, entry.identity.id).key;
|
|
5632
5677
|
}
|
|
5633
5678
|
catch (e) {
|
|
5634
|
-
return { ok: false, agents: [], error: `invalid retained principal for ${entry.name}: ${e
|
|
5679
|
+
return { ok: false, agents: [], error: `invalid retained principal for ${entry.name}: ${rejectionText(e)}` };
|
|
5635
5680
|
}
|
|
5636
5681
|
if (principals.has(principal))
|
|
5637
5682
|
return { ok: false, agents: [], error: `resume inventory contains duplicate principal "${principal}"` };
|
|
@@ -5707,7 +5752,7 @@ export class Manager {
|
|
|
5707
5752
|
discardLaunchArtifacts(spec.artifacts);
|
|
5708
5753
|
}
|
|
5709
5754
|
catch (e) {
|
|
5710
|
-
console.error(`! resume: ${e
|
|
5755
|
+
console.error(`! resume: ${rejectionText(e)}`);
|
|
5711
5756
|
}
|
|
5712
5757
|
}
|
|
5713
5758
|
release();
|
|
@@ -5786,7 +5831,7 @@ export class Manager {
|
|
|
5786
5831
|
throw new Error(`retained credential identity ${actual} does not match inventory principal ${entry.identity.id}`);
|
|
5787
5832
|
}
|
|
5788
5833
|
catch (e) {
|
|
5789
|
-
throw new Error(`retained credential for ${entry.name} is unusable: ${e
|
|
5834
|
+
throw new Error(`retained credential for ${entry.name} is unusable: ${rejectionText(e)}`);
|
|
5790
5835
|
}
|
|
5791
5836
|
const accepted = await this.probeStaticCredential(credentialText);
|
|
5792
5837
|
if (!accepted.ok)
|
|
@@ -5874,7 +5919,7 @@ export class Manager {
|
|
|
5874
5919
|
};
|
|
5875
5920
|
}
|
|
5876
5921
|
catch (e) {
|
|
5877
|
-
throw new Error(`retained user principal ${entry.identity.owner}.${entry.identity.actor} could not be reused: ${e
|
|
5922
|
+
throw new Error(`retained user principal ${entry.identity.owner}.${entry.identity.actor} could not be reused: ${rejectionText(e)}`);
|
|
5878
5923
|
}
|
|
5879
5924
|
}
|
|
5880
5925
|
/** The seat reference behind a live retained principal, when that seat is provably one a lost
|
|
@@ -5907,7 +5952,7 @@ export class Manager {
|
|
|
5907
5952
|
console.error(`resume: reaped orphaned seat ${reference.kind}:${reference.id} of retained principal "${principal}" (${evidence.detail})`);
|
|
5908
5953
|
}
|
|
5909
5954
|
catch (e) {
|
|
5910
|
-
return `retained principal "${principal}" is already live and its recorded seat ${reference.kind}:${reference.id} could not be reaped: ${e
|
|
5955
|
+
return `retained principal "${principal}" is already live and its recorded seat ${reference.kind}:${reference.id} could not be reaped: ${rejectionText(e)}`;
|
|
5911
5956
|
}
|
|
5912
5957
|
const deadline = Date.now() + ORPHAN_PRESENCE_CLEAR_MS;
|
|
5913
5958
|
while (this.ep.getRoster().some((p) => p.card.id === principal && p.status !== "offline")) {
|
|
@@ -5943,7 +5988,7 @@ export class Manager {
|
|
|
5943
5988
|
await this.validateRetainedAuthority(entry);
|
|
5944
5989
|
}
|
|
5945
5990
|
catch (e) {
|
|
5946
|
-
return { ok: false, error: e
|
|
5991
|
+
return { ok: false, error: rejectionText(e) };
|
|
5947
5992
|
}
|
|
5948
5993
|
return this.launchPreparedResume(entry, cached, batchReserved);
|
|
5949
5994
|
}
|
|
@@ -5953,7 +5998,7 @@ export class Manager {
|
|
|
5953
5998
|
return { ok: false, error: `retained cwd is not a real directory: ${entry.launch.cwd}` };
|
|
5954
5999
|
}
|
|
5955
6000
|
catch (e) {
|
|
5956
|
-
return { ok: false, error: `retained cwd unavailable: ${entry.launch.cwd} (${e
|
|
6001
|
+
return { ok: false, error: `retained cwd unavailable: ${entry.launch.cwd} (${rejectionText(e)})` };
|
|
5957
6002
|
}
|
|
5958
6003
|
let connector;
|
|
5959
6004
|
try {
|
|
@@ -5967,7 +6012,7 @@ export class Manager {
|
|
|
5967
6012
|
connector = await this.resolveConnector(entry.launch.connector);
|
|
5968
6013
|
}
|
|
5969
6014
|
catch (e) {
|
|
5970
|
-
return { ok: false, error: e
|
|
6015
|
+
return { ok: false, error: rejectionText(e) };
|
|
5971
6016
|
}
|
|
5972
6017
|
const harness = this.launchHarness(connector);
|
|
5973
6018
|
if ("refusal" in harness)
|
|
@@ -5977,7 +6022,7 @@ export class Manager {
|
|
|
5977
6022
|
retainedSession = this.retainedSessionId(entry, connector);
|
|
5978
6023
|
}
|
|
5979
6024
|
catch (error) {
|
|
5980
|
-
return { ok: false, error: error
|
|
6025
|
+
return { ok: false, error: rejectionText(error) };
|
|
5981
6026
|
}
|
|
5982
6027
|
if (entry.launch.forkSource && !retainedSession && !connector.supportsResume)
|
|
5983
6028
|
return { ok: false, error: `${connector.name} connector does not support session fork (resume)` };
|
|
@@ -5997,7 +6042,7 @@ export class Manager {
|
|
|
5997
6042
|
spec = source.agents.find((a) => a.name === launchSource.requested);
|
|
5998
6043
|
}
|
|
5999
6044
|
catch (e) {
|
|
6000
|
-
return { ok: false, error: e
|
|
6045
|
+
return { ok: false, error: rejectionText(e) };
|
|
6001
6046
|
}
|
|
6002
6047
|
if (!spec || spec.hash !== launchSource.hash)
|
|
6003
6048
|
return { ok: false, error: `retained manifest agent ${launchSource.requested} is missing or its hash changed; refusing same-principal resume` };
|
|
@@ -6009,7 +6054,7 @@ export class Manager {
|
|
|
6009
6054
|
launchOptions = loadAgentFile(entry.launch.source.configPath).launchOptions;
|
|
6010
6055
|
}
|
|
6011
6056
|
catch (e) {
|
|
6012
|
-
return { ok: false, error: e
|
|
6057
|
+
return { ok: false, error: rejectionText(e) };
|
|
6013
6058
|
}
|
|
6014
6059
|
}
|
|
6015
6060
|
// Asked once `exact` is known: an exact seat reopens its retained session or fails, like its
|
|
@@ -6022,7 +6067,7 @@ export class Manager {
|
|
|
6022
6067
|
authority = await this.validateRetainedAuthority(entry);
|
|
6023
6068
|
}
|
|
6024
6069
|
catch (e) {
|
|
6025
|
-
return { ok: false, error: e
|
|
6070
|
+
return { ok: false, error: rejectionText(e) };
|
|
6026
6071
|
}
|
|
6027
6072
|
try {
|
|
6028
6073
|
const resumeConfig = loadCotalConfig(this.workspaceRoot);
|
|
@@ -6071,7 +6116,7 @@ export class Manager {
|
|
|
6071
6116
|
return this.launchPreparedResume(entry, value, batchReserved);
|
|
6072
6117
|
}
|
|
6073
6118
|
catch (e) {
|
|
6074
|
-
return { ok: false, error: e
|
|
6119
|
+
return { ok: false, error: rejectionText(e) };
|
|
6075
6120
|
}
|
|
6076
6121
|
}
|
|
6077
6122
|
finally {
|
|
@@ -6154,7 +6199,7 @@ export class Manager {
|
|
|
6154
6199
|
await this.recordSlotRuntime(managed);
|
|
6155
6200
|
}
|
|
6156
6201
|
catch (error) {
|
|
6157
|
-
return await this.stopFailedResume(managed, "resume-custody-unrecorded", `${managed.name} resumed, but ${error
|
|
6202
|
+
return await this.stopFailedResume(managed, "resume-custody-unrecorded", `${managed.name} resumed, but ${rejectionText(error)}`);
|
|
6158
6203
|
}
|
|
6159
6204
|
const readiness = await this.awaitReadiness(managed, readinessTimeoutMs);
|
|
6160
6205
|
if (!readiness.ok && !readiness.uncertain)
|
|
@@ -6181,7 +6226,7 @@ export class Manager {
|
|
|
6181
6226
|
}
|
|
6182
6227
|
}
|
|
6183
6228
|
catch (error) {
|
|
6184
|
-
return await this.stopFailedResume(managed, "resume-session-rebind-failed", `${managed.name} resumed, but its exact host session could not be rebound: ${error
|
|
6229
|
+
return await this.stopFailedResume(managed, "resume-session-rebind-failed", `${managed.name} resumed, but its exact host session could not be rebound: ${rejectionText(error)}`);
|
|
6185
6230
|
}
|
|
6186
6231
|
}
|
|
6187
6232
|
if (!this.resumeAttemptId)
|
|
@@ -6195,7 +6240,7 @@ export class Manager {
|
|
|
6195
6240
|
};
|
|
6196
6241
|
}
|
|
6197
6242
|
catch (e) {
|
|
6198
|
-
return { ok: false, error: e
|
|
6243
|
+
return { ok: false, error: rejectionText(e) };
|
|
6199
6244
|
}
|
|
6200
6245
|
finally {
|
|
6201
6246
|
if (!batchReserved) {
|
|
@@ -6214,7 +6259,7 @@ export class Manager {
|
|
|
6214
6259
|
}
|
|
6215
6260
|
catch (exit) {
|
|
6216
6261
|
this.watchExit(managed);
|
|
6217
|
-
return { ok: false, error: `${detail}; it stays managed because its stop is unproven: ${exit
|
|
6262
|
+
return { ok: false, error: `${detail}; it stays managed because its stop is unproven: ${rejectionText(exit)}` };
|
|
6218
6263
|
}
|
|
6219
6264
|
this.freeSlot(managed, true, cause, true);
|
|
6220
6265
|
return { ok: false, error: detail };
|
|
@@ -6966,7 +7011,7 @@ export class Manager {
|
|
|
6966
7011
|
// One registration operation for this boot. Fresh executors may replace a dead connection, but
|
|
6967
7012
|
// they must resume THIS freeze rather than minting a new op that discards Phase-2 progress.
|
|
6968
7013
|
const registrationOpId = mintLifecycleUid();
|
|
6969
|
-
const executorExpired = (e) => /closed connection/i.test(
|
|
7014
|
+
const executorExpired = (e) => /closed connection/i.test(rejectionText(e));
|
|
6970
7015
|
const retryExpiredExecutor = async (label, fn) => {
|
|
6971
7016
|
for (;;) {
|
|
6972
7017
|
try {
|
|
@@ -7573,14 +7618,14 @@ export class Manager {
|
|
|
7573
7618
|
await this.reconcileOneGoal(entry.ref, entry.iid);
|
|
7574
7619
|
}
|
|
7575
7620
|
catch (e) {
|
|
7576
|
-
console.error(`! goal reconcile for ${entry.ref.goalId}: ${e
|
|
7621
|
+
console.error(`! goal reconcile for ${entry.ref.goalId}: ${rejectionText(e)}`);
|
|
7577
7622
|
}
|
|
7578
7623
|
}
|
|
7579
7624
|
if (entries.length)
|
|
7580
7625
|
console.error(`goal-index boot reconcile: swept ${entries.length} inherited goal(s)`);
|
|
7581
7626
|
}
|
|
7582
7627
|
catch (e) {
|
|
7583
|
-
console.error(`! goal-index boot reconcile failed: ${e
|
|
7628
|
+
console.error(`! goal-index boot reconcile failed: ${rejectionText(e)} - accepted goals from a predecessor may stay unsettled until the next restart`);
|
|
7584
7629
|
}
|
|
7585
7630
|
finally {
|
|
7586
7631
|
this.goalReconcileDone = true;
|
|
@@ -7630,7 +7675,7 @@ export class Manager {
|
|
|
7630
7675
|
return;
|
|
7631
7676
|
}
|
|
7632
7677
|
console.error(`goal reconcile ${ref.goalId}: within the readiness window (${remaining}ms) - arming a bounded settle`);
|
|
7633
|
-
const t = setTimeout(() => { settle().catch((e) => console.error(`! goal reconcile settle ${ref.goalId}: ${e
|
|
7678
|
+
const t = setTimeout(() => { settle().catch((e) => console.error(`! goal reconcile settle ${ref.goalId}: ${rejectionText(e)}`)); }, remaining + 100);
|
|
7634
7679
|
t.unref?.();
|
|
7635
7680
|
}
|
|
7636
7681
|
/** P2 item 2: publish a goal PROGRESS event on the caller-scoped epe subtree, over the SERVE
|
|
@@ -7646,7 +7691,7 @@ export class Manager {
|
|
|
7646
7691
|
nc.publish(epeSubject(this.space, MANAGER_ENDPOINT, this.managerInstanceId, epoch, goalProgressTopic(ref)), new TextEncoder().encode(JSON.stringify({ v: 1, goalId: ref.goalId, ...event })));
|
|
7647
7692
|
}
|
|
7648
7693
|
catch (e) {
|
|
7649
|
-
console.error(`! goal progress emit for ${ref.goalId} failed: ${e
|
|
7694
|
+
console.error(`! goal progress emit for ${ref.goalId} failed: ${rejectionText(e)}`);
|
|
7650
7695
|
}
|
|
7651
7696
|
}
|
|
7652
7697
|
/** The own-gate currency belt: before the goal-writer commits a terminal fact, the manager reads
|
|
@@ -7785,7 +7830,7 @@ export class Manager {
|
|
|
7785
7830
|
// ENTRY. This leg is infrastructure-class and converges through the reconcile index at the
|
|
7786
7831
|
// next boot, which is why the index is NOT cleared above on this path. Do not "close" it
|
|
7787
7832
|
// here with a retry loop.
|
|
7788
|
-
console.error(`! goal terminal commit for ${goalId} failed: ${e
|
|
7833
|
+
console.error(`! goal terminal commit for ${goalId} failed: ${rejectionText(e)}`);
|
|
7789
7834
|
}
|
|
7790
7835
|
};
|
|
7791
7836
|
const bg = run({
|
|
@@ -7870,7 +7915,7 @@ export class Manager {
|
|
|
7870
7915
|
// the caller follows epe to a terminal that never comes, and the reconcile index that would
|
|
7871
7916
|
// settle it is only swept at BOOT, so a manager that stays up never converges it.
|
|
7872
7917
|
if (reply.ok === false && !terminalEntered)
|
|
7873
|
-
return onOutcome({ kind: "failed", data:
|
|
7918
|
+
return onOutcome({ kind: "failed", data: failedTerminal(reply.error ?? "spawn failed after accept", reply) });
|
|
7874
7919
|
}).catch((e) => {
|
|
7875
7920
|
if (acceptance === undefined) {
|
|
7876
7921
|
rejectAccept(e);
|
|
@@ -7878,9 +7923,9 @@ export class Manager {
|
|
|
7878
7923
|
}
|
|
7879
7924
|
// Same obligation for a genuine rejection (one that escaped `run`'s own catch).
|
|
7880
7925
|
if (!terminalEntered)
|
|
7881
|
-
return onOutcome({ kind: "failed", data:
|
|
7882
|
-
console.error(`! spawn-as-action async body for ${goalId}: ${
|
|
7883
|
-
}).catch((e) => console.error(`! goal terminal fallback for ${goalId}: ${
|
|
7926
|
+
return onOutcome({ kind: "failed", data: failedTerminal(rejectionText(e), caughtEnvelope(e)) });
|
|
7927
|
+
console.error(`! spawn-as-action async body for ${goalId}: ${rejectionText(e)}`);
|
|
7928
|
+
}).catch((e) => console.error(`! goal terminal fallback for ${goalId}: ${rejectionText(e)}`));
|
|
7884
7929
|
return acceptP;
|
|
7885
7930
|
}
|
|
7886
7931
|
/** H2: an acceptance served from a WINNER'S durable acceptance floor (the goal-index entry it
|
|
@@ -8023,7 +8068,7 @@ export class Manager {
|
|
|
8023
8068
|
// The accept is inline (no launch closure to fail later), so a post-bind throw unwinds HERE:
|
|
8024
8069
|
// commit the failed terminal this attempt owns, clear the index, and refuse the accept — an
|
|
8025
8070
|
// accepted-but-unanswered goal must never be left for the boot sweep to find (H1's rule).
|
|
8026
|
-
const msg =
|
|
8071
|
+
const msg = rejectionText(e);
|
|
8027
8072
|
try {
|
|
8028
8073
|
await this.assertGoalWriterEpochCurrent(executor.epoch);
|
|
8029
8074
|
// The goal is TARGET-PINNED, so its completion proves the seat's currency exactly as the
|
|
@@ -8039,9 +8084,9 @@ export class Manager {
|
|
|
8039
8084
|
await clearGoalIndex(gw.ctx, ref);
|
|
8040
8085
|
}
|
|
8041
8086
|
catch (e2) {
|
|
8042
|
-
console.error(`! turn accept unwind for ${goalId}: ${e2
|
|
8087
|
+
console.error(`! turn accept unwind for ${goalId}: ${rejectionText(e2)}`);
|
|
8043
8088
|
}
|
|
8044
|
-
throw e
|
|
8089
|
+
throw caughtEnvelope(e) ?? new EpEnvelopeError("internal", `turn accept for ${goalId} failed: ${msg}`);
|
|
8045
8090
|
}
|
|
8046
8091
|
const pending = {
|
|
8047
8092
|
ref, goalId,
|
|
@@ -8241,7 +8286,7 @@ export class Manager {
|
|
|
8241
8286
|
await clearGoalIndex(gw.ctx, p.ref);
|
|
8242
8287
|
}
|
|
8243
8288
|
catch (e) {
|
|
8244
|
-
console.error(`! turn deadline terminal for ${p.goalId}: ${e
|
|
8289
|
+
console.error(`! turn deadline terminal for ${p.goalId}: ${rejectionText(e)}`);
|
|
8245
8290
|
}
|
|
8246
8291
|
this.maybeStopTurnSweep();
|
|
8247
8292
|
}
|
|
@@ -8273,7 +8318,7 @@ export class Manager {
|
|
|
8273
8318
|
ensureTurnSweep() {
|
|
8274
8319
|
if (this.turnSweepTimer !== undefined)
|
|
8275
8320
|
return;
|
|
8276
|
-
const t = setInterval(() => { void this.sweepTurnDeadlines().catch((e) => console.error(`! turn deadline sweep: ${e
|
|
8321
|
+
const t = setInterval(() => { void this.sweepTurnDeadlines().catch((e) => console.error(`! turn deadline sweep: ${rejectionText(e)}`)); }, TURN_SWEEP_MS);
|
|
8277
8322
|
t.unref?.();
|
|
8278
8323
|
this.turnSweepTimer = t;
|
|
8279
8324
|
}
|
|
@@ -8342,7 +8387,7 @@ export class Manager {
|
|
|
8342
8387
|
await this.commitTurnDeadline(p);
|
|
8343
8388
|
}
|
|
8344
8389
|
catch (e) {
|
|
8345
|
-
console.error(`! turn deadline sweep for ${p.goalId}: ${e
|
|
8390
|
+
console.error(`! turn deadline sweep for ${p.goalId}: ${rejectionText(e)}`);
|
|
8346
8391
|
}
|
|
8347
8392
|
}
|
|
8348
8393
|
}
|
|
@@ -8473,7 +8518,7 @@ export class Manager {
|
|
|
8473
8518
|
});
|
|
8474
8519
|
}
|
|
8475
8520
|
catch (e) {
|
|
8476
|
-
throw new Error(`could not record the custody reference ${runtime.kind}:${runtime.id} on the static slot of "${a.name}": ${e
|
|
8521
|
+
throw new Error(`could not record the custody reference ${runtime.kind}:${runtime.id} on the static slot of "${a.name}": ${rejectionText(e)}`);
|
|
8477
8522
|
}
|
|
8478
8523
|
}
|
|
8479
8524
|
/** Mint the custody reference for a seat this manager is about to spawn, BEFORE the processes
|
|
@@ -8519,7 +8564,7 @@ export class Manager {
|
|
|
8519
8564
|
disposal =
|
|
8520
8565
|
e instanceof RuntimeReapUnproven
|
|
8521
8566
|
? `the spawned seat was NOT proved gone and may still be running as ${e.reference.kind}:${e.reference.id} (${e.message})`
|
|
8522
|
-
: `the spawned seat could NOT be reaped: ${e
|
|
8567
|
+
: `the spawned seat could NOT be reaped: ${rejectionText(e)}`;
|
|
8523
8568
|
}
|
|
8524
8569
|
}
|
|
8525
8570
|
throw new Error(`runtime "${this.runtime.kind}" reserved custody ${reserved.kind}:${reserved.id} for "${name}" but spawned ` +
|
|
@@ -8620,8 +8665,8 @@ export class Manager {
|
|
|
8620
8665
|
catch (e) {
|
|
8621
8666
|
const h = this.retiring.get(a.name);
|
|
8622
8667
|
if (h && h.lifecycleUid === a.lifecycleUid)
|
|
8623
|
-
h.lastError = `the static retirement did not complete (${e
|
|
8624
|
-
console.error(`static retirement ${a.name} (${a.id}): ${e
|
|
8668
|
+
h.lastError = `the static retirement did not complete (${rejectionText(e)}); the name stays held - a same-name spawn retries the same terminal (op ${opId})`;
|
|
8669
|
+
console.error(`static retirement ${a.name} (${a.id}): ${rejectionText(e)}`);
|
|
8625
8670
|
if (surfaceFailure)
|
|
8626
8671
|
throw e;
|
|
8627
8672
|
}
|
|
@@ -8724,7 +8769,7 @@ export class Manager {
|
|
|
8724
8769
|
await this.retryStaticReconcile(key);
|
|
8725
8770
|
};
|
|
8726
8771
|
void run().catch((error) => {
|
|
8727
|
-
item.lastError = `retry driver failed before the exact terminal: ${error
|
|
8772
|
+
item.lastError = `retry driver failed before the exact terminal: ${rejectionText(error)}`;
|
|
8728
8773
|
item.disposition = "retry-exhausted";
|
|
8729
8774
|
item.remedy = "restart this manager for a fresh per-process retry budget";
|
|
8730
8775
|
console.error(`! static reconcile retry-exhausted alias=${item.alias} phase=${item.phase} uid=${item.lifecycleUid}: ${item.lastError}; NEXT: restart this manager for a fresh per-process retry budget`);
|
|
@@ -8765,7 +8810,7 @@ export class Manager {
|
|
|
8765
8810
|
row = await this.readStaticReconcileSlot(item.alias);
|
|
8766
8811
|
}
|
|
8767
8812
|
catch (error) {
|
|
8768
|
-
item.lastError = `durable slot re-read failed: ${error
|
|
8813
|
+
item.lastError = `durable slot re-read failed: ${rejectionText(error)}`;
|
|
8769
8814
|
if (item.attempts >= item.maxAttempts) {
|
|
8770
8815
|
item.disposition = "retry-exhausted";
|
|
8771
8816
|
item.remedy = "restart this manager for a fresh per-process retry budget";
|
|
@@ -8849,7 +8894,7 @@ export class Manager {
|
|
|
8849
8894
|
return true;
|
|
8850
8895
|
}
|
|
8851
8896
|
catch (error) {
|
|
8852
|
-
item.lastError = error
|
|
8897
|
+
item.lastError = rejectionText(error);
|
|
8853
8898
|
try {
|
|
8854
8899
|
const fresh = await this.readStaticReconcileSlot(item.alias);
|
|
8855
8900
|
if (fresh?.lifecycleUid === item.lifecycleUid && fresh.actor === item.actor)
|
|
@@ -8948,16 +8993,8 @@ export class Manager {
|
|
|
8948
8993
|
const kvm = new Kvm(nc);
|
|
8949
8994
|
await ensureAuthorityStores(jsm, kvm, this.space);
|
|
8950
8995
|
const recordsKv = await kvm.open(recordsBucket(this.space));
|
|
8951
|
-
const
|
|
8952
|
-
|
|
8953
|
-
const aliases = [];
|
|
8954
|
-
for await (const k of keys)
|
|
8955
|
-
aliases.push(k.split(".").slice(2).join("."));
|
|
8956
|
-
for (const alias of aliases) {
|
|
8957
|
-
const slot = await readStaticSlot(t, DEV_OWNER, alias);
|
|
8958
|
-
if (slot !== undefined)
|
|
8959
|
-
slotRows.push(slot.row);
|
|
8960
|
-
}
|
|
8996
|
+
for (const slot of await walkStaticSlots(recordsKv, DEV_OWNER))
|
|
8997
|
+
slotRows.push(slot.row);
|
|
8961
8998
|
}
|
|
8962
8999
|
catch (error) {
|
|
8963
9000
|
sweep.completedAt = new Date().toISOString();
|
|
@@ -9206,7 +9243,7 @@ export class Manager {
|
|
|
9206
9243
|
return { ok: true, data: result };
|
|
9207
9244
|
}
|
|
9208
9245
|
catch (e) {
|
|
9209
|
-
return { ok: false, error: e
|
|
9246
|
+
return { ok: false, error: rejectionText(e) };
|
|
9210
9247
|
}
|
|
9211
9248
|
}
|
|
9212
9249
|
/** Persist a peer-defined persona as config. After this, `start name` auto-discovers
|
|
@@ -9238,7 +9275,7 @@ export class Manager {
|
|
|
9238
9275
|
existing = loadAgentFile(path);
|
|
9239
9276
|
}
|
|
9240
9277
|
catch (e) {
|
|
9241
|
-
return { ok: false, error: e
|
|
9278
|
+
return { ok: false, error: rejectionText(e) };
|
|
9242
9279
|
}
|
|
9243
9280
|
if (!admin && existing.owner !== caller) {
|
|
9244
9281
|
const owner = existing.owner ? `owned by ${existing.owner}` : "operator-owned (legacy file - no agent owner)";
|
|
@@ -9265,13 +9302,13 @@ export class Manager {
|
|
|
9265
9302
|
}, existing);
|
|
9266
9303
|
}
|
|
9267
9304
|
catch (e) {
|
|
9268
|
-
return { ok: false, error: e
|
|
9305
|
+
return { ok: false, error: rejectionText(e) };
|
|
9269
9306
|
}
|
|
9270
9307
|
try {
|
|
9271
9308
|
saveAgentFile(path, def);
|
|
9272
9309
|
}
|
|
9273
9310
|
catch (e) {
|
|
9274
|
-
return { ok: false, error: e
|
|
9311
|
+
return { ok: false, error: rejectionText(e) };
|
|
9275
9312
|
}
|
|
9276
9313
|
return { ok: true, data: { name, path } };
|
|
9277
9314
|
}
|
|
@@ -9429,7 +9466,7 @@ export class Manager {
|
|
|
9429
9466
|
accepted = await write(part.data);
|
|
9430
9467
|
}
|
|
9431
9468
|
catch (error) {
|
|
9432
|
-
throw new EpEnvelopeError("unavailable", `input for seat "${a.name}" failed: ${error
|
|
9469
|
+
throw new EpEnvelopeError("unavailable", `input for seat "${a.name}" failed: ${rejectionText(error)}`);
|
|
9433
9470
|
}
|
|
9434
9471
|
if (!Number.isSafeInteger(accepted)) {
|
|
9435
9472
|
throw new EpEnvelopeError("unavailable", `input for seat "${a.name}" failed: runtime accepted ${String(accepted)} of ${intendedBytes} bytes`);
|
|
@@ -9480,7 +9517,7 @@ export class Manager {
|
|
|
9480
9517
|
}
|
|
9481
9518
|
catch (e) {
|
|
9482
9519
|
slot.release();
|
|
9483
|
-
return { ok: false, error: e
|
|
9520
|
+
return { ok: false, error: rejectionText(e) };
|
|
9484
9521
|
}
|
|
9485
9522
|
// establishAttach releases the claim it was handed on every exit; nothing to unwind here.
|
|
9486
9523
|
const { grant } = await this.sessionPlane.establishAttach(caller, { name: a.name, lifecycleUid: a.lifecycleUid }, session, slot);
|