commonswarm 0.1.72 → 0.1.73
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/cswarm.cjs +1238 -273
- package/package.json +1 -1
package/cswarm.cjs
CHANGED
|
@@ -1149,41 +1149,77 @@ async function requestSuccessor(options) {
|
|
|
1149
1149
|
let body = {};
|
|
1150
1150
|
try {
|
|
1151
1151
|
const text = await response.text();
|
|
1152
|
-
if (text)
|
|
1152
|
+
if (text) {
|
|
1153
|
+
const parsed = JSON.parse(text);
|
|
1154
|
+
if (options.listenerMode && (!parsed || typeof parsed !== "object" || Array.isArray(parsed))) {
|
|
1155
|
+
throw new RenewalMalformedResponseError("renewal response was not an object");
|
|
1156
|
+
}
|
|
1157
|
+
body = parsed;
|
|
1158
|
+
}
|
|
1153
1159
|
} catch {
|
|
1154
|
-
|
|
1160
|
+
if (!options.listenerMode) {
|
|
1161
|
+
body = {};
|
|
1162
|
+
} else {
|
|
1163
|
+
throw new RenewalMalformedResponseError("renewal response was not valid JSON");
|
|
1164
|
+
}
|
|
1155
1165
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
throw new RenewalUnsupported(
|
|
1159
|
-
"this deployment does not offer credential renewal yet, so a credential here still has to be re-issued by hand when it expires"
|
|
1160
|
-
);
|
|
1166
|
+
if (options.listenerMode && response.status !== 401 && response.status !== 403 && body.principal_id !== void 0 && body.principal_id !== null && (typeof body.principal_id !== "string" || !UUID_RE5.test(body.principal_id))) {
|
|
1167
|
+
throw new RenewalMalformedResponseError("renewal response carried a malformed principal_id");
|
|
1161
1168
|
}
|
|
1169
|
+
const principalId = typeof body.principal_id === "string" && UUID_RE5.test(body.principal_id) ? body.principal_id.toLowerCase() : null;
|
|
1162
1170
|
if (response.status === 401 || response.status === 403) {
|
|
1171
|
+
if (options.listenerMode) {
|
|
1172
|
+
if (response.status === 401 && body.error === "unauthenticated") {
|
|
1173
|
+
throw new RenewalCredentialCheckError(response.status, "unauthenticated");
|
|
1174
|
+
}
|
|
1175
|
+
throw new RenewalOutcomeUnknown(`renewal command answered HTTP ${response.status}`);
|
|
1176
|
+
}
|
|
1163
1177
|
const named = typeof body.reason === "string" && REVOCATION_REASONS.has(body.reason) ? body.reason : null;
|
|
1164
1178
|
if (named !== null) throw new RenewalRevoked(named, REVOKED_MESSAGE);
|
|
1165
|
-
|
|
1166
|
-
if (expiresAt2 !== null && now() >= expiresAt2) {
|
|
1179
|
+
if (options.expiresAt !== null && options.expiresAt !== void 0 && now() >= options.expiresAt) {
|
|
1167
1180
|
throw new RenewalRevoked("predecessor_expired_local", LOCALLY_EXPIRED_MESSAGE);
|
|
1168
1181
|
}
|
|
1169
1182
|
throw new RenewalRevoked("forbidden", UNEXPLAINED_REFUSAL_MESSAGE);
|
|
1170
1183
|
}
|
|
1171
1184
|
if (response.status === 426) {
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1185
|
+
if (!options.listenerMode) {
|
|
1186
|
+
const minimum = typeof body.min_client_version === "string" ? body.min_client_version : null;
|
|
1187
|
+
throw new RenewalRefused(
|
|
1188
|
+
426,
|
|
1189
|
+
"upgrade_required",
|
|
1190
|
+
`This copy of cswarm is older than the deployment accepts${minimum === null ? "" : ` (minimum ${minimum})`}. Update cswarm; until then this credential cannot renew itself.`
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
if (body.error !== "upgrade_required" || typeof body.min_client_version !== "string") {
|
|
1194
|
+
throw new RenewalOutcomeUnknown("renewal command answered an unrecognized HTTP 426");
|
|
1195
|
+
}
|
|
1196
|
+
throw new RenewalUpgradeRequiredError(body.min_client_version, options.listenerMode);
|
|
1197
|
+
}
|
|
1198
|
+
if (!options.listenerMode && (response.status === 400 || response.status === 404)) {
|
|
1199
|
+
throw new RenewalUnsupported(
|
|
1200
|
+
"this deployment does not offer credential renewal yet, so a credential here still has to be re-issued by hand when it expires"
|
|
1177
1201
|
);
|
|
1178
1202
|
}
|
|
1179
1203
|
if (!response.ok) {
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1204
|
+
if (!options.listenerMode) {
|
|
1205
|
+
throw new RenewalRefused(
|
|
1206
|
+
response.status,
|
|
1207
|
+
typeof body.error === "string" ? body.error : "unknown",
|
|
1208
|
+
`The deployment did not renew this credential (HTTP ${response.status}).`
|
|
1209
|
+
);
|
|
1210
|
+
}
|
|
1211
|
+
throw new RenewalOutcomeUnknown(`renewal command answered HTTP ${response.status}`);
|
|
1212
|
+
}
|
|
1213
|
+
if (options.listenerMode && body.status !== "accepted" && body.status !== "rejected") {
|
|
1214
|
+
throw new RenewalMalformedResponseError("renewal response did not carry a command status");
|
|
1215
|
+
}
|
|
1216
|
+
if (options.listenerMode && body.status === "accepted" && body.ok !== true) {
|
|
1217
|
+
throw new RenewalMalformedResponseError("renewal response did not confirm acceptance");
|
|
1185
1218
|
}
|
|
1186
1219
|
if (body.status === "rejected") {
|
|
1220
|
+
if (options.listenerMode && typeof body.reason !== "string") {
|
|
1221
|
+
throw new RenewalMalformedResponseError("renewal rejection did not name a reason");
|
|
1222
|
+
}
|
|
1187
1223
|
const reason = typeof body.reason === "string" ? body.reason : "unknown";
|
|
1188
1224
|
if (reason === "renewal_idle_suspended" || reason === "renewal_grant_suspended") {
|
|
1189
1225
|
throw new RenewalSuspended(
|
|
@@ -1231,57 +1267,91 @@ async function requestSuccessor(options) {
|
|
|
1231
1267
|
reason === "renewal_device_unavailable" ? "The standing grant is device-bound, but this renewal carried no device identity. Ask a workspace owner to revoke this grant and mint a new credential on the intended device." : "The standing grant is bound to another device, so CommonSwarm refused renewal. Ask a workspace owner to revoke this grant and mint a new credential on the intended device."
|
|
1232
1268
|
);
|
|
1233
1269
|
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1270
|
+
if (!options.listenerMode) {
|
|
1271
|
+
throw new RenewalRefused(
|
|
1272
|
+
200,
|
|
1273
|
+
reason,
|
|
1274
|
+
`The deployment refused to renew this credential (${reason}).`
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
throw new RenewalMalformedResponseError("renewal rejection named an unknown reason");
|
|
1239
1278
|
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
return null;
|
|
1279
|
+
if (options.listenerMode && body.agent_token !== void 0 && typeof body.agent_token !== "string") {
|
|
1280
|
+
throw new RenewalMalformedResponseError("renewal response carried a malformed agent_token");
|
|
1243
1281
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1282
|
+
const token = typeof body.agent_token === "string" ? body.agent_token : "";
|
|
1283
|
+
if (!options.listenerMode && !token) return null;
|
|
1284
|
+
if (token && !AGENT_TOKEN_RE3.test(token)) {
|
|
1285
|
+
if (!options.listenerMode) throw new RenewalRefused(
|
|
1246
1286
|
response.status,
|
|
1247
1287
|
"malformed_successor",
|
|
1248
1288
|
"The deployment returned a credential that is not shaped like one. It was not stored."
|
|
1249
1289
|
);
|
|
1290
|
+
throw new RenewalMalformedResponseError(
|
|
1291
|
+
"The deployment returned a credential that is not shaped like one. It was not stored."
|
|
1292
|
+
);
|
|
1250
1293
|
}
|
|
1251
1294
|
const tokenId = typeof body.token_id === "string" ? body.token_id : "";
|
|
1252
1295
|
const runId = typeof body.run_id === "string" ? body.run_id : "";
|
|
1253
1296
|
if (!UUID_RE5.test(tokenId) || !UUID_RE5.test(runId) || principalId === null) {
|
|
1254
|
-
throw new RenewalRefused(
|
|
1297
|
+
if (!options.listenerMode) throw new RenewalRefused(
|
|
1255
1298
|
response.status,
|
|
1256
1299
|
"incomplete_successor",
|
|
1257
1300
|
"A successor credential was issued but the deployment did not name its principal, run, or token. It was not stored; ask an owner to revoke it."
|
|
1258
1301
|
);
|
|
1302
|
+
throw new RenewalMalformedResponseError(
|
|
1303
|
+
"A successor credential was issued but the deployment did not name its principal, run, or token. It was not stored; ask an owner to revoke it."
|
|
1304
|
+
);
|
|
1305
|
+
}
|
|
1306
|
+
const parsedIssuedAt = timestamp(body.issued_at);
|
|
1307
|
+
if (options.listenerMode && body.issued_at !== void 0 && parsedIssuedAt === null) {
|
|
1308
|
+
throw new RenewalMalformedResponseError("renewal response carried a malformed issued_at");
|
|
1259
1309
|
}
|
|
1260
|
-
const issuedAt =
|
|
1310
|
+
const issuedAt = parsedIssuedAt ?? now();
|
|
1261
1311
|
const expiresAt = timestamp(body.expires_at);
|
|
1262
1312
|
if (expiresAt === null) {
|
|
1263
|
-
throw new RenewalRefused(
|
|
1313
|
+
if (!options.listenerMode) throw new RenewalRefused(
|
|
1264
1314
|
response.status,
|
|
1265
1315
|
"successor_expiry_missing",
|
|
1266
1316
|
"A successor credential was issued without an expiry. It was not stored, because a credential whose lifetime is unknown cannot be renewed on time."
|
|
1267
1317
|
);
|
|
1318
|
+
throw new RenewalMalformedResponseError(
|
|
1319
|
+
"A successor credential was issued without an expiry. It was not stored, because a credential whose lifetime is unknown cannot be renewed on time."
|
|
1320
|
+
);
|
|
1268
1321
|
}
|
|
1269
1322
|
if (expiresAt - issuedAt > AGENT_TOKEN_MAX_TTL_MS) {
|
|
1270
|
-
throw new RenewalRefused(
|
|
1323
|
+
if (!options.listenerMode) throw new RenewalRefused(
|
|
1271
1324
|
response.status,
|
|
1272
1325
|
"successor_ttl_too_long",
|
|
1273
1326
|
"The deployment issued a successor credential that lasts longer than eight hours. cswarm refused to store it. Agent credentials stay short on purpose; renewal is what makes that survivable."
|
|
1274
1327
|
);
|
|
1328
|
+
throw new RenewalMalformedResponseError(
|
|
1329
|
+
"The deployment issued a successor credential that lasts longer than eight hours. cswarm refused to store it. Agent credentials stay short on purpose; renewal is what makes that survivable."
|
|
1330
|
+
);
|
|
1331
|
+
}
|
|
1332
|
+
const horizonExpiresAt = timestamp(body.horizon_expires_at);
|
|
1333
|
+
if (options.listenerMode && body.horizon_expires_at !== void 0 && body.horizon_expires_at !== null && horizonExpiresAt === null) {
|
|
1334
|
+
throw new RenewalMalformedResponseError("renewal response carried a malformed horizon_expires_at");
|
|
1335
|
+
}
|
|
1336
|
+
const successorsRemaining = count(body.successors_remaining);
|
|
1337
|
+
if (options.listenerMode && body.successors_remaining !== void 0 && body.successors_remaining !== null && successorsRemaining === null) {
|
|
1338
|
+
throw new RenewalMalformedResponseError("renewal response carried a malformed successors_remaining");
|
|
1275
1339
|
}
|
|
1276
1340
|
let wake;
|
|
1277
1341
|
try {
|
|
1278
1342
|
wake = parseOptionalWakeHint(body.wake);
|
|
1279
1343
|
} catch {
|
|
1280
|
-
throw new RenewalRefused(
|
|
1344
|
+
if (!options.listenerMode) throw new RenewalRefused(
|
|
1281
1345
|
response.status,
|
|
1282
1346
|
"malformed_wake",
|
|
1283
1347
|
"The deployment returned a successor credential with a malformed wake hint. It was not stored."
|
|
1284
1348
|
);
|
|
1349
|
+
throw new RenewalMalformedResponseError(
|
|
1350
|
+
"The deployment returned a successor credential with a malformed wake hint. It was not stored."
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
if (!token) {
|
|
1354
|
+
return null;
|
|
1285
1355
|
}
|
|
1286
1356
|
return {
|
|
1287
1357
|
token,
|
|
@@ -1290,12 +1360,12 @@ async function requestSuccessor(options) {
|
|
|
1290
1360
|
runId: runId.toLowerCase(),
|
|
1291
1361
|
issuedAt,
|
|
1292
1362
|
expiresAt,
|
|
1293
|
-
horizonExpiresAt
|
|
1294
|
-
successorsRemaining
|
|
1363
|
+
horizonExpiresAt,
|
|
1364
|
+
successorsRemaining,
|
|
1295
1365
|
...wake === void 0 ? {} : { wake }
|
|
1296
1366
|
};
|
|
1297
1367
|
}
|
|
1298
|
-
var import_node_crypto4, AGENT_TOKEN_DEFAULT_TTL_MS, AGENT_TOKEN_MAX_TTL_MS, RENEWAL_HORIZON_DEFAULT_MS, RENEWAL_HORIZON_MAX_MS, RENEWAL_LEAD_FRACTION, RENEWAL_LEAD_FLOOR_MS, RENEWAL_LEAD_CEILING_MS, RENEWAL_PENDING_RECOVERY_MS, RENEW_TIMEOUT_MS, UUID_RE5, AGENT_TOKEN_RE3, RenewalReauthorisationRequired, RenewalRevoked, RenewalSuspended, RenewalUnsupported, RenewalSuperseded, RenewalOutcomeUnknown, RenewalRefused, REVOCATION_REASONS_LIST, REVOCATION_REASONS, REVOKED_MESSAGE, LOCALLY_EXPIRED_MESSAGE, UNEXPLAINED_REFUSAL_MESSAGE, AgentCredentialSession;
|
|
1368
|
+
var import_node_crypto4, AGENT_TOKEN_DEFAULT_TTL_MS, AGENT_TOKEN_MAX_TTL_MS, RENEWAL_HORIZON_DEFAULT_MS, RENEWAL_HORIZON_MAX_MS, RENEWAL_LEAD_FRACTION, RENEWAL_LEAD_FLOOR_MS, RENEWAL_LEAD_CEILING_MS, RENEWAL_PENDING_RECOVERY_MS, RENEW_TIMEOUT_MS, UUID_RE5, AGENT_TOKEN_RE3, RenewalReauthorisationRequired, RenewalRevoked, RenewalSuspended, RenewalUnsupported, RenewalSuperseded, RenewalOutcomeUnknown, RenewalMalformedResponseError, RenewalCredentialCheckError, RenewalRetryError, RenewalRefused, RenewalUpgradeRequiredError, RENEWAL_UPGRADE_LISTENER_ACTION, RENEWAL_UPGRADE_COMMAND_ACTION, REVOCATION_REASONS_LIST, REVOCATION_REASONS, REVOKED_MESSAGE, LOCALLY_EXPIRED_MESSAGE, UNEXPLAINED_REFUSAL_MESSAGE, AgentCredentialSession;
|
|
1299
1369
|
var init_renewal = __esm({
|
|
1300
1370
|
"src/cloud/renewal.ts"() {
|
|
1301
1371
|
"use strict";
|
|
@@ -1358,6 +1428,28 @@ var init_renewal = __esm({
|
|
|
1358
1428
|
super(message);
|
|
1359
1429
|
}
|
|
1360
1430
|
};
|
|
1431
|
+
RenewalMalformedResponseError = class extends RenewalOutcomeUnknown {
|
|
1432
|
+
name = "RenewalMalformedResponseError";
|
|
1433
|
+
};
|
|
1434
|
+
RenewalCredentialCheckError = class extends Error {
|
|
1435
|
+
constructor(status, code) {
|
|
1436
|
+
super(`renewal command refused the credential (${code})`);
|
|
1437
|
+
this.status = status;
|
|
1438
|
+
this.code = code;
|
|
1439
|
+
}
|
|
1440
|
+
status;
|
|
1441
|
+
code;
|
|
1442
|
+
name = "RenewalCredentialCheckError";
|
|
1443
|
+
};
|
|
1444
|
+
RenewalRetryError = class extends Error {
|
|
1445
|
+
constructor(expiresAt) {
|
|
1446
|
+
super("credential renewal is retrying");
|
|
1447
|
+
this.expiresAt = expiresAt;
|
|
1448
|
+
}
|
|
1449
|
+
expiresAt;
|
|
1450
|
+
name = "RenewalRetryError";
|
|
1451
|
+
code = "renewal_retry";
|
|
1452
|
+
};
|
|
1361
1453
|
RenewalRefused = class extends Error {
|
|
1362
1454
|
constructor(status, code, message) {
|
|
1363
1455
|
super(message);
|
|
@@ -1368,6 +1460,14 @@ var init_renewal = __esm({
|
|
|
1368
1460
|
code;
|
|
1369
1461
|
name = "RenewalRefused";
|
|
1370
1462
|
};
|
|
1463
|
+
RenewalUpgradeRequiredError = class extends RenewalRefused {
|
|
1464
|
+
name = "RenewalUpgradeRequiredError";
|
|
1465
|
+
constructor(minimum, listenerMode = false) {
|
|
1466
|
+
super(426, "upgrade_required", `This copy of cswarm is older than the deployment accepts (minimum ${minimum}). ${listenerMode ? RENEWAL_UPGRADE_LISTENER_ACTION : RENEWAL_UPGRADE_COMMAND_ACTION}`);
|
|
1467
|
+
}
|
|
1468
|
+
};
|
|
1469
|
+
RENEWAL_UPGRADE_LISTENER_ACTION = "Update cswarm, then restart the listener.";
|
|
1470
|
+
RENEWAL_UPGRADE_COMMAND_ACTION = "Update cswarm, then run the command again.";
|
|
1371
1471
|
REVOCATION_REASONS_LIST = [
|
|
1372
1472
|
"renewal_lineage_revoked",
|
|
1373
1473
|
"renewal_grant_revoked",
|
|
@@ -1476,6 +1576,14 @@ var init_renewal = __esm({
|
|
|
1476
1576
|
get expiry() {
|
|
1477
1577
|
return this.expiresAt;
|
|
1478
1578
|
}
|
|
1579
|
+
get renewalDue() {
|
|
1580
|
+
return this.due();
|
|
1581
|
+
}
|
|
1582
|
+
/** Next renewal boundary, or null when this session cannot keep a successor. */
|
|
1583
|
+
get renewalAt() {
|
|
1584
|
+
if (this.unsupported || this.options.store === null || this.expiresAt === null) return null;
|
|
1585
|
+
return renewalDueAt(this.issuedAt, this.expiresAt);
|
|
1586
|
+
}
|
|
1479
1587
|
/**
|
|
1480
1588
|
* ★ RENEWAL REQUIRES SOMEWHERE TO KEEP THE SUCCESSOR, AND THAT IS A SAFETY RULE, NOT A
|
|
1481
1589
|
* CONVENIENCE. A successful renewal SUPERSEDES the predecessor server-side — the fence
|
|
@@ -1485,10 +1593,8 @@ var init_renewal = __esm({
|
|
|
1485
1593
|
* bricked by the feature meant to keep it alive. So with no store, this never renews.
|
|
1486
1594
|
*/
|
|
1487
1595
|
due() {
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
if (this.expiresAt === null) return false;
|
|
1491
|
-
return this.clock() >= renewalDueAt(this.issuedAt, this.expiresAt);
|
|
1596
|
+
const at = this.renewalAt;
|
|
1597
|
+
return at !== null && this.clock() >= at;
|
|
1492
1598
|
}
|
|
1493
1599
|
expired() {
|
|
1494
1600
|
return this.expiresAt !== null && this.clock() >= this.expiresAt;
|
|
@@ -1497,9 +1603,9 @@ var init_renewal = __esm({
|
|
|
1497
1603
|
* The credential to present, renewed first if it is close to expiring.
|
|
1498
1604
|
*
|
|
1499
1605
|
* Renewal happens AHEAD of expiry rather than on a 401, so the common path never shows a
|
|
1500
|
-
* person a failure. A
|
|
1501
|
-
*
|
|
1502
|
-
*
|
|
1606
|
+
* person a failure. A known one-shot 401/403 refusal is fatal with the D-004/D-011
|
|
1607
|
+
* remedy; an unknown outcome may use a still-live predecessor. The listener retries
|
|
1608
|
+
* unknown outcomes and samples recognized authentication refusals.
|
|
1503
1609
|
*/
|
|
1504
1610
|
async bearer() {
|
|
1505
1611
|
if (!this.due()) return this.token;
|
|
@@ -1516,17 +1622,32 @@ var init_renewal = __esm({
|
|
|
1516
1622
|
}
|
|
1517
1623
|
return this.token;
|
|
1518
1624
|
}
|
|
1519
|
-
if (this.expired()
|
|
1625
|
+
if (error2 instanceof RenewalCredentialCheckError && this.expired()) {
|
|
1626
|
+
throw new RenewalRevoked(
|
|
1627
|
+
"predecessor_expired_local",
|
|
1628
|
+
"The current credential expired before it could be renewed. Ask whoever set this agent up for a new credential."
|
|
1629
|
+
);
|
|
1630
|
+
}
|
|
1631
|
+
if (error2 instanceof RenewalCredentialCheckError || error2 instanceof RenewalReauthorisationRequired || error2 instanceof RenewalSuspended || error2 instanceof RenewalRevoked) throw error2;
|
|
1632
|
+
if (this.options.listenerMode && error2 instanceof RenewalUpgradeRequiredError) throw error2;
|
|
1633
|
+
const retryableRenewalOutcome = error2 instanceof RenewalOutcomeUnknown || error2 instanceof RenewalUnsupported || error2 instanceof RenewalRefused;
|
|
1634
|
+
if (this.options.listenerMode && retryableRenewalOutcome && this.expired()) {
|
|
1635
|
+
throw new RenewalRevoked(
|
|
1636
|
+
"predecessor_expired_local",
|
|
1637
|
+
"The current credential expired before it could be renewed. Ask whoever set this agent up for a new credential."
|
|
1638
|
+
);
|
|
1639
|
+
}
|
|
1640
|
+
if (this.options.listenerMode && retryableRenewalOutcome) {
|
|
1641
|
+
throw new RenewalRetryError(this.expiresAt);
|
|
1642
|
+
}
|
|
1643
|
+
if (this.options.listenerMode) throw error2;
|
|
1644
|
+
if (this.expired()) throw error2;
|
|
1520
1645
|
if (error2 instanceof RenewalUnsupported) {
|
|
1521
1646
|
this.unsupported = true;
|
|
1522
1647
|
this.warn(`${error2.message}.`);
|
|
1523
|
-
} else
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
this.warn(
|
|
1527
|
-
`${error2.message}. The credential in hand is still valid, so this command went ahead; renewal is retried on the next one.`
|
|
1528
|
-
);
|
|
1529
|
-
}
|
|
1648
|
+
} else this.warn(
|
|
1649
|
+
`${error2.message}. The credential in hand is still valid, so this command went ahead; renewal is retried on the next one.`
|
|
1650
|
+
);
|
|
1530
1651
|
}
|
|
1531
1652
|
return this.token;
|
|
1532
1653
|
}
|
|
@@ -1568,9 +1689,8 @@ var init_renewal = __esm({
|
|
|
1568
1689
|
workspaceId: this.options.workspaceId,
|
|
1569
1690
|
predecessor: this.token,
|
|
1570
1691
|
commandId,
|
|
1571
|
-
// Only so a 401 on an already-expired credential is reported as expiry, not
|
|
1572
|
-
// revocation (D-004). Never sent on the wire.
|
|
1573
1692
|
expiresAt: this.expiresAt,
|
|
1693
|
+
listenerMode: this.options.listenerMode === true,
|
|
1574
1694
|
...this.options.fetcher ? { fetcher: this.options.fetcher } : {},
|
|
1575
1695
|
now: this.clock
|
|
1576
1696
|
});
|
|
@@ -5109,22 +5229,22 @@ var init_error_envelope = __esm({
|
|
|
5109
5229
|
function parseSignalAttachments(value, options = {}) {
|
|
5110
5230
|
if (options.enabled === false || value === void 0) return [];
|
|
5111
5231
|
if (!Array.isArray(value) || value.length > SIGNAL_ATTACHMENT_MAX) {
|
|
5112
|
-
throw new
|
|
5232
|
+
throw new SignalAttachmentMalformedError("signal read returned malformed attachments");
|
|
5113
5233
|
}
|
|
5114
5234
|
const attachments = [];
|
|
5115
5235
|
const seen = /* @__PURE__ */ new Set();
|
|
5116
5236
|
for (const valueAtPosition of value) {
|
|
5117
5237
|
if (!valueAtPosition || typeof valueAtPosition !== "object" || Array.isArray(valueAtPosition)) {
|
|
5118
|
-
throw new
|
|
5238
|
+
throw new SignalAttachmentMalformedError("signal read returned a malformed attachment");
|
|
5119
5239
|
}
|
|
5120
5240
|
const row = valueAtPosition;
|
|
5121
5241
|
if (typeof row.file_id !== "string" || !UUID_RE9.test(row.file_id) || typeof row.version_n !== "number" || !Number.isSafeInteger(row.version_n) || row.version_n < 1 || typeof row.name !== "string" || row.name.length < 1 || row.name.length > 255 || typeof row.content_type !== "string" || row.content_type.length < 1 || typeof row.size_bytes !== "number" || !Number.isSafeInteger(row.size_bytes) || row.size_bytes < 0) {
|
|
5122
|
-
throw new
|
|
5242
|
+
throw new SignalAttachmentMalformedError("signal read returned malformed attachment metadata");
|
|
5123
5243
|
}
|
|
5124
5244
|
const fileId = row.file_id.toLowerCase();
|
|
5125
5245
|
const key2 = `${fileId}:${row.version_n}`;
|
|
5126
5246
|
if (seen.has(key2)) {
|
|
5127
|
-
throw new
|
|
5247
|
+
throw new SignalAttachmentMalformedError("signal read returned duplicate attachment metadata");
|
|
5128
5248
|
}
|
|
5129
5249
|
seen.add(key2);
|
|
5130
5250
|
attachments.push({
|
|
@@ -5152,12 +5272,15 @@ function formatAttachmentSize(bytes) {
|
|
|
5152
5272
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
5153
5273
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
5154
5274
|
}
|
|
5155
|
-
var SIGNAL_ATTACHMENT_MAX, UUID_RE9;
|
|
5275
|
+
var SIGNAL_ATTACHMENT_MAX, UUID_RE9, SignalAttachmentMalformedError;
|
|
5156
5276
|
var init_attachments = __esm({
|
|
5157
5277
|
"src/cloud/attachments.ts"() {
|
|
5158
5278
|
"use strict";
|
|
5159
5279
|
SIGNAL_ATTACHMENT_MAX = 8;
|
|
5160
5280
|
UUID_RE9 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
5281
|
+
SignalAttachmentMalformedError = class extends Error {
|
|
5282
|
+
name = "SignalAttachmentMalformedError";
|
|
5283
|
+
};
|
|
5161
5284
|
}
|
|
5162
5285
|
});
|
|
5163
5286
|
|
|
@@ -5169,13 +5292,13 @@ function plainTransportError(failureCode = "no_response") {
|
|
|
5169
5292
|
return error2;
|
|
5170
5293
|
}
|
|
5171
5294
|
function plainMalformedError(message) {
|
|
5172
|
-
const error2 = new
|
|
5295
|
+
const error2 = new SignalMalformedError(message);
|
|
5173
5296
|
plainMalformedErrors.add(error2);
|
|
5174
5297
|
return error2;
|
|
5175
5298
|
}
|
|
5176
5299
|
function checkedUuid2(value, field) {
|
|
5177
5300
|
if (typeof value !== "string" || !UUID_RE10.test(value)) {
|
|
5178
|
-
throw new
|
|
5301
|
+
throw new SignalMalformedError(`signal read returned a malformed ${field}`);
|
|
5179
5302
|
}
|
|
5180
5303
|
return value.toLowerCase();
|
|
5181
5304
|
}
|
|
@@ -5184,20 +5307,20 @@ function checkedNullableUuid(value, field) {
|
|
|
5184
5307
|
}
|
|
5185
5308
|
function checkedBoolean(value, field) {
|
|
5186
5309
|
if (typeof value !== "boolean") {
|
|
5187
|
-
throw new
|
|
5310
|
+
throw new SignalMalformedError(`signal read returned a malformed ${field}`);
|
|
5188
5311
|
}
|
|
5189
5312
|
return value;
|
|
5190
5313
|
}
|
|
5191
5314
|
function checkedTimestamp(value, field) {
|
|
5192
5315
|
if (typeof value !== "string" || !Number.isFinite(Date.parse(value))) {
|
|
5193
|
-
throw new
|
|
5316
|
+
throw new SignalMalformedError(`signal read returned a malformed ${field}`);
|
|
5194
5317
|
}
|
|
5195
5318
|
return value;
|
|
5196
5319
|
}
|
|
5197
5320
|
function deliveryCapabilityMarker(row, key2) {
|
|
5198
5321
|
if (row[key2] === void 0) return false;
|
|
5199
5322
|
if (row[key2] !== 1) {
|
|
5200
|
-
throw new
|
|
5323
|
+
throw new SignalMalformedError("signal read returned a malformed delivery capability marker");
|
|
5201
5324
|
}
|
|
5202
5325
|
return true;
|
|
5203
5326
|
}
|
|
@@ -5222,30 +5345,30 @@ function pendingDeliveryCountOf(body, capabilities) {
|
|
|
5222
5345
|
if (!capabilities.deliveryClaim && !capabilities.deliveryAck) return null;
|
|
5223
5346
|
const value = body.pending_delivery_count;
|
|
5224
5347
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
5225
|
-
throw new
|
|
5348
|
+
throw new SignalMalformedError("signal read returned a malformed pending_delivery_count");
|
|
5226
5349
|
}
|
|
5227
5350
|
return value;
|
|
5228
5351
|
}
|
|
5229
5352
|
function parseSignalRecipients(value) {
|
|
5230
5353
|
if (value === void 0) return {};
|
|
5231
5354
|
if (!Array.isArray(value)) {
|
|
5232
|
-
throw new
|
|
5355
|
+
throw new SignalMalformedError("signal read returned a malformed recipients list");
|
|
5233
5356
|
}
|
|
5234
5357
|
const recipients = [];
|
|
5235
5358
|
const seenPositions = /* @__PURE__ */ new Set();
|
|
5236
5359
|
const seenIds = /* @__PURE__ */ new Set();
|
|
5237
5360
|
for (const entry of value) {
|
|
5238
5361
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
5239
|
-
throw new
|
|
5362
|
+
throw new SignalMalformedError("signal read returned a malformed recipients list");
|
|
5240
5363
|
}
|
|
5241
5364
|
const row = entry;
|
|
5242
5365
|
const keys = Object.keys(row).sort();
|
|
5243
5366
|
if (keys.length !== 3 || keys[0] !== "id" || keys[1] !== "kind" || keys[2] !== "position" || typeof row.kind !== "string" || !SIGNAL_RECIPIENT_KINDS.has(row.kind) || typeof row.position !== "number" || !Number.isSafeInteger(row.position) || row.position < 0) {
|
|
5244
|
-
throw new
|
|
5367
|
+
throw new SignalMalformedError("signal read returned a malformed recipients list");
|
|
5245
5368
|
}
|
|
5246
5369
|
const id = checkedUuid2(row.id, "recipients[].id");
|
|
5247
5370
|
if (seenPositions.has(row.position) || seenIds.has(id)) {
|
|
5248
|
-
throw new
|
|
5371
|
+
throw new SignalMalformedError("signal read returned a repeated recipient");
|
|
5249
5372
|
}
|
|
5250
5373
|
seenPositions.add(row.position);
|
|
5251
5374
|
seenIds.add(id);
|
|
@@ -5265,18 +5388,18 @@ function signalAddressesAgent(signal, principalId) {
|
|
|
5265
5388
|
}
|
|
5266
5389
|
function parseSignalRecord(value, options = {}) {
|
|
5267
5390
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5268
|
-
throw new
|
|
5391
|
+
throw new SignalMalformedError("signal read returned a malformed row");
|
|
5269
5392
|
}
|
|
5270
5393
|
const row = value;
|
|
5271
5394
|
if (typeof row.from_kind !== "string" || !["user", "agent"].includes(row.from_kind) || typeof row.kind !== "string" || !SIGNAL_KINDS.has(row.kind) || typeof row.body !== "string" || row.body.length < 1 || !(row.about === null || typeof row.about === "string")) {
|
|
5272
|
-
throw new
|
|
5395
|
+
throw new SignalMalformedError("signal read returned malformed signal data");
|
|
5273
5396
|
}
|
|
5274
5397
|
let senderOwnerRelation = "unknown";
|
|
5275
5398
|
if (row.sender_owner_relation !== void 0) {
|
|
5276
5399
|
if (typeof row.sender_owner_relation !== "string" || !SENDER_OWNER_RELATIONS.has(
|
|
5277
5400
|
row.sender_owner_relation
|
|
5278
5401
|
)) {
|
|
5279
|
-
throw new
|
|
5402
|
+
throw new SignalMalformedError(
|
|
5280
5403
|
"signal read returned a malformed sender_owner_relation"
|
|
5281
5404
|
);
|
|
5282
5405
|
}
|
|
@@ -5352,7 +5475,7 @@ function parseSignalRows(rows3, options) {
|
|
|
5352
5475
|
const parsed = error2 instanceof Error ? error2 : new Error(String(error2));
|
|
5353
5476
|
options.onMalformedRow?.(index, parsed);
|
|
5354
5477
|
if (malformedRows > options.maxMalformedRows) {
|
|
5355
|
-
throw new
|
|
5478
|
+
throw new SignalMalformedError(
|
|
5356
5479
|
`signal read returned too many malformed rows (more than ${options.maxMalformedRows})`
|
|
5357
5480
|
);
|
|
5358
5481
|
}
|
|
@@ -5480,7 +5603,7 @@ function classifySignalReadFailure(error2) {
|
|
|
5480
5603
|
if (error2 instanceof SignalTransportError) {
|
|
5481
5604
|
return { code: "no_response", httpStatus: null, errorConstructor: null };
|
|
5482
5605
|
}
|
|
5483
|
-
if (error2 instanceof SignalMalformedError || error2 instanceof Error && plainMalformedErrors.has(error2)) {
|
|
5606
|
+
if (error2 instanceof SignalMalformedError || error2 instanceof SignalAttachmentMalformedError || error2 instanceof Error && plainMalformedErrors.has(error2)) {
|
|
5484
5607
|
return {
|
|
5485
5608
|
code: "malformed_response",
|
|
5486
5609
|
httpStatus: null,
|
|
@@ -5501,14 +5624,18 @@ function isRestartableReadError(error2) {
|
|
|
5501
5624
|
if (isTransportFollowMessage(error2)) return true;
|
|
5502
5625
|
const http = followHttpDetails(error2);
|
|
5503
5626
|
if (http !== null) {
|
|
5504
|
-
|
|
5627
|
+
if (isConfirmedCredentialHttpFailure(
|
|
5628
|
+
http.status,
|
|
5629
|
+
followErrorEnvelope(error2).error
|
|
5630
|
+
)) {
|
|
5631
|
+
return false;
|
|
5632
|
+
}
|
|
5633
|
+
return http.status === 429 || http.status >= 500 || http.status === 401 || http.status === 403;
|
|
5505
5634
|
}
|
|
5506
5635
|
return false;
|
|
5507
5636
|
}
|
|
5508
5637
|
function isMalformedFollowMessage(error2) {
|
|
5509
|
-
|
|
5510
|
-
if (!(error2 instanceof Error)) return false;
|
|
5511
|
-
return error2.message.startsWith("signal read returned a malformed") || error2.message === "signal read returned malformed JSON" || error2.message === "signal read returned malformed signal data" || error2.message === "signal read returned a malformed row";
|
|
5638
|
+
return error2 instanceof SignalMalformedError || error2 instanceof SignalAttachmentMalformedError || error2 instanceof Error && plainMalformedErrors.has(error2);
|
|
5512
5639
|
}
|
|
5513
5640
|
function checkedLimit(value) {
|
|
5514
5641
|
const limit = value ?? 50;
|
|
@@ -5796,17 +5923,17 @@ async function agentSignalPage(target2, credential, query, options, allowLegacyC
|
|
|
5796
5923
|
}
|
|
5797
5924
|
function parseAgentMemberRow(value) {
|
|
5798
5925
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5799
|
-
throw new
|
|
5926
|
+
throw new SignalMalformedError("member read returned a malformed agent row");
|
|
5800
5927
|
}
|
|
5801
5928
|
const row = value;
|
|
5802
5929
|
if (typeof row.name !== "string") {
|
|
5803
|
-
throw new
|
|
5930
|
+
throw new SignalMalformedError("member read returned a malformed agent name");
|
|
5804
5931
|
}
|
|
5805
5932
|
if (row.model !== void 0 && row.model !== null && typeof row.model !== "string") {
|
|
5806
|
-
throw new
|
|
5933
|
+
throw new SignalMalformedError("member read returned a malformed agent model");
|
|
5807
5934
|
}
|
|
5808
5935
|
if (row.generation !== void 0 && row.generation !== null && (typeof row.generation !== "number" || !Number.isSafeInteger(row.generation) || row.generation < 1)) {
|
|
5809
|
-
throw new
|
|
5936
|
+
throw new SignalMalformedError("member read returned a malformed agent generation");
|
|
5810
5937
|
}
|
|
5811
5938
|
return {
|
|
5812
5939
|
...row.model === void 0 ? {} : { model: row.model },
|
|
@@ -5818,11 +5945,11 @@ function parseAgentMemberRow(value) {
|
|
|
5818
5945
|
}
|
|
5819
5946
|
function parseMemberRow(value) {
|
|
5820
5947
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5821
|
-
throw new
|
|
5948
|
+
throw new SignalMalformedError("member read returned a malformed row");
|
|
5822
5949
|
}
|
|
5823
5950
|
const row = value;
|
|
5824
5951
|
if (typeof row.display_name !== "string") {
|
|
5825
|
-
throw new
|
|
5952
|
+
throw new SignalMalformedError("member read returned a malformed display name");
|
|
5826
5953
|
}
|
|
5827
5954
|
return {
|
|
5828
5955
|
user_id: checkedUuid2(row.user_id, "member user_id"),
|
|
@@ -5831,15 +5958,15 @@ function parseMemberRow(value) {
|
|
|
5831
5958
|
}
|
|
5832
5959
|
function parseAgentIdentity(value) {
|
|
5833
5960
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5834
|
-
throw new
|
|
5961
|
+
throw new SignalMalformedError("member read returned a malformed credential identity");
|
|
5835
5962
|
}
|
|
5836
5963
|
const row = value;
|
|
5837
5964
|
if (row.credential_valid !== true) {
|
|
5838
|
-
throw new
|
|
5965
|
+
throw new SignalMalformedError("member read returned a malformed credential validity");
|
|
5839
5966
|
}
|
|
5840
5967
|
const name = row.workspace_name;
|
|
5841
5968
|
if (name !== void 0 && name !== null && typeof name !== "string") {
|
|
5842
|
-
throw new
|
|
5969
|
+
throw new SignalMalformedError("member read returned a malformed workspace name");
|
|
5843
5970
|
}
|
|
5844
5971
|
return {
|
|
5845
5972
|
credential_valid: true,
|
|
@@ -5870,27 +5997,27 @@ async function readAgentSignalDirectory(target2, token, workspaceId2, fetcherOrO
|
|
|
5870
5997
|
} catch (error2) {
|
|
5871
5998
|
if (error2 instanceof SignalReadTimeoutError) {
|
|
5872
5999
|
if (options.deadlineMs !== void 0) throw error2;
|
|
5873
|
-
throw new
|
|
6000
|
+
throw new SignalTransportError("member read could not reach the cloud service");
|
|
5874
6001
|
}
|
|
5875
6002
|
throw error2;
|
|
5876
6003
|
}
|
|
5877
6004
|
if (result === null) {
|
|
5878
|
-
throw new
|
|
6005
|
+
throw new SignalTransportError("member read could not reach the cloud service");
|
|
5879
6006
|
}
|
|
5880
6007
|
const { response, body } = result;
|
|
5881
6008
|
if (!response.ok) {
|
|
5882
6009
|
throwSignalHttp(response, body, "member read failed");
|
|
5883
6010
|
}
|
|
5884
6011
|
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
5885
|
-
throw new
|
|
6012
|
+
throw new SignalMalformedError("member read returned malformed JSON");
|
|
5886
6013
|
}
|
|
5887
6014
|
const payload = body;
|
|
5888
6015
|
if (!Array.isArray(payload.members)) {
|
|
5889
|
-
throw new
|
|
6016
|
+
throw new SignalMalformedError("member read returned malformed JSON");
|
|
5890
6017
|
}
|
|
5891
6018
|
const agentsRaw = payload.agents;
|
|
5892
6019
|
const agents = agentsRaw === void 0 ? [] : Array.isArray(agentsRaw) ? agentsRaw.map(parseAgentMemberRow) : (() => {
|
|
5893
|
-
throw new
|
|
6020
|
+
throw new SignalMalformedError("member read returned malformed agents");
|
|
5894
6021
|
})();
|
|
5895
6022
|
return {
|
|
5896
6023
|
members: payload.members.map(parseMemberRow),
|
|
@@ -6241,12 +6368,26 @@ function resolveRefusalToleranceMs(raw, warn = () => {
|
|
|
6241
6368
|
}
|
|
6242
6369
|
return parsed;
|
|
6243
6370
|
}
|
|
6371
|
+
function isConfirmedCredentialLossCode(code, surface = "read") {
|
|
6372
|
+
if (typeof code !== "string") return false;
|
|
6373
|
+
const set = surface === "command" ? COMMAND_CONFIRMED_CREDENTIAL_LOSS_CODE_SET : READ_CONFIRMED_CREDENTIAL_LOSS_CODE_SET;
|
|
6374
|
+
return set.has(code);
|
|
6375
|
+
}
|
|
6376
|
+
function isConfirmedCredentialHttpFailure(status, code, surface = "read") {
|
|
6377
|
+
return (status === 401 || status === 403) && isConfirmedCredentialLossCode(code, surface);
|
|
6378
|
+
}
|
|
6244
6379
|
function isRetryableFollowError(error2) {
|
|
6380
|
+
const http = followHttpDetails(error2);
|
|
6381
|
+
if (http !== null && (http.status === 401 || http.status === 403) && !isConfirmedCredentialHttpFailure(
|
|
6382
|
+
http.status,
|
|
6383
|
+
followErrorEnvelope(error2).error
|
|
6384
|
+
)) {
|
|
6385
|
+
return true;
|
|
6386
|
+
}
|
|
6245
6387
|
if (serverRefusedRetry(followErrorEnvelope(error2))) return false;
|
|
6246
6388
|
if (error2 instanceof SignalHostPortsExhaustedError) return true;
|
|
6247
6389
|
if (error2 instanceof SignalReadTimeoutError) return true;
|
|
6248
6390
|
if (isTransportFollowMessage(error2)) return true;
|
|
6249
|
-
const http = followHttpDetails(error2);
|
|
6250
6391
|
if (http) return http.status === 429 || http.status >= 500;
|
|
6251
6392
|
return false;
|
|
6252
6393
|
}
|
|
@@ -6254,18 +6395,27 @@ function isFatalFollowError(error2) {
|
|
|
6254
6395
|
if (isMalformedFollowMessage(error2)) return true;
|
|
6255
6396
|
const http = followHttpDetails(error2);
|
|
6256
6397
|
if (!http) return false;
|
|
6257
|
-
|
|
6398
|
+
if (http.status === 401 || http.status === 403) {
|
|
6399
|
+
return isConfirmedCredentialHttpFailure(
|
|
6400
|
+
http.status,
|
|
6401
|
+
followErrorEnvelope(error2).error
|
|
6402
|
+
);
|
|
6403
|
+
}
|
|
6404
|
+
return http.status === 400 || http.status === 404 || http.status === 426 || http.status >= 400 && http.status < 500 && http.status !== 429;
|
|
6258
6405
|
}
|
|
6259
6406
|
function isFollowCredentialFailure(error2) {
|
|
6260
6407
|
if (!(error2 instanceof Error)) return false;
|
|
6261
6408
|
const http = followHttpDetails(error2);
|
|
6262
6409
|
if (http !== null) {
|
|
6263
|
-
return
|
|
6410
|
+
return isConfirmedCredentialHttpFailure(
|
|
6411
|
+
http.status,
|
|
6412
|
+
followErrorEnvelope(error2).error
|
|
6413
|
+
);
|
|
6264
6414
|
}
|
|
6265
6415
|
if (error2.name === "RenewalReauthorisationRequired" || error2.name === "RenewalRevoked" || error2.name === "RenewalSuspended") {
|
|
6266
6416
|
return true;
|
|
6267
6417
|
}
|
|
6268
|
-
return
|
|
6418
|
+
return error2 instanceof LocalCredentialSecretAbsentError;
|
|
6269
6419
|
}
|
|
6270
6420
|
function followRetryReason(error2) {
|
|
6271
6421
|
if (error2 instanceof SignalReadTimeoutError) return "idle_deadline";
|
|
@@ -6472,7 +6622,7 @@ async function runInboxFollow(options) {
|
|
|
6472
6622
|
}
|
|
6473
6623
|
}
|
|
6474
6624
|
}
|
|
6475
|
-
var UUID_RE10, SIGNAL_KINDS, SIGNAL_BODY_DISPLAY_MAX, SIGNAL_ABOUT_DISPLAY_MAX, SIGNAL_READ_TIMEOUT_MS, SignalReadTimeoutError, SignalHostPortsExhaustedError, SIGNAL_WAIT_MIN_SECONDS, SIGNAL_WAIT_MAX_SECONDS, SIGNAL_WAIT_POLL_MS, SIGNAL_FOLLOW_POLL_MS, SIGNAL_FOLLOW_BACKOFF_INITIAL_MS, SIGNAL_FOLLOW_BACKOFF_MAX_MS, SIGNAL_FOLLOW_SEEN_MAX, SIGNAL_FOLLOW_POST_EMIT_MS, SIGNAL_FOLLOW_PAGE_LIMIT, SignalHttpError, SignalTransportError, SignalMalformedError, plainHttpRetryAfterMs, plainHttpStatus, plainHttpEnvelope, plainTransportErrors, plainTransportFailureCodes, plainMalformedErrors, SENDER_OWNER_RELATIONS, SIGNAL_RECIPIENT_KINDS, READ_RETRY_ATTEMPTS, READ_RETRY_BASE_MS, SIGNAL_STATUS_UNAVAILABLE_MESSAGE, ASK_WAIT_TIMEOUT_MESSAGE, BoundedSignalIdSet, DEFAULT_REFUSAL_TOLERANCE_MS, MAX_REFUSAL_TOLERANCE_MS;
|
|
6625
|
+
var UUID_RE10, SIGNAL_KINDS, SIGNAL_BODY_DISPLAY_MAX, SIGNAL_ABOUT_DISPLAY_MAX, SIGNAL_READ_TIMEOUT_MS, SignalReadTimeoutError, SignalHostPortsExhaustedError, SIGNAL_WAIT_MIN_SECONDS, SIGNAL_WAIT_MAX_SECONDS, SIGNAL_WAIT_POLL_MS, SIGNAL_FOLLOW_POLL_MS, SIGNAL_FOLLOW_BACKOFF_INITIAL_MS, SIGNAL_FOLLOW_BACKOFF_MAX_MS, SIGNAL_FOLLOW_SEEN_MAX, SIGNAL_FOLLOW_POST_EMIT_MS, SIGNAL_FOLLOW_PAGE_LIMIT, SignalHttpError, SignalTransportError, LocalCredentialSecretAbsentError, ListenerCredentialStateMismatchError, SignalMalformedError, plainHttpRetryAfterMs, plainHttpStatus, plainHttpEnvelope, plainTransportErrors, plainTransportFailureCodes, plainMalformedErrors, SENDER_OWNER_RELATIONS, SIGNAL_RECIPIENT_KINDS, READ_RETRY_ATTEMPTS, READ_RETRY_BASE_MS, SIGNAL_STATUS_UNAVAILABLE_MESSAGE, ASK_WAIT_TIMEOUT_MESSAGE, BoundedSignalIdSet, DEFAULT_REFUSAL_TOLERANCE_MS, MAX_REFUSAL_TOLERANCE_MS, CONFIRMED_CREDENTIAL_LOSS_CODES, COMMAND_CONFIRMED_CREDENTIAL_LOSS_CODES, READ_CONFIRMED_CREDENTIAL_LOSS_CODE_SET, COMMAND_CONFIRMED_CREDENTIAL_LOSS_CODE_SET;
|
|
6476
6626
|
var init_signals = __esm({
|
|
6477
6627
|
"src/cloud/signals.ts"() {
|
|
6478
6628
|
"use strict";
|
|
@@ -6529,6 +6679,19 @@ var init_signals = __esm({
|
|
|
6529
6679
|
this.name = "SignalTransportError";
|
|
6530
6680
|
}
|
|
6531
6681
|
};
|
|
6682
|
+
LocalCredentialSecretAbsentError = class extends Error {
|
|
6683
|
+
constructor(message = "agent credential secret is absent") {
|
|
6684
|
+
super(message);
|
|
6685
|
+
this.name = "LocalCredentialSecretAbsentError";
|
|
6686
|
+
}
|
|
6687
|
+
};
|
|
6688
|
+
ListenerCredentialStateMismatchError = class extends LocalCredentialSecretAbsentError {
|
|
6689
|
+
code = "local_credential_state_mismatch";
|
|
6690
|
+
constructor() {
|
|
6691
|
+
super("listener credential state did not preserve the live credential");
|
|
6692
|
+
this.name = "ListenerCredentialStateMismatchError";
|
|
6693
|
+
}
|
|
6694
|
+
};
|
|
6532
6695
|
SignalMalformedError = class extends Error {
|
|
6533
6696
|
constructor(message) {
|
|
6534
6697
|
super(message);
|
|
@@ -6584,6 +6747,19 @@ var init_signals = __esm({
|
|
|
6584
6747
|
};
|
|
6585
6748
|
DEFAULT_REFUSAL_TOLERANCE_MS = 6e4;
|
|
6586
6749
|
MAX_REFUSAL_TOLERANCE_MS = 10 * 6e4;
|
|
6750
|
+
CONFIRMED_CREDENTIAL_LOSS_CODES = Object.freeze([
|
|
6751
|
+
"unauthenticated",
|
|
6752
|
+
"forbidden"
|
|
6753
|
+
]);
|
|
6754
|
+
COMMAND_CONFIRMED_CREDENTIAL_LOSS_CODES = Object.freeze([
|
|
6755
|
+
"unauthenticated"
|
|
6756
|
+
]);
|
|
6757
|
+
READ_CONFIRMED_CREDENTIAL_LOSS_CODE_SET = new Set(
|
|
6758
|
+
CONFIRMED_CREDENTIAL_LOSS_CODES
|
|
6759
|
+
);
|
|
6760
|
+
COMMAND_CONFIRMED_CREDENTIAL_LOSS_CODE_SET = new Set(
|
|
6761
|
+
COMMAND_CONFIRMED_CREDENTIAL_LOSS_CODES
|
|
6762
|
+
);
|
|
6587
6763
|
}
|
|
6588
6764
|
});
|
|
6589
6765
|
|
|
@@ -24589,7 +24765,7 @@ function observationCommandId(signalId) {
|
|
|
24589
24765
|
}
|
|
24590
24766
|
function checkedUuid3(value, field) {
|
|
24591
24767
|
if (typeof value !== "string" || !UUID_RE11.test(value)) {
|
|
24592
|
-
throw new
|
|
24768
|
+
throw new DeliveryMalformedResponseError(
|
|
24593
24769
|
`delivery response returned a malformed ${field}`
|
|
24594
24770
|
);
|
|
24595
24771
|
}
|
|
@@ -24621,13 +24797,13 @@ function daysInMonth(year, month) {
|
|
|
24621
24797
|
}
|
|
24622
24798
|
function checkedRfc3339Timestamp(value, field) {
|
|
24623
24799
|
if (typeof value !== "string") {
|
|
24624
|
-
throw new
|
|
24800
|
+
throw new DeliveryMalformedResponseError(
|
|
24625
24801
|
`delivery response returned a malformed ${field}`
|
|
24626
24802
|
);
|
|
24627
24803
|
}
|
|
24628
24804
|
const match = RFC3339_TIMESTAMP_RE.exec(value);
|
|
24629
24805
|
if (!match) {
|
|
24630
|
-
throw new
|
|
24806
|
+
throw new DeliveryMalformedResponseError(
|
|
24631
24807
|
`delivery response returned a malformed ${field}`
|
|
24632
24808
|
);
|
|
24633
24809
|
}
|
|
@@ -24638,7 +24814,7 @@ function checkedRfc3339Timestamp(value, field) {
|
|
|
24638
24814
|
const minute = parseInt(match[5], 10);
|
|
24639
24815
|
const second = parseInt(match[6], 10);
|
|
24640
24816
|
if (month < 1 || month > 12 || day < 1 || day > daysInMonth(year, month) || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) {
|
|
24641
|
-
throw new
|
|
24817
|
+
throw new DeliveryMalformedResponseError(
|
|
24642
24818
|
`delivery response returned a malformed ${field}`
|
|
24643
24819
|
);
|
|
24644
24820
|
}
|
|
@@ -24646,13 +24822,13 @@ function checkedRfc3339Timestamp(value, field) {
|
|
|
24646
24822
|
const offsetHour = Math.abs(parseInt(match[7], 10));
|
|
24647
24823
|
const offsetMin = parseInt(match[8], 10);
|
|
24648
24824
|
if (offsetHour > 23 || offsetMin < 0 || offsetMin > 59) {
|
|
24649
|
-
throw new
|
|
24825
|
+
throw new DeliveryMalformedResponseError(
|
|
24650
24826
|
`delivery response returned a malformed ${field}`
|
|
24651
24827
|
);
|
|
24652
24828
|
}
|
|
24653
24829
|
}
|
|
24654
24830
|
if (!Number.isFinite(Date.parse(value))) {
|
|
24655
|
-
throw new
|
|
24831
|
+
throw new DeliveryMalformedResponseError(
|
|
24656
24832
|
`delivery response returned a malformed ${field}`
|
|
24657
24833
|
);
|
|
24658
24834
|
}
|
|
@@ -24660,14 +24836,14 @@ function checkedRfc3339Timestamp(value, field) {
|
|
|
24660
24836
|
}
|
|
24661
24837
|
function checkedLiveLease(leasedUntil, now) {
|
|
24662
24838
|
if (Date.parse(leasedUntil) <= now()) {
|
|
24663
|
-
throw new
|
|
24839
|
+
throw new DeliveryMalformedResponseError(
|
|
24664
24840
|
"delivery claim response returned an already expired lease"
|
|
24665
24841
|
);
|
|
24666
24842
|
}
|
|
24667
24843
|
}
|
|
24668
24844
|
function checkedRelation(value) {
|
|
24669
24845
|
if (typeof value !== "string" || !SENDER_OWNER_RELATIONS2.has(value)) {
|
|
24670
|
-
throw new
|
|
24846
|
+
throw new DeliveryMalformedResponseError(
|
|
24671
24847
|
"delivery response returned a malformed sender_owner_relation"
|
|
24672
24848
|
);
|
|
24673
24849
|
}
|
|
@@ -24675,7 +24851,7 @@ function checkedRelation(value) {
|
|
|
24675
24851
|
}
|
|
24676
24852
|
function checkedNonNegativeCount(value, field) {
|
|
24677
24853
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
24678
|
-
throw new
|
|
24854
|
+
throw new DeliveryMalformedResponseError(
|
|
24679
24855
|
`delivery response returned a malformed ${field}`
|
|
24680
24856
|
);
|
|
24681
24857
|
}
|
|
@@ -24683,14 +24859,14 @@ function checkedNonNegativeCount(value, field) {
|
|
|
24683
24859
|
}
|
|
24684
24860
|
function checkedClaimCapabilities(value) {
|
|
24685
24861
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
24686
|
-
throw new
|
|
24862
|
+
throw new DeliveryMalformedResponseError(
|
|
24687
24863
|
"delivery claim response is missing delivery capabilities"
|
|
24688
24864
|
);
|
|
24689
24865
|
}
|
|
24690
24866
|
const row = value;
|
|
24691
24867
|
for (const marker of ["delivery_claim", "delivery_ack", "sender_owner_relation"]) {
|
|
24692
24868
|
if (row[marker] !== 1) {
|
|
24693
|
-
throw new
|
|
24869
|
+
throw new DeliveryMalformedResponseError(
|
|
24694
24870
|
`delivery claim response is missing the ${marker} capability`
|
|
24695
24871
|
);
|
|
24696
24872
|
}
|
|
@@ -24700,7 +24876,7 @@ function checkedClaimCapabilities(value) {
|
|
|
24700
24876
|
function checkedOptionalUuidArray(value, field) {
|
|
24701
24877
|
if (value === void 0) return;
|
|
24702
24878
|
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !UUID_RE11.test(item))) {
|
|
24703
|
-
throw new
|
|
24879
|
+
throw new DeliveryMalformedResponseError(
|
|
24704
24880
|
`delivery response returned a malformed ${field}`
|
|
24705
24881
|
);
|
|
24706
24882
|
}
|
|
@@ -24708,7 +24884,7 @@ function checkedOptionalUuidArray(value, field) {
|
|
|
24708
24884
|
function checkedOptionalArray(value, field) {
|
|
24709
24885
|
if (value === void 0) return;
|
|
24710
24886
|
if (!Array.isArray(value)) {
|
|
24711
|
-
throw new
|
|
24887
|
+
throw new DeliveryMalformedResponseError(
|
|
24712
24888
|
`delivery response returned a malformed ${field}`
|
|
24713
24889
|
);
|
|
24714
24890
|
}
|
|
@@ -24718,7 +24894,7 @@ function checkedRecipientSlot(row) {
|
|
|
24718
24894
|
const hasCount = Object.hasOwn(row, "recipient_count");
|
|
24719
24895
|
if (!hasPosition && !hasCount) return { position: null, count: null };
|
|
24720
24896
|
if (!hasPosition || !hasCount) {
|
|
24721
|
-
throw new
|
|
24897
|
+
throw new DeliveryMalformedResponseError(
|
|
24722
24898
|
"delivery claim response returned a recipient position without its count"
|
|
24723
24899
|
);
|
|
24724
24900
|
}
|
|
@@ -24728,7 +24904,7 @@ function checkedRecipientSlot(row) {
|
|
|
24728
24904
|
);
|
|
24729
24905
|
const count2 = checkedNonNegativeCount(row.recipient_count, "recipient_count");
|
|
24730
24906
|
if (count2 < 1 || position >= count2) {
|
|
24731
|
-
throw new
|
|
24907
|
+
throw new DeliveryMalformedResponseError(
|
|
24732
24908
|
"delivery claim response returned a recipient position outside its set"
|
|
24733
24909
|
);
|
|
24734
24910
|
}
|
|
@@ -24736,7 +24912,7 @@ function checkedRecipientSlot(row) {
|
|
|
24736
24912
|
}
|
|
24737
24913
|
function parseDeliveryRow(value, expected, index, now) {
|
|
24738
24914
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
24739
|
-
throw new
|
|
24915
|
+
throw new DeliveryMalformedResponseError(
|
|
24740
24916
|
"delivery claim response returned a malformed delivery row"
|
|
24741
24917
|
);
|
|
24742
24918
|
}
|
|
@@ -24745,22 +24921,22 @@ function parseDeliveryRow(value, expected, index, now) {
|
|
|
24745
24921
|
try {
|
|
24746
24922
|
signal = parseSignalRecord(row.signal);
|
|
24747
24923
|
} catch {
|
|
24748
|
-
throw new
|
|
24924
|
+
throw new DeliveryMalformedResponseError(
|
|
24749
24925
|
`delivery claim response returned a malformed signal at ${index}`
|
|
24750
24926
|
);
|
|
24751
24927
|
}
|
|
24752
24928
|
if (signal.workspace_id !== expected.workspaceId) {
|
|
24753
|
-
throw new
|
|
24929
|
+
throw new DeliveryMalformedResponseError(
|
|
24754
24930
|
"delivery claim response returned a signal for another workspace"
|
|
24755
24931
|
);
|
|
24756
24932
|
}
|
|
24757
24933
|
if (signal.to_agent !== expected.principalId) {
|
|
24758
|
-
throw new
|
|
24934
|
+
throw new DeliveryMalformedResponseError(
|
|
24759
24935
|
"delivery claim response returned a signal addressed to another agent"
|
|
24760
24936
|
);
|
|
24761
24937
|
}
|
|
24762
24938
|
if (!DELIVERY_KINDS.has(signal.kind)) {
|
|
24763
|
-
throw new
|
|
24939
|
+
throw new DeliveryMalformedResponseError(
|
|
24764
24940
|
"delivery claim response returned a non-direct signal kind"
|
|
24765
24941
|
);
|
|
24766
24942
|
}
|
|
@@ -24781,11 +24957,11 @@ function parseDeliveryRow(value, expected, index, now) {
|
|
|
24781
24957
|
}
|
|
24782
24958
|
function parseClaimSuccess(body, expected, now) {
|
|
24783
24959
|
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
24784
|
-
throw new
|
|
24960
|
+
throw new DeliveryMalformedResponseError("delivery claim response was not an object");
|
|
24785
24961
|
}
|
|
24786
24962
|
const row = body;
|
|
24787
24963
|
if (row.status !== "accepted" || row.ok !== true) {
|
|
24788
|
-
throw new
|
|
24964
|
+
throw new DeliveryMalformedResponseError(
|
|
24789
24965
|
"delivery claim response did not report accepted ok"
|
|
24790
24966
|
);
|
|
24791
24967
|
}
|
|
@@ -24793,7 +24969,7 @@ function parseClaimSuccess(body, expected, now) {
|
|
|
24793
24969
|
checkedOptionalUuidArray(row.event_ids, "event_ids");
|
|
24794
24970
|
checkedOptionalArray(row.events, "events");
|
|
24795
24971
|
if (!Array.isArray(row.deliveries)) {
|
|
24796
|
-
throw new
|
|
24972
|
+
throw new DeliveryMalformedResponseError(
|
|
24797
24973
|
"delivery claim response is missing its deliveries array"
|
|
24798
24974
|
);
|
|
24799
24975
|
}
|
|
@@ -24804,20 +24980,20 @@ function parseClaimSuccess(body, expected, now) {
|
|
|
24804
24980
|
const leaseIds = /* @__PURE__ */ new Set();
|
|
24805
24981
|
for (const delivery of deliveries) {
|
|
24806
24982
|
if (signalIds.has(delivery.signal.id)) {
|
|
24807
|
-
throw new
|
|
24983
|
+
throw new DeliveryMalformedResponseError(
|
|
24808
24984
|
"delivery claim response repeats a signal id"
|
|
24809
24985
|
);
|
|
24810
24986
|
}
|
|
24811
24987
|
signalIds.add(delivery.signal.id);
|
|
24812
24988
|
if (leaseIds.has(delivery.leaseId)) {
|
|
24813
|
-
throw new
|
|
24989
|
+
throw new DeliveryMalformedResponseError(
|
|
24814
24990
|
"delivery claim response repeats a lease id"
|
|
24815
24991
|
);
|
|
24816
24992
|
}
|
|
24817
24993
|
leaseIds.add(delivery.leaseId);
|
|
24818
24994
|
}
|
|
24819
24995
|
if (deliveries.length > 1) {
|
|
24820
|
-
throw new
|
|
24996
|
+
throw new DeliveryMalformedResponseError(
|
|
24821
24997
|
"delivery claim response returned more than one delivery"
|
|
24822
24998
|
);
|
|
24823
24999
|
}
|
|
@@ -24830,7 +25006,7 @@ function parseClaimSuccess(body, expected, now) {
|
|
|
24830
25006
|
"terminal_delivery_failure_count"
|
|
24831
25007
|
);
|
|
24832
25008
|
if (deliveries.length > pendingDeliveryCount) {
|
|
24833
|
-
throw new
|
|
25009
|
+
throw new DeliveryMalformedResponseError(
|
|
24834
25010
|
"delivery claim response returned more deliveries than its pending count"
|
|
24835
25011
|
);
|
|
24836
25012
|
}
|
|
@@ -24838,7 +25014,7 @@ function parseClaimSuccess(body, expected, now) {
|
|
|
24838
25014
|
try {
|
|
24839
25015
|
wake = parseOptionalWakeHint(row.wake);
|
|
24840
25016
|
} catch {
|
|
24841
|
-
throw new
|
|
25017
|
+
throw new DeliveryMalformedResponseError("delivery claim response wake field is malformed");
|
|
24842
25018
|
}
|
|
24843
25019
|
return {
|
|
24844
25020
|
capabilities,
|
|
@@ -24850,25 +25026,25 @@ function parseClaimSuccess(body, expected, now) {
|
|
|
24850
25026
|
}
|
|
24851
25027
|
function parseAckSuccess(body, expected) {
|
|
24852
25028
|
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
24853
|
-
throw new
|
|
25029
|
+
throw new DeliveryMalformedResponseError(
|
|
24854
25030
|
"delivery acknowledgement response was not an object"
|
|
24855
25031
|
);
|
|
24856
25032
|
}
|
|
24857
25033
|
const row = body;
|
|
24858
25034
|
if (row.status !== "accepted" || row.ok !== true) {
|
|
24859
|
-
throw new
|
|
25035
|
+
throw new DeliveryMalformedResponseError(
|
|
24860
25036
|
"delivery acknowledgement response did not report accepted ok"
|
|
24861
25037
|
);
|
|
24862
25038
|
}
|
|
24863
25039
|
checkedOptionalUuidArray(row.event_ids, "event_ids");
|
|
24864
25040
|
checkedOptionalArray(row.events, "events");
|
|
24865
25041
|
if (row.signal_id !== expected.signalId) {
|
|
24866
|
-
throw new
|
|
25042
|
+
throw new DeliveryMalformedResponseError(
|
|
24867
25043
|
"delivery acknowledgement response echoed a different signal id"
|
|
24868
25044
|
);
|
|
24869
25045
|
}
|
|
24870
25046
|
if (row.outcome !== expected.outcome) {
|
|
24871
|
-
throw new
|
|
25047
|
+
throw new DeliveryMalformedResponseError(
|
|
24872
25048
|
"delivery acknowledgement response echoed a different outcome"
|
|
24873
25049
|
);
|
|
24874
25050
|
}
|
|
@@ -24912,18 +25088,23 @@ function assertAckRequest(request) {
|
|
|
24912
25088
|
}
|
|
24913
25089
|
function boundedDeliveryErrorCode(body) {
|
|
24914
25090
|
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
24915
|
-
return
|
|
25091
|
+
return null;
|
|
24916
25092
|
}
|
|
24917
25093
|
const error2 = body.error;
|
|
24918
25094
|
if (typeof error2 === "string" && SERVER_ERROR_CODES_SET.has(error2)) {
|
|
24919
25095
|
return error2;
|
|
24920
25096
|
}
|
|
24921
|
-
return
|
|
25097
|
+
return null;
|
|
24922
25098
|
}
|
|
24923
25099
|
function refusal(response, text) {
|
|
24924
25100
|
let code = DELIVERY_UNKNOWN_ERROR_CODE;
|
|
25101
|
+
let recognizedEnvelope = false;
|
|
24925
25102
|
try {
|
|
24926
|
-
|
|
25103
|
+
const recognizedCode = boundedDeliveryErrorCode(JSON.parse(text));
|
|
25104
|
+
if (recognizedCode !== null) {
|
|
25105
|
+
code = recognizedCode;
|
|
25106
|
+
recognizedEnvelope = true;
|
|
25107
|
+
}
|
|
24927
25108
|
} catch {
|
|
24928
25109
|
}
|
|
24929
25110
|
const retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after"));
|
|
@@ -24931,19 +25112,25 @@ function refusal(response, text) {
|
|
|
24931
25112
|
response.status,
|
|
24932
25113
|
code,
|
|
24933
25114
|
`delivery command failed (HTTP ${response.status}): ${code}`,
|
|
24934
|
-
retryAfterMs
|
|
25115
|
+
retryAfterMs,
|
|
25116
|
+
recognizedEnvelope
|
|
24935
25117
|
);
|
|
24936
25118
|
}
|
|
24937
25119
|
function successBody(response, text, verb) {
|
|
25120
|
+
let body;
|
|
24938
25121
|
try {
|
|
24939
|
-
|
|
25122
|
+
body = JSON.parse(text);
|
|
24940
25123
|
} catch {
|
|
24941
|
-
throw new
|
|
25124
|
+
throw new DeliveryResponseError(
|
|
24942
25125
|
`${verb} response was not JSON (HTTP ${response.status})`
|
|
24943
25126
|
);
|
|
24944
25127
|
}
|
|
25128
|
+
if (!body || typeof body !== "object" || Array.isArray(body) || body.status !== "accepted" || body.ok !== true) {
|
|
25129
|
+
throw new DeliveryResponseError(`${verb} response did not carry an accepted envelope`);
|
|
25130
|
+
}
|
|
25131
|
+
return body;
|
|
24945
25132
|
}
|
|
24946
|
-
var UUID_RE11, RFC3339_TIMESTAMP_RE, DELIVERY_KINDS, SENDER_OWNER_RELATIONS2, DELIVERY_ACK_OUTCOMES, DELIVERY_HANDLED_OUTCOMES, DELIVERY_PROVIDER_PROVEN_OUTCOMES, DELIVERY_REQUEST_TIMEOUT_MS, COMMAND_ID_VALIDATOR_RE, FAILED_TERMINAL_CODES_SET,
|
|
25133
|
+
var UUID_RE11, RFC3339_TIMESTAMP_RE, DELIVERY_KINDS, SENDER_OWNER_RELATIONS2, DELIVERY_ACK_OUTCOMES, DELIVERY_HANDLED_OUTCOMES, DELIVERY_PROVIDER_PROVEN_OUTCOMES, DELIVERY_REQUEST_TIMEOUT_MS, COMMAND_ID_VALIDATOR_RE, FAILED_TERMINAL_CODES_SET, H0_SEAT_CLAIM_REFUSED_CODE, H0_SEAT_LISTENER_STOP_SENTENCE, DELIVERY_FAILED_TERMINAL_CODES, DELIVERY_SESSION_PROOF_CODES, DELIVERY_SERVER_ERROR_CODES, SERVER_ERROR_CODES_SET, DELIVERY_UNKNOWN_ERROR_CODE, DeliveryTransportError, DeliveryHttpError, DeliveryProtocolError, DeliveryResponseError, DeliveryMalformedResponseError, DeliveryCommandClient;
|
|
24947
25134
|
var init_delivery = __esm({
|
|
24948
25135
|
"src/cloud/delivery.ts"() {
|
|
24949
25136
|
"use strict";
|
|
@@ -24984,26 +25171,20 @@ var init_delivery = __esm({
|
|
|
24984
25171
|
"host_session_failed",
|
|
24985
25172
|
"credential_unavailable"
|
|
24986
25173
|
]);
|
|
24987
|
-
|
|
24988
|
-
|
|
24989
|
-
"fresh_auth_required",
|
|
24990
|
-
"invalid_request",
|
|
24991
|
-
"payload_too_large",
|
|
24992
|
-
"forbidden",
|
|
24993
|
-
"delivery_unavailable",
|
|
24994
|
-
"delivery_ack_conflict",
|
|
24995
|
-
"command_id_conflict",
|
|
24996
|
-
"rate_limited",
|
|
24997
|
-
"upgrade_required",
|
|
24998
|
-
"temporarily_unavailable",
|
|
24999
|
-
"internal_error"
|
|
25000
|
-
]);
|
|
25174
|
+
H0_SEAT_CLAIM_REFUSED_CODE = "h0_seat_uses_poll";
|
|
25175
|
+
H0_SEAT_LISTENER_STOP_SENTENCE = "This seat receives messages through the h0 poll. The listener has stopped; no further listener action is needed for this seat";
|
|
25001
25176
|
DELIVERY_FAILED_TERMINAL_CODES = Object.freeze([
|
|
25002
25177
|
"provider_refused",
|
|
25003
25178
|
"local_effect_failed",
|
|
25004
25179
|
"host_session_failed",
|
|
25005
25180
|
"credential_unavailable"
|
|
25006
25181
|
]);
|
|
25182
|
+
DELIVERY_SESSION_PROOF_CODES = Object.freeze([
|
|
25183
|
+
"session_proof_missing",
|
|
25184
|
+
"session_proof_invalid",
|
|
25185
|
+
"session_expired",
|
|
25186
|
+
"session_conflict"
|
|
25187
|
+
]);
|
|
25007
25188
|
DELIVERY_SERVER_ERROR_CODES = Object.freeze([
|
|
25008
25189
|
"unauthenticated",
|
|
25009
25190
|
"fresh_auth_required",
|
|
@@ -25012,12 +25193,18 @@ var init_delivery = __esm({
|
|
|
25012
25193
|
"forbidden",
|
|
25013
25194
|
"delivery_unavailable",
|
|
25014
25195
|
"delivery_ack_conflict",
|
|
25196
|
+
"delivery_not_surfaced",
|
|
25015
25197
|
"command_id_conflict",
|
|
25016
25198
|
"rate_limited",
|
|
25017
25199
|
"upgrade_required",
|
|
25018
25200
|
"temporarily_unavailable",
|
|
25019
|
-
"internal_error"
|
|
25201
|
+
"internal_error",
|
|
25202
|
+
...DELIVERY_SESSION_PROOF_CODES,
|
|
25203
|
+
H0_SEAT_CLAIM_REFUSED_CODE
|
|
25020
25204
|
]);
|
|
25205
|
+
SERVER_ERROR_CODES_SET = new Set(
|
|
25206
|
+
DELIVERY_SERVER_ERROR_CODES
|
|
25207
|
+
);
|
|
25021
25208
|
DELIVERY_UNKNOWN_ERROR_CODE = "unknown_error";
|
|
25022
25209
|
DeliveryTransportError = class extends Error {
|
|
25023
25210
|
constructor(message) {
|
|
@@ -25026,16 +25213,18 @@ var init_delivery = __esm({
|
|
|
25026
25213
|
}
|
|
25027
25214
|
};
|
|
25028
25215
|
DeliveryHttpError = class extends Error {
|
|
25029
|
-
constructor(status, code, message, retryAfterMs = null) {
|
|
25216
|
+
constructor(status, code, message, retryAfterMs = null, recognizedEnvelope = true) {
|
|
25030
25217
|
super(message);
|
|
25031
25218
|
this.status = status;
|
|
25032
25219
|
this.code = code;
|
|
25033
25220
|
this.retryAfterMs = retryAfterMs;
|
|
25221
|
+
this.recognizedEnvelope = recognizedEnvelope;
|
|
25034
25222
|
this.name = "DeliveryHttpError";
|
|
25035
25223
|
}
|
|
25036
25224
|
status;
|
|
25037
25225
|
code;
|
|
25038
25226
|
retryAfterMs;
|
|
25227
|
+
recognizedEnvelope;
|
|
25039
25228
|
};
|
|
25040
25229
|
DeliveryProtocolError = class extends Error {
|
|
25041
25230
|
constructor(message) {
|
|
@@ -25043,6 +25232,18 @@ var init_delivery = __esm({
|
|
|
25043
25232
|
this.name = "DeliveryProtocolError";
|
|
25044
25233
|
}
|
|
25045
25234
|
};
|
|
25235
|
+
DeliveryResponseError = class extends DeliveryProtocolError {
|
|
25236
|
+
constructor(message) {
|
|
25237
|
+
super(message);
|
|
25238
|
+
this.name = "DeliveryResponseError";
|
|
25239
|
+
}
|
|
25240
|
+
};
|
|
25241
|
+
DeliveryMalformedResponseError = class extends DeliveryResponseError {
|
|
25242
|
+
constructor(message) {
|
|
25243
|
+
super(message);
|
|
25244
|
+
this.name = "DeliveryMalformedResponseError";
|
|
25245
|
+
}
|
|
25246
|
+
};
|
|
25046
25247
|
DeliveryCommandClient = class {
|
|
25047
25248
|
constructor(target2, fetcher = fetch, options = {}) {
|
|
25048
25249
|
this.target = target2;
|
|
@@ -46583,6 +46784,9 @@ function formatIdlePollDuration(ms) {
|
|
|
46583
46784
|
if (ms % 1e3 === 0) return `${ms / 1e3}s`;
|
|
46584
46785
|
throw new Error("idle poll duration must be a whole number of seconds");
|
|
46585
46786
|
}
|
|
46787
|
+
function formatIdleWaitDuration(ms) {
|
|
46788
|
+
return formatIdlePollDuration(Math.ceil(ms / 1e3) * 1e3);
|
|
46789
|
+
}
|
|
46586
46790
|
function idlePollDurationExamples() {
|
|
46587
46791
|
const midMs = Math.min(IDLE_POLL_MAX_MS, IDLE_POLL_DEFAULT_MS * 2);
|
|
46588
46792
|
const labels = [];
|
|
@@ -46631,7 +46835,7 @@ function nextIdlePollMs(baseMs, emptyStreak, maxMs = IDLE_POLL_MAX_MS) {
|
|
|
46631
46835
|
return Math.min(maxMs, grown);
|
|
46632
46836
|
}
|
|
46633
46837
|
function idlePollStatusSentence(currentMs) {
|
|
46634
|
-
return `Current idle poll interval: ${
|
|
46838
|
+
return `Current idle poll interval: ${formatIdleWaitDuration(currentMs)}.`;
|
|
46635
46839
|
}
|
|
46636
46840
|
function idlePollHelpSentence(defaultMs = IDLE_POLL_DEFAULT_MS) {
|
|
46637
46841
|
return `listen start --poll-interval sets how long the listener waits after an empty claim (default ${formatIdlePollDuration(defaultMs)}). A whole number plus s or m (for example ${idlePollDurationHint()}), ${idlePollBoundSentence()}. Empty polls double that wait up to ${IDLE_POLL_MAX_LABEL}; any delivery resets it to the configured interval.`;
|
|
@@ -46699,13 +46903,13 @@ function listenerWakePersistWorthy(previous, next, lastPersistMs, nowMs) {
|
|
|
46699
46903
|
function listenerWakeStatusSentence(wake, pollIntervalMs, lastWakeLabel) {
|
|
46700
46904
|
if (wake.mode === LISTENER_WAKE_MODE_PUSH) {
|
|
46701
46905
|
const last = lastWakeLabel === null ? "no wake yet" : `last wake ${lastWakeLabel}`;
|
|
46702
|
-
return `${LISTENER_WAKE_MODE_PUSH} (Realtime), ${last}, reconcile every ${
|
|
46906
|
+
return `${LISTENER_WAKE_MODE_PUSH} (Realtime), ${last}, reconcile every ${formatIdleWaitDuration(pollIntervalMs)}.`;
|
|
46703
46907
|
}
|
|
46704
46908
|
if (wake.errorCode === WAKE_ERROR_CODE_WAKE_BUDGET) {
|
|
46705
|
-
return `Subscribed; claims paused until the minute clears (${WAKE_ERROR_CODE_WAKE_BUDGET}); polling every ${
|
|
46909
|
+
return `Subscribed; claims paused until the minute clears (${WAKE_ERROR_CODE_WAKE_BUDGET}); polling every ${formatIdleWaitDuration(pollIntervalMs)} meanwhile.`;
|
|
46706
46910
|
}
|
|
46707
46911
|
const code = wake.errorCode ?? "disconnected";
|
|
46708
|
-
return `${LISTENER_WAKE_MODE_POLL} every ${
|
|
46912
|
+
return `${LISTENER_WAKE_MODE_POLL} every ${formatIdleWaitDuration(pollIntervalMs)}. Realtime not connected (${code}).`;
|
|
46709
46913
|
}
|
|
46710
46914
|
function createWakeSubscriber(options) {
|
|
46711
46915
|
return new WakeSubscriber(options);
|
|
@@ -50845,12 +51049,15 @@ __export(cli_exports, {
|
|
|
50845
51049
|
agentToolsForTransport: () => agentToolsForTransport,
|
|
50846
51050
|
clampTurnBudgetToCredential: () => clampTurnBudgetToCredential,
|
|
50847
51051
|
claudeUserPromptHookSnippet: () => claudeUserPromptHookSnippet,
|
|
51052
|
+
collectListenerAttendanceEvidence: () => collectListenerAttendanceEvidence,
|
|
50848
51053
|
describeAudience: () => describeAudience,
|
|
50849
51054
|
formatBodySourceConflict: () => formatBodySourceConflict,
|
|
50850
51055
|
formatBodySourceMissing: () => formatBodySourceMissing,
|
|
50851
51056
|
formatBodyUsage: () => formatBodyUsage,
|
|
50852
51057
|
formatOrList: () => formatOrList,
|
|
50853
51058
|
isCliMain: () => isCliMain,
|
|
51059
|
+
isFollowRenewalCredentialFailure: () => isFollowRenewalCredentialFailure,
|
|
51060
|
+
listenerAttendanceProjectDirectory: () => listenerAttendanceProjectDirectory,
|
|
50854
51061
|
listenerFailureMessage: () => listenerFailureMessage,
|
|
50855
51062
|
listenerHostLimits: () => listenerHostLimits,
|
|
50856
51063
|
listenerMainHostLimits: () => listenerMainHostLimits,
|
|
@@ -50858,6 +51065,8 @@ __export(cli_exports, {
|
|
|
50858
51065
|
listenerPollIntervalMs: () => listenerPollIntervalMs,
|
|
50859
51066
|
listenerProviderInstallEvidence: () => listenerProviderInstallEvidence,
|
|
50860
51067
|
listenerRouteConfiguration: () => listenerRouteConfiguration,
|
|
51068
|
+
listenerSettingsHookInstalled: () => listenerSettingsHookInstalled,
|
|
51069
|
+
listenerStartPendingMessage: () => listenerStartPendingMessage,
|
|
50861
51070
|
listenerStatusJson: () => listenerStatusJson,
|
|
50862
51071
|
messageFormatAdvisory: () => messageFormatAdvisory,
|
|
50863
51072
|
postSignalAllowedFlags: () => postSignalAllowedFlags,
|
|
@@ -57436,6 +57645,7 @@ function pendingMainEntry(signal, principalId, provenance, now, options = {}) {
|
|
|
57436
57645
|
init_idle_poll();
|
|
57437
57646
|
init_wake2();
|
|
57438
57647
|
var LISTENER_PAGE_LIMIT = 100;
|
|
57648
|
+
var LISTENER_CLAIM_REFUSALS_BEFORE_READ = 3;
|
|
57439
57649
|
var LISTENER_IDLE_POLL_MS = IDLE_POLL_DEFAULT_MS;
|
|
57440
57650
|
var LISTENER_IDLE_POLL_MAX_MS = IDLE_POLL_MAX_MS;
|
|
57441
57651
|
var LISTENER_DELIVERY_SAFETY_MARGIN_MS = 3e4;
|
|
@@ -57446,8 +57656,71 @@ var LISTENER_DELIVERY_HOLD_BUDGET_MS = LISTENER_PROMPT_TIMEOUT_MS;
|
|
|
57446
57656
|
var LISTENER_DELIVERY_RETRY_INITIAL_MS = 500;
|
|
57447
57657
|
var LISTENER_DELIVERY_RETRY_MAX_MS = 3e4;
|
|
57448
57658
|
var LISTENER_HOST_PORTS_PROBE_MS = 6e4;
|
|
57659
|
+
var CREDENTIAL_LOSS_CONFIRM_MIN_CHECKS = 3;
|
|
57660
|
+
var CREDENTIAL_LOSS_CONFIRM_INTERVAL_MS = 5 * 6e4;
|
|
57661
|
+
var RENEWAL_WINDOW_RETRY_MS = 3e4;
|
|
57662
|
+
var LISTENER_REQUEST_WAIT_FLOOR_MS = 1e3;
|
|
57663
|
+
var RENEWAL_PENDING_WRITE_ALLOWANCE_MS = 5e3;
|
|
57664
|
+
var RENEWAL_SERVER_CLOCK_LEAD_ALLOWANCE_MS = 3e4;
|
|
57665
|
+
var RENEWAL_EXPIRY_HEADROOM_MS = 8e3;
|
|
57666
|
+
var RENEWAL_WINDOW_EXPIRY_MARGIN_MS = 2 * RENEW_TIMEOUT_MS + RENEWAL_SERVER_CLOCK_LEAD_ALLOWANCE_MS + 2 * LISTENER_REQUEST_WAIT_FLOOR_MS + 2 * RENEWAL_PENDING_WRITE_ALLOWANCE_MS + RENEWAL_EXPIRY_HEADROOM_MS;
|
|
57667
|
+
var CREDENTIAL_LOSS_CONFIRM_WINDOW_MS = (CREDENTIAL_LOSS_CONFIRM_MIN_CHECKS - 1) * CREDENTIAL_LOSS_CONFIRM_INTERVAL_MS;
|
|
57668
|
+
var READ_FATAL_ANSWERS = Object.freeze({
|
|
57669
|
+
credentialCodes: CONFIRMED_CREDENTIAL_LOSS_CODES,
|
|
57670
|
+
configurationCode: "delivery_configuration_missing",
|
|
57671
|
+
refusals: Object.freeze([
|
|
57672
|
+
[400, "invalid_request"],
|
|
57673
|
+
[404, "channel_not_found"]
|
|
57674
|
+
])
|
|
57675
|
+
});
|
|
57676
|
+
var COMMAND_FATAL_ANSWERS = Object.freeze({
|
|
57677
|
+
credentialCodes: COMMAND_CONFIRMED_CREDENTIAL_LOSS_CODES,
|
|
57678
|
+
h0FenceCode: H0_SEAT_CLAIM_REFUSED_CODE,
|
|
57679
|
+
refusals: Object.freeze([
|
|
57680
|
+
[400, "invalid_request"],
|
|
57681
|
+
[409, "command_id_conflict"],
|
|
57682
|
+
[409, "delivery_ack_conflict"],
|
|
57683
|
+
[409, "delivery_not_surfaced"],
|
|
57684
|
+
[413, "payload_too_large"],
|
|
57685
|
+
// command/index.ts version gate: the compiled client version cannot change on retry.
|
|
57686
|
+
[426, "upgrade_required"],
|
|
57687
|
+
[403, H0_SEAT_CLAIM_REFUSED_CODE]
|
|
57688
|
+
])
|
|
57689
|
+
});
|
|
57690
|
+
function exactRefusal(set, status, code) {
|
|
57691
|
+
return code !== null && set.some(([s, c]) => s === status && c === code);
|
|
57692
|
+
}
|
|
57693
|
+
function fatalReadRefusal(error2) {
|
|
57694
|
+
const http = followHttpDetails(error2);
|
|
57695
|
+
return http !== null && exactRefusal(
|
|
57696
|
+
READ_FATAL_ANSWERS.refusals,
|
|
57697
|
+
http.status,
|
|
57698
|
+
followErrorEnvelope(error2).error
|
|
57699
|
+
);
|
|
57700
|
+
}
|
|
57701
|
+
function fatalCommandRefusal(error2) {
|
|
57702
|
+
return error2.recognizedEnvelope && exactRefusal(
|
|
57703
|
+
COMMAND_FATAL_ANSWERS.refusals,
|
|
57704
|
+
error2.status,
|
|
57705
|
+
error2.code
|
|
57706
|
+
);
|
|
57707
|
+
}
|
|
57708
|
+
var ListenerH0SeatError = class extends Error {
|
|
57709
|
+
code = H0_SEAT_CLAIM_REFUSED_CODE;
|
|
57710
|
+
constructor() {
|
|
57711
|
+
super(H0_SEAT_LISTENER_STOP_SENTENCE);
|
|
57712
|
+
this.name = "ListenerH0SeatError";
|
|
57713
|
+
}
|
|
57714
|
+
};
|
|
57449
57715
|
var UUID_RE18 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
57450
|
-
var ListenerCapabilityError = class extends Error {
|
|
57716
|
+
var ListenerCapabilityError = class _ListenerCapabilityError extends Error {
|
|
57717
|
+
static CODES = Object.freeze([
|
|
57718
|
+
"sender_relation_capability_missing",
|
|
57719
|
+
"cursor_capability_missing",
|
|
57720
|
+
"delivery_capability_inconsistent",
|
|
57721
|
+
"delivery_configuration_missing"
|
|
57722
|
+
]);
|
|
57723
|
+
static READ_EDGE_CODES = _ListenerCapabilityError.CODES.filter((code) => code !== "delivery_configuration_missing");
|
|
57451
57724
|
code;
|
|
57452
57725
|
constructor(code, message) {
|
|
57453
57726
|
super(message);
|
|
@@ -57455,6 +57728,9 @@ var ListenerCapabilityError = class extends Error {
|
|
|
57455
57728
|
this.code = code;
|
|
57456
57729
|
}
|
|
57457
57730
|
};
|
|
57731
|
+
var ListenerLeaseResponseError = class extends Error {
|
|
57732
|
+
name = "ListenerLeaseResponseError";
|
|
57733
|
+
};
|
|
57458
57734
|
var NullListenerModel = class {
|
|
57459
57735
|
async start() {
|
|
57460
57736
|
throw new Error("listener never starts a model");
|
|
@@ -57472,39 +57748,98 @@ function isRestartableListenerStop(stop) {
|
|
|
57472
57748
|
return isRestartableRuntimeError(stop.error);
|
|
57473
57749
|
}
|
|
57474
57750
|
function isRestartableRuntimeError(error2) {
|
|
57751
|
+
if (error2 instanceof ListenerH0SeatError || error2 instanceof DeliveryHttpError && error2.recognizedEnvelope && error2.code === COMMAND_FATAL_ANSWERS.h0FenceCode) {
|
|
57752
|
+
return false;
|
|
57753
|
+
}
|
|
57475
57754
|
if (error2 instanceof DeliveryTransportError) return true;
|
|
57476
57755
|
if (error2 instanceof DeliveryHttpError) {
|
|
57477
|
-
|
|
57756
|
+
if (isConfirmedCredentialHttpFailure(error2.status, error2.code, "command")) {
|
|
57757
|
+
return false;
|
|
57758
|
+
}
|
|
57759
|
+
return !fatalCommandRefusal(error2);
|
|
57478
57760
|
}
|
|
57761
|
+
if (error2 instanceof DeliveryResponseError) return true;
|
|
57762
|
+
if (error2 instanceof DeliveryMalformedResponseError) return true;
|
|
57763
|
+
if (error2 instanceof ListenerLeaseResponseError) return true;
|
|
57479
57764
|
if (error2 instanceof DeliveryProtocolError) return false;
|
|
57765
|
+
if (error2 instanceof RenewalRetryError) return true;
|
|
57480
57766
|
if (error2 instanceof CommandTransportError) return true;
|
|
57481
57767
|
if (error2 instanceof CommandHttpError) {
|
|
57482
|
-
|
|
57768
|
+
if (isConfirmedCredentialHttpFailure(error2.status, error2.code, "command")) {
|
|
57769
|
+
return false;
|
|
57770
|
+
}
|
|
57771
|
+
return error2.status === 429 || error2.status >= 500 || error2.status === 401 || error2.status === 403;
|
|
57483
57772
|
}
|
|
57484
57773
|
if (error2 instanceof AcpHostError) return TRANSIENT_ACP_CODES.has(error2.code);
|
|
57485
|
-
if (error2 instanceof ListenerCapabilityError)
|
|
57774
|
+
if (error2 instanceof ListenerCapabilityError) {
|
|
57775
|
+
return error2.code !== READ_FATAL_ANSWERS.configurationCode;
|
|
57776
|
+
}
|
|
57486
57777
|
if (error2 instanceof RenewalReauthorisationRequired || error2 instanceof RenewalRevoked) {
|
|
57487
57778
|
return false;
|
|
57488
57779
|
}
|
|
57489
|
-
return isRestartableReadError(error2);
|
|
57780
|
+
return !fatalReadRefusal(error2) && (isRestartableReadError(error2) || isForeignReadResponseFailure(error2));
|
|
57781
|
+
}
|
|
57782
|
+
function isForeignReadResponseFailure(error2) {
|
|
57783
|
+
if (error2 instanceof ListenerCapabilityError) {
|
|
57784
|
+
return error2.code !== READ_FATAL_ANSWERS.configurationCode;
|
|
57785
|
+
}
|
|
57786
|
+
if (classifySignalReadFailure(error2).code === "malformed_response") return true;
|
|
57787
|
+
const http = followHttpDetails(error2);
|
|
57788
|
+
return http !== null && !fatalReadRefusal(error2) && !isConfirmedCredentialHttpFailure(http.status, followErrorEnvelope(error2).error, "read");
|
|
57490
57789
|
}
|
|
57491
57790
|
function isAbort(error2) {
|
|
57492
57791
|
return error2 instanceof Error && error2.name === "AbortError";
|
|
57493
57792
|
}
|
|
57494
|
-
function
|
|
57495
|
-
if (error2 instanceof CommandHttpError) {
|
|
57496
|
-
return error2.status === 401 || error2.status === 403;
|
|
57497
|
-
}
|
|
57793
|
+
function isLocalCredentialLoss(error2) {
|
|
57498
57794
|
if (error2 instanceof RenewalReauthorisationRequired || error2 instanceof RenewalRevoked) {
|
|
57499
57795
|
return true;
|
|
57500
57796
|
}
|
|
57797
|
+
if (followHttpDetails(error2) !== null || error2 instanceof CommandHttpError || error2 instanceof DeliveryHttpError || error2 instanceof SignalHttpError) {
|
|
57798
|
+
return false;
|
|
57799
|
+
}
|
|
57501
57800
|
return isFollowCredentialFailure(error2);
|
|
57502
57801
|
}
|
|
57503
|
-
function
|
|
57504
|
-
|
|
57802
|
+
function isServerConfirmedCredentialLoss(error2) {
|
|
57803
|
+
if (error2 instanceof RenewalCredentialCheckError) {
|
|
57804
|
+
return isConfirmedCredentialHttpFailure(error2.status, error2.code, "command");
|
|
57805
|
+
}
|
|
57806
|
+
if (error2 instanceof CommandHttpError || error2 instanceof DeliveryHttpError) {
|
|
57807
|
+
return isConfirmedCredentialHttpFailure(error2.status, error2.code, "command");
|
|
57808
|
+
}
|
|
57809
|
+
if (error2 instanceof SignalHttpError) {
|
|
57810
|
+
return isConfirmedCredentialHttpFailure(
|
|
57811
|
+
error2.status,
|
|
57812
|
+
error2.envelope.error,
|
|
57813
|
+
"read"
|
|
57814
|
+
);
|
|
57815
|
+
}
|
|
57816
|
+
return isFollowCredentialFailure(error2) && followErrorEnvelope(error2).error !== null;
|
|
57817
|
+
}
|
|
57818
|
+
function isH0SeatClaimRefusal(error2) {
|
|
57819
|
+
return error2 instanceof DeliveryHttpError && error2.recognizedEnvelope && error2.status === 403 && error2.code === COMMAND_FATAL_ANSWERS.h0FenceCode;
|
|
57820
|
+
}
|
|
57821
|
+
function isForeignDeliveryHttpResponse(error2) {
|
|
57822
|
+
return !error2.recognizedEnvelope;
|
|
57823
|
+
}
|
|
57824
|
+
function deliveryRetryCode(error2) {
|
|
57825
|
+
if (error2 instanceof RenewalRetryError) return error2.code;
|
|
57826
|
+
if (error2 instanceof DeliveryResponseError) return "malformed_response";
|
|
57827
|
+
if (error2 instanceof DeliveryHttpError) {
|
|
57828
|
+
return isForeignDeliveryHttpResponse(error2) ? `http_${error2.status}` : error2.code;
|
|
57829
|
+
}
|
|
57830
|
+
return "delivery_unreachable";
|
|
57505
57831
|
}
|
|
57506
57832
|
function isRetryableDeliveryError(error2) {
|
|
57507
|
-
|
|
57833
|
+
if (error2 instanceof RenewalRetryError) return true;
|
|
57834
|
+
if (error2 instanceof DeliveryTransportError) return true;
|
|
57835
|
+
if (error2 instanceof DeliveryResponseError) return true;
|
|
57836
|
+
if (error2 instanceof DeliveryMalformedResponseError) return true;
|
|
57837
|
+
if (!(error2 instanceof DeliveryHttpError)) return false;
|
|
57838
|
+
if (fatalCommandRefusal(error2)) return false;
|
|
57839
|
+
if (isConfirmedCredentialHttpFailure(error2.status, error2.code, "command")) {
|
|
57840
|
+
return false;
|
|
57841
|
+
}
|
|
57842
|
+
return true;
|
|
57508
57843
|
}
|
|
57509
57844
|
function deliveryRetryDelay(attempt, error2, random) {
|
|
57510
57845
|
const exponent = Math.min(20, Math.max(0, attempt - 1));
|
|
@@ -57512,7 +57847,7 @@ function deliveryRetryDelay(attempt, error2, random) {
|
|
|
57512
57847
|
LISTENER_DELIVERY_RETRY_MAX_MS,
|
|
57513
57848
|
LISTENER_DELIVERY_RETRY_INITIAL_MS * 2 ** exponent
|
|
57514
57849
|
);
|
|
57515
|
-
const jitter = Math.floor(Math.max(0, Math.min(1, random())) * ceiling);
|
|
57850
|
+
const jitter = Math.floor((0.5 + Math.max(0, Math.min(1, random())) * 0.5) * ceiling);
|
|
57516
57851
|
const retryAfter = error2 instanceof DeliveryHttpError && error2.status === 429 ? error2.retryAfterMs ?? 0 : 0;
|
|
57517
57852
|
return Math.max(jitter, retryAfter);
|
|
57518
57853
|
}
|
|
@@ -57592,13 +57927,13 @@ async function defaultSleep(ms, signal) {
|
|
|
57592
57927
|
function requireCapabilities(page) {
|
|
57593
57928
|
if (!page.capabilities.senderOwnerRelation) {
|
|
57594
57929
|
throw new ListenerCapabilityError(
|
|
57595
|
-
|
|
57930
|
+
ListenerCapabilityError.CODES[0],
|
|
57596
57931
|
"the read service does not prove sender ownership; refusing to wake a model"
|
|
57597
57932
|
);
|
|
57598
57933
|
}
|
|
57599
57934
|
if (!page.capabilities.cursorAfter || page.legacyCursorFallback) {
|
|
57600
57935
|
throw new ListenerCapabilityError(
|
|
57601
|
-
|
|
57936
|
+
ListenerCapabilityError.CODES[1],
|
|
57602
57937
|
"the read service does not support lossless ascending inbox pages; refusing to wake a model"
|
|
57603
57938
|
);
|
|
57604
57939
|
}
|
|
@@ -57607,13 +57942,13 @@ function classifyDeliveryMode(page, durableConfigured) {
|
|
|
57607
57942
|
const { deliveryClaim, deliveryAck } = page.capabilities;
|
|
57608
57943
|
if (deliveryClaim && !deliveryAck) {
|
|
57609
57944
|
throw new ListenerCapabilityError(
|
|
57610
|
-
|
|
57945
|
+
ListenerCapabilityError.CODES[2],
|
|
57611
57946
|
"the read service delivery capability is inconsistent"
|
|
57612
57947
|
);
|
|
57613
57948
|
}
|
|
57614
57949
|
if ((deliveryClaim || deliveryAck) && !durableConfigured) {
|
|
57615
57950
|
throw new ListenerCapabilityError(
|
|
57616
|
-
|
|
57951
|
+
ListenerCapabilityError.CODES[3],
|
|
57617
57952
|
"durable delivery configuration is required by the read service"
|
|
57618
57953
|
);
|
|
57619
57954
|
}
|
|
@@ -57687,7 +58022,36 @@ async function closeBeforeStart(model, error2) {
|
|
|
57687
58022
|
}
|
|
57688
58023
|
async function runListenerRuntime(options) {
|
|
57689
58024
|
const now = options.now ?? Date.now;
|
|
57690
|
-
const
|
|
58025
|
+
const rawSleep = options.sleep ?? defaultSleep;
|
|
58026
|
+
let waitGeneration = 0;
|
|
58027
|
+
const renewalDeadline = () => {
|
|
58028
|
+
const expiry = options.credentialSession.expiry;
|
|
58029
|
+
return expiry === null || expiry === void 0 ? null : expiry - RENEWAL_WINDOW_EXPIRY_MARGIN_MS;
|
|
58030
|
+
};
|
|
58031
|
+
const renewalWaitBoundary = () => {
|
|
58032
|
+
const expiry = options.credentialSession.expiry;
|
|
58033
|
+
if (expiry === null || expiry === void 0 || now() >= expiry) return null;
|
|
58034
|
+
const dueAt = options.credentialSession.renewalAt;
|
|
58035
|
+
if (dueAt === null) return null;
|
|
58036
|
+
if (dueAt !== void 0 && now() < dueAt) return dueAt;
|
|
58037
|
+
if (dueAt === void 0 && options.credentialSession.renewalDue === false) return null;
|
|
58038
|
+
return renewalDeadline();
|
|
58039
|
+
};
|
|
58040
|
+
const capWaitMs = (ms) => {
|
|
58041
|
+
const boundary = renewalWaitBoundary();
|
|
58042
|
+
const wait = boundary === null ? ms : Math.min(ms, Math.max(0, boundary - now()));
|
|
58043
|
+
return Math.max(LISTENER_REQUEST_WAIT_FLOOR_MS, wait);
|
|
58044
|
+
};
|
|
58045
|
+
const mayWaitForWake = () => {
|
|
58046
|
+
const boundary = renewalWaitBoundary();
|
|
58047
|
+
return boundary === null || now() < boundary;
|
|
58048
|
+
};
|
|
58049
|
+
const sleep2 = async (ms, signal) => {
|
|
58050
|
+
const capped = capWaitMs(ms);
|
|
58051
|
+
if (capped <= 0) return;
|
|
58052
|
+
await rawSleep(capped, signal);
|
|
58053
|
+
if (!signal?.aborted) waitGeneration += 1;
|
|
58054
|
+
};
|
|
57691
58055
|
const random = options.random ?? Math.random;
|
|
57692
58056
|
const pageLimit = options.pageLimit ?? LISTENER_PAGE_LIMIT;
|
|
57693
58057
|
const pollMs = options.pollMs ?? LISTENER_IDLE_POLL_MS;
|
|
@@ -57696,9 +58060,29 @@ async function runListenerRuntime(options) {
|
|
|
57696
58060
|
const deferOverChars = options.deferOverChars ?? null;
|
|
57697
58061
|
const deliveryHoldBudgetMs = options.deliveryHoldBudgetMs ?? LISTENER_DELIVERY_HOLD_BUDGET_MS;
|
|
57698
58062
|
const abort = options.signal;
|
|
58063
|
+
let lastRequestWaitGeneration = -1;
|
|
58064
|
+
let requestGate = Promise.resolve();
|
|
58065
|
+
const paceRequest = async () => {
|
|
58066
|
+
const preceding = requestGate;
|
|
58067
|
+
let release;
|
|
58068
|
+
requestGate = new Promise((resolve7) => {
|
|
58069
|
+
release = resolve7;
|
|
58070
|
+
});
|
|
58071
|
+
await preceding;
|
|
58072
|
+
try {
|
|
58073
|
+
if (lastRequestWaitGeneration === waitGeneration) {
|
|
58074
|
+
await rawSleep(LISTENER_REQUEST_WAIT_FLOOR_MS, abort);
|
|
58075
|
+
if (!abort?.aborted) waitGeneration += 1;
|
|
58076
|
+
}
|
|
58077
|
+
if (abort?.aborted) throw new DOMException("listener stopped", "AbortError");
|
|
58078
|
+
lastRequestWaitGeneration = waitGeneration;
|
|
58079
|
+
} finally {
|
|
58080
|
+
release();
|
|
58081
|
+
}
|
|
58082
|
+
};
|
|
57699
58083
|
const idleSleep = async (hadDelivery) => {
|
|
57700
58084
|
if (hadDelivery) emptyIdleStreak = 0;
|
|
57701
|
-
const intervalMs = nextIdlePollMs(pollMs, emptyIdleStreak, LISTENER_IDLE_POLL_MAX_MS);
|
|
58085
|
+
const intervalMs = capWaitMs(nextIdlePollMs(pollMs, emptyIdleStreak, LISTENER_IDLE_POLL_MAX_MS));
|
|
57702
58086
|
if (!hadDelivery) emptyIdleStreak += 1;
|
|
57703
58087
|
options.onEvent?.({
|
|
57704
58088
|
type: "idle_poll",
|
|
@@ -57853,6 +58237,7 @@ async function runListenerRuntime(options) {
|
|
|
57853
58237
|
let stop;
|
|
57854
58238
|
let wakeSubscriber = options.wake ?? null;
|
|
57855
58239
|
let reconcileDueAt = now();
|
|
58240
|
+
let plannedWakeUntil = null;
|
|
57856
58241
|
const ensureWake = () => {
|
|
57857
58242
|
if (wakeSubscriber === null) {
|
|
57858
58243
|
wakeSubscriber = options.createWake ? options.createWake(options.target) : createWakeSubscriber({ target: options.target, now });
|
|
@@ -57880,6 +58265,102 @@ async function runListenerRuntime(options) {
|
|
|
57880
58265
|
}
|
|
57881
58266
|
return nextIdlePollMs(pollMs, emptyIdleStreak, LISTENER_IDLE_POLL_MAX_MS);
|
|
57882
58267
|
};
|
|
58268
|
+
const wakeWaitUntil = () => Math.max(
|
|
58269
|
+
now() + LISTENER_REQUEST_WAIT_FLOOR_MS,
|
|
58270
|
+
Math.min(reconcileDueAt, now() + waitCapMs(), renewalWaitBoundary() ?? Infinity)
|
|
58271
|
+
);
|
|
58272
|
+
let credentialWindow = null;
|
|
58273
|
+
const confirmedLossCode = (error2) => {
|
|
58274
|
+
if (error2 instanceof DeliveryHttpError || error2 instanceof CommandHttpError || error2 instanceof RenewalCredentialCheckError) {
|
|
58275
|
+
const code2 = error2.code;
|
|
58276
|
+
if (typeof code2 === "string" && /^[a-z0-9_-]{1,96}$/.test(code2)) return code2;
|
|
58277
|
+
}
|
|
58278
|
+
const code = followErrorEnvelope(error2).error;
|
|
58279
|
+
if (typeof code === "string" && /^[a-z0-9_-]{1,96}$/.test(code)) return code;
|
|
58280
|
+
return "unauthenticated";
|
|
58281
|
+
};
|
|
58282
|
+
const emitCredentialCheck = (delayMs) => {
|
|
58283
|
+
if (credentialWindow === null) return;
|
|
58284
|
+
options.onEvent?.({
|
|
58285
|
+
type: "credential_check",
|
|
58286
|
+
stopAt: new Date(credentialWindow.stopAtMs).toISOString(),
|
|
58287
|
+
checks: credentialWindow.checks,
|
|
58288
|
+
code: credentialWindow.code,
|
|
58289
|
+
edge: credentialWindow.edge,
|
|
58290
|
+
...delayMs > 0 ? { nextAttemptAt: new Date(now() + delayMs).toISOString() } : {},
|
|
58291
|
+
...options.credentialSession.expiry == null ? {} : { renewalExpiresAt: new Date(options.credentialSession.expiry).toISOString() },
|
|
58292
|
+
ts: eventTime(now)
|
|
58293
|
+
});
|
|
58294
|
+
};
|
|
58295
|
+
const projectCredentialStopAt = (atMs) => {
|
|
58296
|
+
if (credentialWindow === null) return atMs;
|
|
58297
|
+
const remaining = Math.max(
|
|
58298
|
+
0,
|
|
58299
|
+
CREDENTIAL_LOSS_CONFIRM_MIN_CHECKS - credentialWindow.checks
|
|
58300
|
+
);
|
|
58301
|
+
return Math.max(
|
|
58302
|
+
credentialWindow.startedAtMs + CREDENTIAL_LOSS_CONFIRM_WINDOW_MS,
|
|
58303
|
+
atMs + remaining * credentialCheckDelayMs(atMs)
|
|
58304
|
+
);
|
|
58305
|
+
};
|
|
58306
|
+
const credentialCheckDelayMs = (atMs) => {
|
|
58307
|
+
const expiry = options.credentialSession.expiry;
|
|
58308
|
+
return expiry !== null && expiry !== void 0 && atMs < expiry ? RENEWAL_WINDOW_RETRY_MS : CREDENTIAL_LOSS_CONFIRM_INTERVAL_MS;
|
|
58309
|
+
};
|
|
58310
|
+
const clearCredentialWindow = () => {
|
|
58311
|
+
if (credentialWindow === null) return;
|
|
58312
|
+
credentialWindow = null;
|
|
58313
|
+
options.onEvent?.({
|
|
58314
|
+
type: "credential_check_cleared",
|
|
58315
|
+
ts: eventTime(now)
|
|
58316
|
+
});
|
|
58317
|
+
};
|
|
58318
|
+
const holdCredentialWindow = async (kind, error2) => {
|
|
58319
|
+
const atMs = now();
|
|
58320
|
+
const currentExpiry = options.credentialSession.expiry;
|
|
58321
|
+
if (currentExpiry !== null && currentExpiry !== void 0 && atMs >= currentExpiry) {
|
|
58322
|
+
return { reason: "credential", error: new RenewalRevoked(
|
|
58323
|
+
"predecessor_expired_local",
|
|
58324
|
+
"The current credential expired before it could be renewed. Ask whoever set this agent up for a new credential."
|
|
58325
|
+
) };
|
|
58326
|
+
}
|
|
58327
|
+
if (kind === "confirmed") {
|
|
58328
|
+
if (credentialWindow === null) {
|
|
58329
|
+
credentialWindow = {
|
|
58330
|
+
startedAtMs: atMs,
|
|
58331
|
+
checks: 1,
|
|
58332
|
+
stopAtMs: atMs + CREDENTIAL_LOSS_CONFIRM_WINDOW_MS,
|
|
58333
|
+
code: confirmedLossCode(error2),
|
|
58334
|
+
edge: error2 instanceof DeliveryHttpError || error2 instanceof CommandHttpError || error2 instanceof RenewalCredentialCheckError ? "command" : "read"
|
|
58335
|
+
};
|
|
58336
|
+
} else {
|
|
58337
|
+
credentialWindow.checks += 1;
|
|
58338
|
+
credentialWindow.code = confirmedLossCode(error2);
|
|
58339
|
+
credentialWindow.edge = error2 instanceof DeliveryHttpError || error2 instanceof CommandHttpError || error2 instanceof RenewalCredentialCheckError ? "command" : "read";
|
|
58340
|
+
credentialWindow.stopAtMs = projectCredentialStopAt(atMs);
|
|
58341
|
+
}
|
|
58342
|
+
const window2 = credentialWindow;
|
|
58343
|
+
if (window2.checks >= CREDENTIAL_LOSS_CONFIRM_MIN_CHECKS && atMs >= window2.startedAtMs + CREDENTIAL_LOSS_CONFIRM_WINDOW_MS) {
|
|
58344
|
+
window2.stopAtMs = atMs;
|
|
58345
|
+
emitCredentialCheck(0);
|
|
58346
|
+
return { reason: "credential", error: asError(error2) };
|
|
58347
|
+
}
|
|
58348
|
+
} else if (credentialWindow !== null) {
|
|
58349
|
+
credentialWindow.stopAtMs = Math.max(
|
|
58350
|
+
credentialWindow.stopAtMs,
|
|
58351
|
+
projectCredentialStopAt(atMs)
|
|
58352
|
+
);
|
|
58353
|
+
} else {
|
|
58354
|
+
return "continue";
|
|
58355
|
+
}
|
|
58356
|
+
const delayMs = credentialCheckDelayMs(atMs);
|
|
58357
|
+
emitCredentialCheck(capWaitMs(delayMs));
|
|
58358
|
+
await sleep2(delayMs, abort);
|
|
58359
|
+
if (abort?.aborted) return { reason: "cancelled" };
|
|
58360
|
+
return "continue";
|
|
58361
|
+
};
|
|
58362
|
+
let ackAttempt = 0;
|
|
58363
|
+
let ackReadDue = false;
|
|
57883
58364
|
const sendPreparedAck = async (active) => {
|
|
57884
58365
|
if (active.phase !== "ack_pending" || active.signalId === null || active.leaseId === null || active.leasedUntil === null || active.ack === null) {
|
|
57885
58366
|
return {
|
|
@@ -57893,10 +58374,11 @@ async function runListenerRuntime(options) {
|
|
|
57893
58374
|
} catch (error2) {
|
|
57894
58375
|
return { reason: "fatal", error: asError(error2) };
|
|
57895
58376
|
}
|
|
57896
|
-
let attempt = 0;
|
|
57897
58377
|
while (true) {
|
|
57898
58378
|
try {
|
|
58379
|
+
if (options.credentialSession.renewalDue === true) await paceRequest();
|
|
57899
58380
|
const credential = await options.credentialSession.bearer();
|
|
58381
|
+
await paceRequest();
|
|
57900
58382
|
await deliveryClient.ackAgentDelivery({
|
|
57901
58383
|
workspaceId: options.workspaceId,
|
|
57902
58384
|
credential,
|
|
@@ -57909,6 +58391,9 @@ async function runListenerRuntime(options) {
|
|
|
57909
58391
|
});
|
|
57910
58392
|
await options.deliveryJournal.clearActive(eventTime(now));
|
|
57911
58393
|
after = null;
|
|
58394
|
+
ackAttempt = 0;
|
|
58395
|
+
clearCredentialWindow();
|
|
58396
|
+
options.onEvent?.({ type: "ack_retry_cleared", ts: eventTime(now) });
|
|
57912
58397
|
options.onEvent?.({
|
|
57913
58398
|
type: "delivery_ack",
|
|
57914
58399
|
signalId: active.signalId,
|
|
@@ -57922,37 +58407,75 @@ async function runListenerRuntime(options) {
|
|
|
57922
58407
|
try {
|
|
57923
58408
|
await options.deliveryJournal.clearActive(eventTime(now));
|
|
57924
58409
|
after = null;
|
|
58410
|
+
options.onEvent?.({ type: "ack_retry_cleared", ts: eventTime(now) });
|
|
57925
58411
|
return null;
|
|
57926
58412
|
} catch (clearError) {
|
|
57927
58413
|
return { reason: "fatal", error: asError(clearError) };
|
|
57928
58414
|
}
|
|
57929
58415
|
}
|
|
57930
58416
|
if (abort?.aborted) return { reason: "cancelled" };
|
|
57931
|
-
if (
|
|
58417
|
+
if (isH0SeatClaimRefusal(error2)) {
|
|
58418
|
+
return { reason: "fatal", error: new ListenerH0SeatError() };
|
|
58419
|
+
}
|
|
58420
|
+
if (isLocalCredentialLoss(error2)) {
|
|
57932
58421
|
return { reason: "credential", error: asError(error2) };
|
|
57933
58422
|
}
|
|
58423
|
+
if (isServerConfirmedCredentialLoss(error2)) {
|
|
58424
|
+
const decided = await holdCredentialWindow("confirmed", error2);
|
|
58425
|
+
if (decided !== "continue") return decided;
|
|
58426
|
+
continue;
|
|
58427
|
+
}
|
|
58428
|
+
if (credentialWindow !== null && isRetryableDeliveryError(error2)) {
|
|
58429
|
+
const decided = await holdCredentialWindow("transient", error2);
|
|
58430
|
+
if (decided !== "continue") return decided;
|
|
58431
|
+
continue;
|
|
58432
|
+
}
|
|
57934
58433
|
if (!isRetryableDeliveryError(error2)) {
|
|
57935
58434
|
return { reason: "fatal", error: asError(error2) };
|
|
57936
58435
|
}
|
|
57937
|
-
|
|
57938
|
-
|
|
58436
|
+
ackAttempt += 1;
|
|
58437
|
+
const delayMs = capWaitMs(deliveryRetryDelay(ackAttempt, error2, random));
|
|
58438
|
+
options.onEvent?.({
|
|
58439
|
+
type: "ack_retry",
|
|
58440
|
+
code: deliveryRetryCode(error2),
|
|
58441
|
+
attempt: ackAttempt,
|
|
58442
|
+
delayMs,
|
|
58443
|
+
...error2 instanceof RenewalRetryError && error2.expiresAt !== null ? { renewalExpiresAt: new Date(error2.expiresAt).toISOString() } : {},
|
|
58444
|
+
ts: eventTime(now)
|
|
58445
|
+
});
|
|
58446
|
+
await sleep2(delayMs, abort);
|
|
57939
58447
|
if (abort?.aborted) return { reason: "cancelled" };
|
|
58448
|
+
if (ackAttempt % LISTENER_CLAIM_REFUSALS_BEFORE_READ === 0) {
|
|
58449
|
+
ackReadDue = true;
|
|
58450
|
+
return null;
|
|
58451
|
+
}
|
|
57940
58452
|
}
|
|
57941
58453
|
}
|
|
57942
58454
|
};
|
|
57943
58455
|
try {
|
|
58456
|
+
let forceRead = false;
|
|
58457
|
+
let claimRefusals = 0;
|
|
58458
|
+
let deliveryAttempt = 0;
|
|
57944
58459
|
while (true) {
|
|
57945
58460
|
if (abort?.aborted) {
|
|
57946
58461
|
stop = { reason: "cancelled" };
|
|
57947
58462
|
break;
|
|
57948
58463
|
}
|
|
57949
58464
|
let skipRead = false;
|
|
57950
|
-
if (ready && deliveryMode === "durable_claim" && wakeSubscriber !== null && wakeSubscriber.hasTopic) {
|
|
57951
|
-
const until = Math.
|
|
58465
|
+
if (ready && !forceRead && deliveryMode === "durable_claim" && wakeSubscriber !== null && wakeSubscriber.hasTopic && mayWaitForWake()) {
|
|
58466
|
+
const until = Math.max(
|
|
58467
|
+
now() + LISTENER_REQUEST_WAIT_FLOOR_MS,
|
|
58468
|
+
plannedWakeUntil ?? wakeWaitUntil()
|
|
58469
|
+
);
|
|
58470
|
+
plannedWakeUntil = null;
|
|
58471
|
+
const wakeWaitStartedAt = now();
|
|
57952
58472
|
const reason = await wakeSubscriber.next({
|
|
57953
58473
|
until,
|
|
57954
58474
|
...abort ? { signal: abort } : {}
|
|
57955
58475
|
});
|
|
58476
|
+
const remainingFloorMs = LISTENER_REQUEST_WAIT_FLOOR_MS - (now() - wakeWaitStartedAt);
|
|
58477
|
+
if (remainingFloorMs > 0 && !abort?.aborted) await rawSleep(remainingFloorMs, abort);
|
|
58478
|
+
if (!abort?.aborted) waitGeneration += 1;
|
|
57956
58479
|
emitWake();
|
|
57957
58480
|
if (abort?.aborted) {
|
|
57958
58481
|
stop = { reason: "cancelled" };
|
|
@@ -57969,11 +58492,17 @@ async function runListenerRuntime(options) {
|
|
|
57969
58492
|
skipRead = true;
|
|
57970
58493
|
}
|
|
57971
58494
|
}
|
|
58495
|
+
} else {
|
|
58496
|
+
plannedWakeUntil = null;
|
|
57972
58497
|
}
|
|
57973
58498
|
let page = null;
|
|
58499
|
+
forceRead = false;
|
|
58500
|
+
ackReadDue = false;
|
|
57974
58501
|
if (skipRead) {
|
|
57975
58502
|
} else try {
|
|
58503
|
+
if (options.credentialSession.renewalDue === true) await paceRequest();
|
|
57976
58504
|
const token = await options.credentialSession.bearer();
|
|
58505
|
+
await paceRequest();
|
|
57977
58506
|
page = await readPage({
|
|
57978
58507
|
token,
|
|
57979
58508
|
after,
|
|
@@ -57990,9 +58519,14 @@ async function runListenerRuntime(options) {
|
|
|
57990
58519
|
}
|
|
57991
58520
|
});
|
|
57992
58521
|
requireCapabilities(page);
|
|
58522
|
+
if (page.rawCount >= pageLimit && page.nextCursor === null) {
|
|
58523
|
+
throw new SignalMalformedError(
|
|
58524
|
+
"the read service returned a full page without a safe cursor"
|
|
58525
|
+
);
|
|
58526
|
+
}
|
|
57993
58527
|
applyWakeHint(page.wake);
|
|
57994
58528
|
emitWake();
|
|
57995
|
-
if (
|
|
58529
|
+
if (readEpisodeStartedAtMs !== null) {
|
|
57996
58530
|
const recoveredAtMs = now();
|
|
57997
58531
|
options.onEvent?.({
|
|
57998
58532
|
type: "read_recovered",
|
|
@@ -58005,6 +58539,7 @@ async function runListenerRuntime(options) {
|
|
|
58005
58539
|
readEpisodeAttempts = 0;
|
|
58006
58540
|
}
|
|
58007
58541
|
const nextMode = classifyDeliveryMode(page, durableConfigured);
|
|
58542
|
+
clearCredentialWindow();
|
|
58008
58543
|
if (nextMode !== deliveryMode) {
|
|
58009
58544
|
deliveryMode = nextMode;
|
|
58010
58545
|
options.onEvent?.({
|
|
@@ -58020,32 +58555,52 @@ async function runListenerRuntime(options) {
|
|
|
58020
58555
|
stop = { reason: "cancelled" };
|
|
58021
58556
|
break;
|
|
58022
58557
|
}
|
|
58023
|
-
if (
|
|
58558
|
+
if (isLocalCredentialLoss(error2)) {
|
|
58024
58559
|
stop = { reason: "credential", error: asError(error2) };
|
|
58025
58560
|
break;
|
|
58026
58561
|
}
|
|
58562
|
+
if (isServerConfirmedCredentialLoss(error2)) {
|
|
58563
|
+
const decided = await holdCredentialWindow("confirmed", error2);
|
|
58564
|
+
if (decided !== "continue") {
|
|
58565
|
+
stop = decided;
|
|
58566
|
+
break;
|
|
58567
|
+
}
|
|
58568
|
+
forceRead = true;
|
|
58569
|
+
continue;
|
|
58570
|
+
}
|
|
58027
58571
|
const failure = classifySignalReadFailure(error2);
|
|
58028
|
-
|
|
58572
|
+
const transientRead = error2 instanceof RenewalRetryError || !fatalReadRefusal(error2) && (isRetryableFollowError(error2) || isForeignReadResponseFailure(error2) || failure.code === "aborted" || failure.code === "host_ports_exhausted");
|
|
58573
|
+
if (credentialWindow !== null && transientRead) {
|
|
58574
|
+
const decided = await holdCredentialWindow("transient", error2);
|
|
58575
|
+
if (decided !== "continue") {
|
|
58576
|
+
stop = decided;
|
|
58577
|
+
break;
|
|
58578
|
+
}
|
|
58579
|
+
forceRead = true;
|
|
58580
|
+
continue;
|
|
58581
|
+
}
|
|
58582
|
+
if (transientRead) {
|
|
58029
58583
|
readAttempt += 1;
|
|
58030
|
-
const delayMs = failure.code === "host_ports_exhausted" ? LISTENER_HOST_PORTS_PROBE_MS : nextFollowBackoffMs(readAttempt, null, random);
|
|
58031
|
-
|
|
58032
|
-
|
|
58033
|
-
|
|
58034
|
-
|
|
58035
|
-
readEpisodeAttempts = 0;
|
|
58036
|
-
}
|
|
58037
|
-
readEpisodeAttempts += 1;
|
|
58038
|
-
options.onEvent?.({
|
|
58039
|
-
type: "read_retry",
|
|
58040
|
-
attempt: readAttempt,
|
|
58041
|
-
episodeAttempt: readEpisodeAttempts,
|
|
58042
|
-
episodeStartedAt: new Date(readEpisodeStartedAtMs).toISOString(),
|
|
58043
|
-
failure,
|
|
58044
|
-
delayMs,
|
|
58045
|
-
ts: new Date(failedAtMs).toISOString()
|
|
58046
|
-
});
|
|
58584
|
+
const delayMs = capWaitMs(failure.code === "host_ports_exhausted" ? LISTENER_HOST_PORTS_PROBE_MS : nextFollowBackoffMs(readAttempt, null, random));
|
|
58585
|
+
const failedAtMs = now();
|
|
58586
|
+
if (readEpisodeStartedAtMs === null) {
|
|
58587
|
+
readEpisodeStartedAtMs = failedAtMs;
|
|
58588
|
+
readEpisodeAttempts = 0;
|
|
58047
58589
|
}
|
|
58590
|
+
readEpisodeAttempts += 1;
|
|
58591
|
+
options.onEvent?.({
|
|
58592
|
+
type: "read_retry",
|
|
58593
|
+
attempt: readAttempt,
|
|
58594
|
+
episodeAttempt: readEpisodeAttempts,
|
|
58595
|
+
episodeStartedAt: new Date(readEpisodeStartedAtMs).toISOString(),
|
|
58596
|
+
failure,
|
|
58597
|
+
code: error2 instanceof RenewalRetryError ? error2.code : error2 instanceof ListenerCapabilityError ? error2.code : failure.code === "http_status" ? `http_${failure.httpStatus}` : failure.code,
|
|
58598
|
+
...error2 instanceof RenewalRetryError && error2.expiresAt !== null ? { renewalExpiresAt: new Date(error2.expiresAt).toISOString() } : {},
|
|
58599
|
+
delayMs,
|
|
58600
|
+
ts: new Date(failedAtMs).toISOString()
|
|
58601
|
+
});
|
|
58048
58602
|
await sleep2(delayMs, abort);
|
|
58603
|
+
forceRead = true;
|
|
58049
58604
|
continue;
|
|
58050
58605
|
}
|
|
58051
58606
|
stop = { reason: "fatal", error: asError(error2) };
|
|
@@ -58065,7 +58620,9 @@ async function runListenerRuntime(options) {
|
|
|
58065
58620
|
void (async () => {
|
|
58066
58621
|
let declared = false;
|
|
58067
58622
|
try {
|
|
58623
|
+
if (options.credentialSession.renewalDue === true) await paceRequest();
|
|
58068
58624
|
const credential = await options.credentialSession.bearer();
|
|
58625
|
+
await paceRequest();
|
|
58069
58626
|
const outcome = await declareAgentModel(options.target, {
|
|
58070
58627
|
workspaceId: options.workspaceId,
|
|
58071
58628
|
model: declaredLabel,
|
|
@@ -58108,6 +58665,10 @@ async function runListenerRuntime(options) {
|
|
|
58108
58665
|
stop = { reason: "cancelled" };
|
|
58109
58666
|
break;
|
|
58110
58667
|
}
|
|
58668
|
+
if (ackReadDue) {
|
|
58669
|
+
forceRead = true;
|
|
58670
|
+
continue;
|
|
58671
|
+
}
|
|
58111
58672
|
await idleSleep(true);
|
|
58112
58673
|
continue;
|
|
58113
58674
|
}
|
|
@@ -58152,6 +58713,7 @@ async function runListenerRuntime(options) {
|
|
|
58152
58713
|
stop = ackStop;
|
|
58153
58714
|
break;
|
|
58154
58715
|
}
|
|
58716
|
+
if (ackReadDue) forceRead = true;
|
|
58155
58717
|
continue;
|
|
58156
58718
|
} catch (error2) {
|
|
58157
58719
|
stop = { reason: "fatal", error: asError(error2) };
|
|
@@ -58216,11 +58778,12 @@ async function runListenerRuntime(options) {
|
|
|
58216
58778
|
}
|
|
58217
58779
|
}
|
|
58218
58780
|
let result = null;
|
|
58219
|
-
let deliveryAttempt = 0;
|
|
58220
58781
|
while (result === null && !stop) {
|
|
58221
58782
|
try {
|
|
58222
58783
|
await journal.recordClaimAttempt(eventTime(now));
|
|
58784
|
+
if (options.credentialSession.renewalDue === true) await paceRequest();
|
|
58223
58785
|
const credential = await options.credentialSession.bearer();
|
|
58786
|
+
await paceRequest();
|
|
58224
58787
|
result = await deliveryClient.claimAgentInbox({
|
|
58225
58788
|
workspaceId: options.workspaceId,
|
|
58226
58789
|
credential,
|
|
@@ -58234,32 +58797,79 @@ async function runListenerRuntime(options) {
|
|
|
58234
58797
|
stop = { reason: "cancelled" };
|
|
58235
58798
|
break;
|
|
58236
58799
|
}
|
|
58237
|
-
if (
|
|
58800
|
+
if (isH0SeatClaimRefusal(error2)) {
|
|
58801
|
+
stop = { reason: "fatal", error: new ListenerH0SeatError() };
|
|
58802
|
+
break;
|
|
58803
|
+
}
|
|
58804
|
+
if (isLocalCredentialLoss(error2)) {
|
|
58238
58805
|
stop = { reason: "credential", error: asError(error2) };
|
|
58239
58806
|
break;
|
|
58240
58807
|
}
|
|
58808
|
+
if (isServerConfirmedCredentialLoss(error2)) {
|
|
58809
|
+
const decided = await holdCredentialWindow("confirmed", error2);
|
|
58810
|
+
if (decided !== "continue") {
|
|
58811
|
+
stop = decided;
|
|
58812
|
+
break;
|
|
58813
|
+
}
|
|
58814
|
+
continue;
|
|
58815
|
+
}
|
|
58241
58816
|
if (error2 instanceof DeliveryHttpError && error2.code === "rate_limited") {
|
|
58242
58817
|
wakeSubscriber?.markRateLimited(now());
|
|
58243
58818
|
emitWake();
|
|
58244
58819
|
}
|
|
58245
|
-
|
|
58820
|
+
const retryableClaim = isRetryableDeliveryError(error2);
|
|
58821
|
+
const delayMs = capWaitMs(retryableClaim ? credentialWindow !== null ? RENEWAL_WINDOW_RETRY_MS : deliveryRetryDelay(deliveryAttempt + 1, error2, random) : 0);
|
|
58822
|
+
if (retryableClaim) {
|
|
58823
|
+
claimRefusals += 1;
|
|
58824
|
+
options.onEvent?.({
|
|
58825
|
+
type: "claim_retry",
|
|
58826
|
+
code: deliveryRetryCode(error2),
|
|
58827
|
+
attempts: claimRefusals,
|
|
58828
|
+
delayMs: credentialWindow !== null ? capWaitMs(options.credentialSession.expiry == null ? CREDENTIAL_LOSS_CONFIRM_INTERVAL_MS : RENEWAL_WINDOW_RETRY_MS) : delayMs,
|
|
58829
|
+
...error2 instanceof RenewalRetryError && error2.expiresAt !== null ? { renewalExpiresAt: new Date(error2.expiresAt).toISOString() } : {},
|
|
58830
|
+
ts: eventTime(now)
|
|
58831
|
+
});
|
|
58832
|
+
}
|
|
58833
|
+
if (credentialWindow !== null && retryableClaim) {
|
|
58834
|
+
const decided = await holdCredentialWindow("transient", error2);
|
|
58835
|
+
if (decided !== "continue") {
|
|
58836
|
+
stop = decided;
|
|
58837
|
+
break;
|
|
58838
|
+
}
|
|
58839
|
+
if (claimRefusals >= LISTENER_CLAIM_REFUSALS_BEFORE_READ) {
|
|
58840
|
+
forceRead = true;
|
|
58841
|
+
break;
|
|
58842
|
+
}
|
|
58843
|
+
continue;
|
|
58844
|
+
}
|
|
58845
|
+
if (!retryableClaim) {
|
|
58246
58846
|
stop = { reason: "fatal", error: asError(error2) };
|
|
58247
58847
|
break;
|
|
58248
58848
|
}
|
|
58249
58849
|
deliveryAttempt += 1;
|
|
58250
|
-
const delayMs = deliveryRetryDelay(deliveryAttempt, error2, random);
|
|
58251
58850
|
await sleep2(delayMs, abort);
|
|
58252
58851
|
if (abort?.aborted) {
|
|
58253
58852
|
stop = { reason: "cancelled" };
|
|
58254
58853
|
break;
|
|
58255
58854
|
}
|
|
58855
|
+
if (claimRefusals >= LISTENER_CLAIM_REFUSALS_BEFORE_READ) {
|
|
58856
|
+
forceRead = true;
|
|
58857
|
+
break;
|
|
58858
|
+
}
|
|
58256
58859
|
}
|
|
58257
58860
|
}
|
|
58258
58861
|
if (stop) break;
|
|
58862
|
+
if (forceRead) continue;
|
|
58259
58863
|
if (result === null) {
|
|
58260
58864
|
stop = { reason: "fatal", error: new Error("delivery claim did not settle") };
|
|
58261
58865
|
break;
|
|
58262
58866
|
}
|
|
58867
|
+
if (claimRefusals > 0) {
|
|
58868
|
+
claimRefusals = 0;
|
|
58869
|
+
deliveryAttempt = 0;
|
|
58870
|
+
options.onEvent?.({ type: "claim_retry_cleared", ts: eventTime(now) });
|
|
58871
|
+
}
|
|
58872
|
+
clearCredentialWindow();
|
|
58263
58873
|
applyWakeHint(result.wake);
|
|
58264
58874
|
if (!skipRead && wakeSubscriber !== null && wakeSubscriber.hasTopic) {
|
|
58265
58875
|
wakeSubscriber.noteReconcile(now());
|
|
@@ -58288,7 +58898,7 @@ async function runListenerRuntime(options) {
|
|
|
58288
58898
|
if (active.phase === "leased") {
|
|
58289
58899
|
stop = {
|
|
58290
58900
|
reason: "fatal",
|
|
58291
|
-
error: new
|
|
58901
|
+
error: new ListenerLeaseResponseError("delivery claim replay did not return the stored lease")
|
|
58292
58902
|
};
|
|
58293
58903
|
break;
|
|
58294
58904
|
}
|
|
@@ -58300,12 +58910,14 @@ async function runListenerRuntime(options) {
|
|
|
58300
58910
|
}
|
|
58301
58911
|
if (wakeSubscriber !== null && wakeSubscriber.hasTopic) {
|
|
58302
58912
|
const snap = wakeSubscriber.snapshot(now());
|
|
58303
|
-
|
|
58913
|
+
plannedWakeUntil = wakeWaitUntil();
|
|
58914
|
+
const intervalMs = plannedWakeUntil - now();
|
|
58304
58915
|
if (snap.mode === LISTENER_WAKE_MODE_PUSH) emptyIdleStreak = 0;
|
|
58305
58916
|
else emptyIdleStreak += 1;
|
|
58306
58917
|
options.onEvent?.({
|
|
58307
58918
|
type: "idle_poll",
|
|
58308
58919
|
intervalMs,
|
|
58920
|
+
pushReconcileWait: snap.mode === LISTENER_WAKE_MODE_PUSH && !skipRead,
|
|
58309
58921
|
ts: eventTime(now)
|
|
58310
58922
|
});
|
|
58311
58923
|
emitWake();
|
|
@@ -58322,14 +58934,14 @@ async function runListenerRuntime(options) {
|
|
|
58322
58934
|
});
|
|
58323
58935
|
const leasedUntilMs = Date.parse(claimed.leasedUntil);
|
|
58324
58936
|
if (!Number.isFinite(leasedUntilMs) || leasedUntilMs > now() + LISTENER_DELIVERY_MAX_LEASE_MS + LISTENER_LEASE_CLOCK_SKEW_ALLOWANCE_MS) {
|
|
58325
|
-
stop = { reason: "fatal", error: new
|
|
58937
|
+
stop = { reason: "fatal", error: new ListenerLeaseResponseError("delivery lease deadline is invalid") };
|
|
58326
58938
|
break;
|
|
58327
58939
|
}
|
|
58328
58940
|
if (active.phase === "leased") {
|
|
58329
58941
|
if (!exactRecoveredLease(active, claimed)) {
|
|
58330
58942
|
stop = {
|
|
58331
58943
|
reason: "fatal",
|
|
58332
|
-
error: new
|
|
58944
|
+
error: new ListenerLeaseResponseError("delivery claim replay does not match the stored lease")
|
|
58333
58945
|
};
|
|
58334
58946
|
break;
|
|
58335
58947
|
}
|
|
@@ -58401,8 +59013,20 @@ async function runListenerRuntime(options) {
|
|
|
58401
59013
|
} catch (error2) {
|
|
58402
59014
|
if (abort?.aborted) {
|
|
58403
59015
|
stop = { reason: "cancelled" };
|
|
58404
|
-
} else if (
|
|
59016
|
+
} else if (isLocalCredentialLoss(error2)) {
|
|
58405
59017
|
stop = { reason: "credential", error: asError(error2) };
|
|
59018
|
+
} else if (isServerConfirmedCredentialLoss(error2)) {
|
|
59019
|
+
const decided = await holdCredentialWindow("confirmed", error2);
|
|
59020
|
+
if (decided !== "continue") stop = decided;
|
|
59021
|
+
else {
|
|
59022
|
+
continue;
|
|
59023
|
+
}
|
|
59024
|
+
} else if (credentialWindow !== null && (isRetryableFollowError(error2) || isRetryableDeliveryError(error2))) {
|
|
59025
|
+
const decided = await holdCredentialWindow("transient", error2);
|
|
59026
|
+
if (decided !== "continue") stop = decided;
|
|
59027
|
+
else {
|
|
59028
|
+
continue;
|
|
59029
|
+
}
|
|
58406
59030
|
} else if (isAbort(error2)) {
|
|
58407
59031
|
stop = { reason: "cancelled" };
|
|
58408
59032
|
} else {
|
|
@@ -58430,6 +59054,7 @@ async function runListenerRuntime(options) {
|
|
|
58430
59054
|
stop = ackStop;
|
|
58431
59055
|
break;
|
|
58432
59056
|
}
|
|
59057
|
+
if (ackReadDue) forceRead = true;
|
|
58433
59058
|
} catch (error2) {
|
|
58434
59059
|
stop = { reason: "fatal", error: asError(error2) };
|
|
58435
59060
|
break;
|
|
@@ -58490,10 +59115,28 @@ async function runListenerRuntime(options) {
|
|
|
58490
59115
|
stop = { reason: "cancelled" };
|
|
58491
59116
|
break;
|
|
58492
59117
|
}
|
|
58493
|
-
if (
|
|
59118
|
+
if (isLocalCredentialLoss(error2)) {
|
|
58494
59119
|
stop = { reason: "credential", error: asError(error2) };
|
|
58495
59120
|
break;
|
|
58496
59121
|
}
|
|
59122
|
+
if (isServerConfirmedCredentialLoss(error2)) {
|
|
59123
|
+
const decided = await holdCredentialWindow("confirmed", error2);
|
|
59124
|
+
if (decided !== "continue") {
|
|
59125
|
+
stop = decided;
|
|
59126
|
+
break;
|
|
59127
|
+
}
|
|
59128
|
+
stop = { reason: "cancelled" };
|
|
59129
|
+
break;
|
|
59130
|
+
}
|
|
59131
|
+
if (credentialWindow !== null && (isRetryableFollowError(error2) || isRetryableDeliveryError(error2))) {
|
|
59132
|
+
const decided = await holdCredentialWindow("transient", error2);
|
|
59133
|
+
if (decided !== "continue") {
|
|
59134
|
+
stop = decided;
|
|
59135
|
+
break;
|
|
59136
|
+
}
|
|
59137
|
+
stop = { reason: "cancelled" };
|
|
59138
|
+
break;
|
|
59139
|
+
}
|
|
58497
59140
|
if (isAbort(error2)) {
|
|
58498
59141
|
stop = { reason: "cancelled" };
|
|
58499
59142
|
break;
|
|
@@ -58502,18 +59145,13 @@ async function runListenerRuntime(options) {
|
|
|
58502
59145
|
break;
|
|
58503
59146
|
}
|
|
58504
59147
|
}
|
|
59148
|
+
if (stop?.reason === "cancelled" && abort?.aborted !== true && credentialWindow !== null) {
|
|
59149
|
+
stop = void 0;
|
|
59150
|
+
continue;
|
|
59151
|
+
}
|
|
58505
59152
|
if (stop) break;
|
|
58506
59153
|
const fullPage = page.rawCount >= pageLimit;
|
|
58507
59154
|
if (fullPage) {
|
|
58508
|
-
if (page.nextCursor === null) {
|
|
58509
|
-
stop = {
|
|
58510
|
-
reason: "fatal",
|
|
58511
|
-
error: new Error(
|
|
58512
|
-
"the read service returned a full page without a safe cursor"
|
|
58513
|
-
)
|
|
58514
|
-
};
|
|
58515
|
-
break;
|
|
58516
|
-
}
|
|
58517
59155
|
after = page.nextCursor;
|
|
58518
59156
|
continue;
|
|
58519
59157
|
}
|
|
@@ -58882,6 +59520,19 @@ var MAX_CONTROL_BYTES = 8 * 1024;
|
|
|
58882
59520
|
var CONTROL_TIMEOUT_MS = 2e3;
|
|
58883
59521
|
var START_LOCK_WAIT_MS = 2e3;
|
|
58884
59522
|
var START_LOCK_STALE_MS = 1e4;
|
|
59523
|
+
var LISTENER_RUNNING_STATES = [
|
|
59524
|
+
"starting",
|
|
59525
|
+
"ready",
|
|
59526
|
+
"credential_check",
|
|
59527
|
+
"claim_retry",
|
|
59528
|
+
"ack_retry",
|
|
59529
|
+
"stopping"
|
|
59530
|
+
];
|
|
59531
|
+
var LISTENER_STATUS_STATES = [
|
|
59532
|
+
...LISTENER_RUNNING_STATES,
|
|
59533
|
+
"stopped",
|
|
59534
|
+
"failed"
|
|
59535
|
+
];
|
|
58885
59536
|
var LISTENER_DELIVERY_FAILING_THRESHOLD = 3;
|
|
58886
59537
|
var ListenerAlreadyRunningError = class extends Error {
|
|
58887
59538
|
constructor() {
|
|
@@ -58962,7 +59613,16 @@ var STATUS_ALLOWED_KEYS = /* @__PURE__ */ new Set([
|
|
|
58962
59613
|
"activityPublishFailures",
|
|
58963
59614
|
"activityLastErrorCode",
|
|
58964
59615
|
"idlePollMs",
|
|
58965
|
-
"
|
|
59616
|
+
"pushReconcileWaitMs",
|
|
59617
|
+
"wake",
|
|
59618
|
+
"nextAttemptAt",
|
|
59619
|
+
"credentialStopAt",
|
|
59620
|
+
"renewalExpiresAt",
|
|
59621
|
+
"credentialCheckEdge",
|
|
59622
|
+
"claimRetryCount",
|
|
59623
|
+
"projectDirectory",
|
|
59624
|
+
"targetUrl",
|
|
59625
|
+
"lastRetryEdge"
|
|
58966
59626
|
]);
|
|
58967
59627
|
var STATUS_ACTIVITY_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
58968
59628
|
"activity_credential_failed",
|
|
@@ -59081,9 +59741,16 @@ function parseStatus(raw, rejectUnknownKeys = false) {
|
|
|
59081
59741
|
const readHealth = row.readHealth === void 0 ? void 0 : parseListenerReadHealth(row.readHealth, rejectUnknownKeys);
|
|
59082
59742
|
const heldBackDeliveries = row.heldBackDeliveries === void 0 ? void 0 : parseHeldBackDeliveries(row.heldBackDeliveries);
|
|
59083
59743
|
const wake = row.wake === void 0 ? void 0 : parseListenerWake(row.wake, rejectUnknownKeys);
|
|
59084
|
-
if (row.version !== 1 || typeof row.instanceId !== "string" || !UUID_RE19.test(row.instanceId) || row.provider !== "grok" && row.provider !== "opencode" && row.provider !== "claude" && row.provider !== "codex" || typeof row.profileId !== "string" || typeof row.workspaceId !== "string" || !UUID_RE19.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE19.test(row.principalId) || !Number.isSafeInteger(row.pid) || row.pid < 1 || typeof row.state !== "string" || !
|
|
59744
|
+
if (row.version !== 1 || typeof row.instanceId !== "string" || !UUID_RE19.test(row.instanceId) || row.provider !== "grok" && row.provider !== "opencode" && row.provider !== "claude" && row.provider !== "codex" || typeof row.profileId !== "string" || typeof row.workspaceId !== "string" || !UUID_RE19.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE19.test(row.principalId) || !Number.isSafeInteger(row.pid) || row.pid < 1 || typeof row.state !== "string" || !LISTENER_STATUS_STATES.includes(row.state) || typeof row.startedAt !== "string" || !Number.isFinite(Date.parse(row.startedAt)) || !(row.readyAt === null || typeof row.readyAt === "string" && Number.isFinite(Date.parse(row.readyAt))) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt)) || !(row.stoppedAt === null || typeof row.stoppedAt === "string" && Number.isFinite(Date.parse(row.stoppedAt))) || !nullableUuid3(row.lastSignalId) || !(row.lastErrorCode === null || typeof row.lastErrorCode === "string" && /^[a-z0-9_-]{1,96}$/.test(row.lastErrorCode)) || !(row.lastErrorDetail === void 0 || row.lastErrorDetail === null || typeof row.lastErrorDetail === "string" && row.lastErrorDetail.length > 0 && row.lastErrorDetail.length <= 2048 && !SECRET_SHAPE_RE.test(row.lastErrorDetail)) || !(row.lastErrorReasonCode === void 0 || row.lastErrorReasonCode === null || typeof row.lastErrorReasonCode === "string" && /^[a-z0-9_-]{1,96}$/.test(row.lastErrorReasonCode)) || !(row.providerExecutable === void 0 || row.providerExecutable === null || typeof row.providerExecutable === "string" && (0, import_node_path15.isAbsolute)(row.providerExecutable)) || !(row.providerVersion === void 0 || row.providerVersion === null || typeof row.providerVersion === "string" && SEMVER_RE2.test(row.providerVersion)) || !(row.providerLastMeasuredVersion === void 0 || row.providerLastMeasuredVersion === null || typeof row.providerLastMeasuredVersion === "string" && SEMVER_RE2.test(row.providerLastMeasuredVersion)) || !(row.providerBundledAgentSdkVersion === void 0 || row.providerBundledAgentSdkVersion === null || typeof row.providerBundledAgentSdkVersion === "string" && SEMVER_RE2.test(row.providerBundledAgentSdkVersion)) || !(row.providerBundledClaudeCodeVersion === void 0 || row.providerBundledClaudeCodeVersion === null || typeof row.providerBundledClaudeCodeVersion === "string" && SEMVER_RE2.test(row.providerBundledClaudeCodeVersion)) || !(row.providerMinimumRequiredVersion === void 0 || row.providerMinimumRequiredVersion === null || typeof row.providerMinimumRequiredVersion === "string" && SEMVER_RE2.test(row.providerMinimumRequiredVersion)) || !(row.cswarmVersion === void 0 || row.cswarmVersion === null || typeof row.cswarmVersion === "string" && SEMVER_RE2.test(row.cswarmVersion)) || (row.providerVersion === null || row.providerVersion === void 0) !== (row.providerLastMeasuredVersion === null || row.providerLastMeasuredVersion === void 0) || !(row.lastWorkerStderrTail === void 0 || row.lastWorkerStderrTail === null || typeof row.lastWorkerStderrTail === "string" && row.lastWorkerStderrTail.length > 0 && row.lastWorkerStderrTail.length <= 2048 && !SECRET_SHAPE_RE.test(row.lastWorkerStderrTail)) || typeof row.logPath !== "string" || !(0, import_node_path15.isAbsolute)(row.logPath) || !(row.deliveryMode === void 0 || row.deliveryMode === null || typeof row.deliveryMode === "string" && STATUS_DELIVERY_MODES.has(row.deliveryMode)) || !(row.pendingDeliveryCount === void 0 || nullableCount(row.pendingDeliveryCount)) || !(row.lastTerminalDeliveryFailureCount === void 0 || nullableCount(row.lastTerminalDeliveryFailureCount)) || !(row.lastTerminalDeliveryFailureAt === void 0 || nullableTimestamp3(row.lastTerminalDeliveryFailureAt)) || !(row.lastClaimAt === void 0 || nullableTimestamp3(row.lastClaimAt)) || !(row.lastAckAt === void 0 || nullableTimestamp3(row.lastAckAt)) || !(row.lastAckOutcome === void 0 || row.lastAckOutcome === null || typeof row.lastAckOutcome === "string" && deliveryOutcomes.has(row.lastAckOutcome)) || !(row.consecutiveAckFailureCount === void 0 || nullableCount(row.consecutiveAckFailureCount)) || !(row.lastAckSignalId === void 0 || row.lastAckSignalId === null || typeof row.lastAckSignalId === "string" && UUID_RE19.test(row.lastAckSignalId)) || !(row.currentDeliverySignalId === void 0 || row.currentDeliverySignalId === null || typeof row.currentDeliverySignalId === "string" && UUID_RE19.test(row.currentDeliverySignalId)) || !(row.currentDeliverySince === void 0 || nullableTimestamp3(row.currentDeliverySince)) || heldBackDeliveries === null || !(row.pendingDeliveryCountAt === void 0 || nullableTimestamp3(row.pendingDeliveryCountAt)) || !(row.routeMode === void 0 || typeof row.routeMode === "string" && isStoredListenerRouteMode(row.routeMode)) || !(row.deferOverChars === void 0 || row.deferOverChars === null || typeof row.deferOverChars === "number" && Number.isSafeInteger(row.deferOverChars) && row.deferOverChars >= 1 && row.deferOverChars <= 1e4) || !(row.pendingForMainCount === void 0 || typeof row.pendingForMainCount === "number" && Number.isSafeInteger(row.pendingForMainCount) && row.pendingForMainCount >= 0) || !(row.droppedForMainCount === void 0 || typeof row.droppedForMainCount === "number" && Number.isSafeInteger(row.droppedForMainCount) && row.droppedForMainCount >= 0) || readHealth === null || wake === null || !(row.connectionsOpened === void 0 || typeof row.connectionsOpened === "number" && Number.isSafeInteger(row.connectionsOpened) && row.connectionsOpened >= 0) || !(row.connectionReuseRatio === void 0 || typeof row.connectionReuseRatio === "number" && Number.isFinite(row.connectionReuseRatio) && row.connectionReuseRatio >= 0) || !(row.activityPublishFailures === void 0 || typeof row.activityPublishFailures === "number" && Number.isSafeInteger(row.activityPublishFailures) && row.activityPublishFailures >= 0) || !(row.activityLastErrorCode === void 0 || row.activityLastErrorCode === null || typeof row.activityLastErrorCode === "string" && STATUS_ACTIVITY_ERROR_CODES.has(
|
|
59085
59745
|
row.activityLastErrorCode
|
|
59086
|
-
)) || !(row.idlePollMs === void 0 || row.idlePollMs === null || typeof row.idlePollMs === "number" && Number.isSafeInteger(row.idlePollMs) && row.idlePollMs >= 0)) {
|
|
59746
|
+
)) || !(row.idlePollMs === void 0 || row.idlePollMs === null || typeof row.idlePollMs === "number" && Number.isSafeInteger(row.idlePollMs) && row.idlePollMs >= 0) || !(row.pushReconcileWaitMs === void 0 || row.pushReconcileWaitMs === null || typeof row.pushReconcileWaitMs === "number" && Number.isSafeInteger(row.pushReconcileWaitMs) && row.pushReconcileWaitMs >= 0) || !(row.nextAttemptAt === void 0 || nullableTimestamp3(row.nextAttemptAt)) || !(row.credentialStopAt === void 0 || nullableTimestamp3(row.credentialStopAt)) || !(row.renewalExpiresAt === void 0 || nullableTimestamp3(row.renewalExpiresAt)) || !(row.credentialCheckEdge === void 0 || row.credentialCheckEdge === null || row.credentialCheckEdge === "read" || row.credentialCheckEdge === "command") || !(row.claimRetryCount === void 0 || typeof row.claimRetryCount === "number" && Number.isSafeInteger(row.claimRetryCount) && row.claimRetryCount >= 0) || !(row.projectDirectory === void 0 || typeof row.projectDirectory === "string" && (0, import_node_path15.isAbsolute)(row.projectDirectory)) || !(row.targetUrl === void 0 || typeof row.targetUrl === "string" && (() => {
|
|
59747
|
+
try {
|
|
59748
|
+
const url = new URL(row.targetUrl);
|
|
59749
|
+
return (url.protocol === "https:" || url.protocol === "http:") && url.origin === row.targetUrl && !url.username && !url.password;
|
|
59750
|
+
} catch {
|
|
59751
|
+
return false;
|
|
59752
|
+
}
|
|
59753
|
+
})()) || !(row.lastRetryEdge === void 0 || row.lastRetryEdge === "read" || row.lastRetryEdge === "command" || row.lastRetryEdge === "local")) {
|
|
59087
59754
|
throw new Error("stored listener status is malformed");
|
|
59088
59755
|
}
|
|
59089
59756
|
const routeMode = row.routeMode ?? "worker";
|
|
@@ -59122,12 +59789,14 @@ function parseStatus(raw, rejectUnknownKeys = false) {
|
|
|
59122
59789
|
providerVersion: row.providerVersion ?? null,
|
|
59123
59790
|
providerLastMeasuredVersion: row.providerLastMeasuredVersion ?? null,
|
|
59124
59791
|
...row.cswarmVersion === void 0 ? {} : { cswarmVersion: row.cswarmVersion },
|
|
59792
|
+
...row.renewalExpiresAt === void 0 ? {} : { renewalExpiresAt: row.renewalExpiresAt ?? null },
|
|
59125
59793
|
routeMode,
|
|
59126
59794
|
deferOverChars,
|
|
59127
59795
|
pendingForMainCount: row.pendingForMainCount ?? 0,
|
|
59128
59796
|
droppedForMainCount: row.droppedForMainCount ?? 0,
|
|
59129
59797
|
...readHealth === void 0 ? {} : { readHealth },
|
|
59130
59798
|
...row.idlePollMs === void 0 ? {} : { idlePollMs: row.idlePollMs ?? null },
|
|
59799
|
+
...row.pushReconcileWaitMs === void 0 ? {} : { pushReconcileWaitMs: row.pushReconcileWaitMs ?? null },
|
|
59131
59800
|
...wake === void 0 ? {} : { wake }
|
|
59132
59801
|
};
|
|
59133
59802
|
}
|
|
@@ -59540,7 +60209,9 @@ async function queryListenerControl(paths, command2, timeoutMs = CONTROL_TIMEOUT
|
|
|
59540
60209
|
|
|
59541
60210
|
// src/listener/supervisor.ts
|
|
59542
60211
|
var import_node_crypto20 = require("node:crypto");
|
|
60212
|
+
init_signals();
|
|
59543
60213
|
init_delivery();
|
|
60214
|
+
init_command_client();
|
|
59544
60215
|
init_credential_redaction();
|
|
59545
60216
|
init_session_proof();
|
|
59546
60217
|
init_types2();
|
|
@@ -59549,6 +60220,8 @@ var UUID_RE20 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-
|
|
|
59549
60220
|
var LISTENER_RESTART_MAX_ATTEMPTS = 5;
|
|
59550
60221
|
var LISTENER_RESTART_INITIAL_MS = 1e3;
|
|
59551
60222
|
var LISTENER_RESTART_MAX_MS = 6e4;
|
|
60223
|
+
var LISTENER_RESTART_SUSTAINED_MAX_MS = 5 * 6e4;
|
|
60224
|
+
var LISTENER_RESTART_CLEAN_RUN_MS = 6e4;
|
|
59552
60225
|
function nextListenerRestartMs(attempt, policy = {}, random = Math.random) {
|
|
59553
60226
|
const initial = policy.initialMs ?? LISTENER_RESTART_INITIAL_MS;
|
|
59554
60227
|
const max = policy.maxMs ?? LISTENER_RESTART_MAX_MS;
|
|
@@ -59556,6 +60229,17 @@ function nextListenerRestartMs(attempt, policy = {}, random = Math.random) {
|
|
|
59556
60229
|
const exp = Math.min(max, initial * 2 ** (safeAttempt - 1));
|
|
59557
60230
|
return Math.floor(exp * (0.5 + random() * 0.5));
|
|
59558
60231
|
}
|
|
60232
|
+
function sustainedListenerRestartMs(policy = {}, random = Math.random) {
|
|
60233
|
+
const requested = policy.sustainedMaxMs ?? LISTENER_RESTART_SUSTAINED_MAX_MS;
|
|
60234
|
+
const cap = Math.min(Math.max(0, requested), 5 * 6e4);
|
|
60235
|
+
return Math.floor(cap * (0.5 + random() * 0.5));
|
|
60236
|
+
}
|
|
60237
|
+
function listenerRestartDelayMs(attempt, policy = {}, random = Math.random) {
|
|
60238
|
+
if (policy.maxAttempts === void 0 && attempt > LISTENER_RESTART_MAX_ATTEMPTS) {
|
|
60239
|
+
return sustainedListenerRestartMs(policy, random);
|
|
60240
|
+
}
|
|
60241
|
+
return nextListenerRestartMs(attempt, policy, random);
|
|
60242
|
+
}
|
|
59559
60243
|
async function defaultRestartSleep(ms, signal) {
|
|
59560
60244
|
if (ms <= 0 || signal.aborted) return;
|
|
59561
60245
|
await new Promise((resolve7) => {
|
|
@@ -59585,9 +60269,18 @@ function safeErrorCode(error2) {
|
|
|
59585
60269
|
const normalized = explicit.toLowerCase().replace(/[^a-z0-9_-]+/g, "_");
|
|
59586
60270
|
if (normalized.length > 0) return normalized.slice(0, 96);
|
|
59587
60271
|
}
|
|
60272
|
+
const read = classifySignalReadFailure(error2);
|
|
60273
|
+
if (read.code === "http_status") return `http_${read.httpStatus}`;
|
|
60274
|
+
if (read.code === "malformed_response") return read.code;
|
|
60275
|
+
if (error2 instanceof DeliveryResponseError) return "malformed_response";
|
|
59588
60276
|
const name = error2.name.toLowerCase().replace(/[^a-z0-9_-]+/g, "_");
|
|
59589
60277
|
return name.slice(0, 96) || "listener_error";
|
|
59590
60278
|
}
|
|
60279
|
+
function retryEdgeOf(error2) {
|
|
60280
|
+
if (error2 instanceof DeliveryHttpError || error2 instanceof DeliveryResponseError || error2 instanceof DeliveryTransportError || error2 instanceof CommandHttpError || error2 instanceof CommandTransportError) return "command";
|
|
60281
|
+
if (classifySignalReadFailure(error2).code !== "unclassified") return "read";
|
|
60282
|
+
return "local";
|
|
60283
|
+
}
|
|
59591
60284
|
function localDiagnostic(message, maxChars) {
|
|
59592
60285
|
const redacted = message.replace(
|
|
59593
60286
|
new RegExp(SECRET_SHAPE_RE.source, "gi"),
|
|
@@ -59658,6 +60351,8 @@ async function runListenerSupervisor(options) {
|
|
|
59658
60351
|
profileId: options.profileId,
|
|
59659
60352
|
workspaceId: options.workspaceId.toLowerCase(),
|
|
59660
60353
|
principalId: options.principalId.toLowerCase(),
|
|
60354
|
+
...options.projectDirectory ? { projectDirectory: options.projectDirectory } : {},
|
|
60355
|
+
...options.targetUrl ? { targetUrl: options.targetUrl } : {},
|
|
59661
60356
|
pid: process.pid,
|
|
59662
60357
|
state: "starting",
|
|
59663
60358
|
startedAt,
|
|
@@ -59704,9 +60399,16 @@ async function runListenerSupervisor(options) {
|
|
|
59704
60399
|
activityPublishFailures: 0,
|
|
59705
60400
|
activityLastErrorCode: null,
|
|
59706
60401
|
idlePollMs: null,
|
|
60402
|
+
pushReconcileWaitMs: null,
|
|
59707
60403
|
wake: emptyListenerWakeStatus(),
|
|
60404
|
+
nextAttemptAt: null,
|
|
60405
|
+
credentialStopAt: null,
|
|
60406
|
+
credentialCheckEdge: null,
|
|
60407
|
+
claimRetryCount: 0,
|
|
59708
60408
|
logPath: options.paths.logPath
|
|
59709
60409
|
};
|
|
60410
|
+
let lastClaimRetryCode = null;
|
|
60411
|
+
let lastAckRetryCode = null;
|
|
59710
60412
|
let writes = Promise.resolve();
|
|
59711
60413
|
const chain = (work) => {
|
|
59712
60414
|
writes = writes.then(work).catch(() => void 0);
|
|
@@ -59778,6 +60480,7 @@ async function runListenerSupervisor(options) {
|
|
|
59778
60480
|
return fitted.length > 0 ? fitted : null;
|
|
59779
60481
|
};
|
|
59780
60482
|
let lastWakePersistMs = 0;
|
|
60483
|
+
let attemptReadyAtMs = null;
|
|
59781
60484
|
const onEvent = (event) => {
|
|
59782
60485
|
if (event.type === "wake") {
|
|
59783
60486
|
const previousWake = status.wake;
|
|
@@ -59825,9 +60528,10 @@ async function runListenerSupervisor(options) {
|
|
|
59825
60528
|
status = {
|
|
59826
60529
|
...status,
|
|
59827
60530
|
idlePollMs: event.intervalMs,
|
|
60531
|
+
pushReconcileWaitMs: event.pushReconcileWait ? event.intervalMs : status.pushReconcileWaitMs,
|
|
59828
60532
|
readHealth: recordListenerClaimCadence(
|
|
59829
60533
|
status.readHealth ?? emptyListenerReadHealth(),
|
|
59830
|
-
event.intervalMs > 0 ? event.intervalMs : 1,
|
|
60534
|
+
status.wake?.mode === LISTENER_WAKE_MODE_PUSH ? LISTENER_RECONCILE_POLL_MS : event.intervalMs > 0 ? event.intervalMs : 1,
|
|
59831
60535
|
event.ts
|
|
59832
60536
|
),
|
|
59833
60537
|
updatedAt: event.ts
|
|
@@ -59841,9 +60545,13 @@ async function runListenerSupervisor(options) {
|
|
|
59841
60545
|
return;
|
|
59842
60546
|
}
|
|
59843
60547
|
if (event.type === "ready") {
|
|
60548
|
+
attemptReadyAtMs = now();
|
|
59844
60549
|
const versionNotice = options.getProviderVersionNotice?.() ?? null;
|
|
59845
60550
|
transition("ready", {
|
|
59846
60551
|
readyAt: event.ts,
|
|
60552
|
+
nextAttemptAt: null,
|
|
60553
|
+
credentialStopAt: null,
|
|
60554
|
+
renewalExpiresAt: null,
|
|
59847
60555
|
// Deliberately does NOT clear consecutiveAckFailureCount. Reaching
|
|
59848
60556
|
// `ready` is not provider proof: the permission canary is its own
|
|
59849
60557
|
// prompt, and a provider can answer it and fail every real one --
|
|
@@ -59908,9 +60616,97 @@ async function runListenerSupervisor(options) {
|
|
|
59908
60616
|
});
|
|
59909
60617
|
return;
|
|
59910
60618
|
}
|
|
60619
|
+
if (event.type === "credential_check") {
|
|
60620
|
+
transition("credential_check", {
|
|
60621
|
+
credentialStopAt: event.stopAt,
|
|
60622
|
+
credentialCheckEdge: event.edge,
|
|
60623
|
+
renewalExpiresAt: event.renewalExpiresAt ?? null,
|
|
60624
|
+
lastErrorCode: event.code,
|
|
60625
|
+
lastErrorDetail: null,
|
|
60626
|
+
lastErrorReasonCode: null,
|
|
60627
|
+
nextAttemptAt: event.nextAttemptAt ?? null
|
|
60628
|
+
});
|
|
60629
|
+
log({
|
|
60630
|
+
ts: event.ts,
|
|
60631
|
+
event: "listener_credential_check",
|
|
60632
|
+
failure_code: event.code,
|
|
60633
|
+
attempt: event.checks,
|
|
60634
|
+
reason: event.stopAt
|
|
60635
|
+
});
|
|
60636
|
+
return;
|
|
60637
|
+
}
|
|
60638
|
+
if (event.type === "credential_check_cleared") {
|
|
60639
|
+
transition(status.claimRetryCount && status.claimRetryCount > 0 ? "claim_retry" : status.readyAt === null ? "starting" : "ready", {
|
|
60640
|
+
credentialStopAt: null,
|
|
60641
|
+
credentialCheckEdge: null,
|
|
60642
|
+
renewalExpiresAt: null,
|
|
60643
|
+
lastErrorCode: status.claimRetryCount && status.claimRetryCount > 0 ? lastClaimRetryCode : null,
|
|
60644
|
+
lastRetryEdge: status.claimRetryCount && status.claimRetryCount > 0 ? "command" : void 0,
|
|
60645
|
+
lastErrorDetail: null,
|
|
60646
|
+
lastErrorReasonCode: null,
|
|
60647
|
+
nextAttemptAt: null
|
|
60648
|
+
});
|
|
60649
|
+
log({
|
|
60650
|
+
ts: event.ts,
|
|
60651
|
+
event: "listener_credential_check_cleared"
|
|
60652
|
+
});
|
|
60653
|
+
return;
|
|
60654
|
+
}
|
|
60655
|
+
if (event.type === "claim_retry") {
|
|
60656
|
+
lastClaimRetryCode = event.code;
|
|
60657
|
+
transition(status.credentialStopAt ? "credential_check" : "claim_retry", {
|
|
60658
|
+
lastRetryEdge: "command",
|
|
60659
|
+
claimRetryCount: event.attempts,
|
|
60660
|
+
lastErrorCode: status.credentialStopAt ? status.lastErrorCode : event.code,
|
|
60661
|
+
renewalExpiresAt: event.renewalExpiresAt ?? null,
|
|
60662
|
+
lastErrorDetail: null,
|
|
60663
|
+
nextAttemptAt: new Date(Date.parse(event.ts) + event.delayMs).toISOString()
|
|
60664
|
+
});
|
|
60665
|
+
log({ ts: event.ts, event: "listener_claim_retry", failure_code: event.code, attempt: event.attempts });
|
|
60666
|
+
return;
|
|
60667
|
+
}
|
|
60668
|
+
if (event.type === "claim_retry_cleared") {
|
|
60669
|
+
lastClaimRetryCode = null;
|
|
60670
|
+
transition(status.credentialStopAt ? "credential_check" : status.readyAt === null ? "starting" : "ready", {
|
|
60671
|
+
claimRetryCount: 0,
|
|
60672
|
+
lastErrorCode: status.credentialStopAt ? status.lastErrorCode : null,
|
|
60673
|
+
lastErrorDetail: null,
|
|
60674
|
+
nextAttemptAt: null,
|
|
60675
|
+
renewalExpiresAt: null
|
|
60676
|
+
});
|
|
60677
|
+
return;
|
|
60678
|
+
}
|
|
60679
|
+
if (event.type === "ack_retry") {
|
|
60680
|
+
lastAckRetryCode = event.code;
|
|
60681
|
+
transition(status.credentialStopAt ? "credential_check" : "ack_retry", {
|
|
60682
|
+
lastRetryEdge: "command",
|
|
60683
|
+
lastErrorCode: status.credentialStopAt ? status.lastErrorCode : event.code,
|
|
60684
|
+
renewalExpiresAt: event.renewalExpiresAt ?? null,
|
|
60685
|
+
lastErrorDetail: null,
|
|
60686
|
+
nextAttemptAt: new Date(Date.parse(event.ts) + event.delayMs).toISOString()
|
|
60687
|
+
});
|
|
60688
|
+
log({ ts: event.ts, event: "listener_ack_retry", failure_code: event.code, attempt: event.attempt });
|
|
60689
|
+
return;
|
|
60690
|
+
}
|
|
60691
|
+
if (event.type === "ack_retry_cleared") {
|
|
60692
|
+
lastAckRetryCode = null;
|
|
60693
|
+
if (status.state === "ack_retry") {
|
|
60694
|
+
transition(status.readyAt === null ? "starting" : "ready", {
|
|
60695
|
+
lastErrorCode: null,
|
|
60696
|
+
lastErrorDetail: null,
|
|
60697
|
+
nextAttemptAt: null,
|
|
60698
|
+
renewalExpiresAt: null
|
|
60699
|
+
});
|
|
60700
|
+
}
|
|
60701
|
+
return;
|
|
60702
|
+
}
|
|
59911
60703
|
if (event.type === "read_retry") {
|
|
59912
60704
|
status = {
|
|
59913
60705
|
...status,
|
|
60706
|
+
lastErrorCode: event.code,
|
|
60707
|
+
renewalExpiresAt: event.renewalExpiresAt ?? null,
|
|
60708
|
+
lastRetryEdge: "read",
|
|
60709
|
+
nextAttemptAt: new Date(Date.parse(event.ts) + event.delayMs).toISOString(),
|
|
59914
60710
|
readHealth: recordListenerReadRetry(
|
|
59915
60711
|
status.readHealth ?? emptyListenerReadHealth(),
|
|
59916
60712
|
{
|
|
@@ -59929,6 +60725,7 @@ async function runListenerSupervisor(options) {
|
|
|
59929
60725
|
attempt: event.attempt,
|
|
59930
60726
|
episode_attempt: event.episodeAttempt,
|
|
59931
60727
|
reason_code: event.failure.code,
|
|
60728
|
+
failure_code: event.code,
|
|
59932
60729
|
...event.failure.httpStatus === null ? {} : { http_status: event.failure.httpStatus },
|
|
59933
60730
|
...event.failure.errorConstructor === null ? {} : { error_constructor: event.failure.errorConstructor },
|
|
59934
60731
|
delay_ms: event.delayMs
|
|
@@ -59938,6 +60735,12 @@ async function runListenerSupervisor(options) {
|
|
|
59938
60735
|
if (event.type === "read_recovered") {
|
|
59939
60736
|
status = {
|
|
59940
60737
|
...status,
|
|
60738
|
+
...status.lastRetryEdge === "read" ? {
|
|
60739
|
+
nextAttemptAt: null,
|
|
60740
|
+
renewalExpiresAt: null,
|
|
60741
|
+
lastErrorCode: status.claimRetryCount && status.claimRetryCount > 0 ? lastClaimRetryCode : status.state === "ack_retry" ? lastAckRetryCode : null,
|
|
60742
|
+
lastRetryEdge: status.claimRetryCount && status.claimRetryCount > 0 || status.state === "ack_retry" ? "command" : void 0
|
|
60743
|
+
} : {},
|
|
59941
60744
|
readHealth: recordListenerReadRecovery(
|
|
59942
60745
|
status.readHealth ?? emptyListenerReadHealth(),
|
|
59943
60746
|
{
|
|
@@ -60141,16 +60944,18 @@ async function runListenerSupervisor(options) {
|
|
|
60141
60944
|
});
|
|
60142
60945
|
};
|
|
60143
60946
|
const policy = options.restart ?? {};
|
|
60144
|
-
const
|
|
60947
|
+
const explicitCeiling = policy.maxAttempts;
|
|
60145
60948
|
const isRestartable = policy.isRestartable ?? isRestartableListenerStop;
|
|
60146
60949
|
const restartSleep = policy.sleep ?? defaultRestartSleep;
|
|
60147
60950
|
const restartRandom = policy.random ?? Math.random;
|
|
60951
|
+
const cleanRunMs = policy.cleanRunMs ?? LISTENER_RESTART_CLEAN_RUN_MS;
|
|
60148
60952
|
try {
|
|
60149
60953
|
let restarts = 0;
|
|
60150
60954
|
let exhausted = false;
|
|
60151
60955
|
let eligible = false;
|
|
60152
60956
|
let stop;
|
|
60153
60957
|
for (; ; ) {
|
|
60958
|
+
attemptReadyAtMs = null;
|
|
60154
60959
|
stop = await options.run(
|
|
60155
60960
|
controller.signal,
|
|
60156
60961
|
onEvent,
|
|
@@ -60159,14 +60964,23 @@ async function runListenerSupervisor(options) {
|
|
|
60159
60964
|
if (stop.reason === "cancelled" || controller.signal.aborted) break;
|
|
60160
60965
|
eligible = isRestartable(stop);
|
|
60161
60966
|
if (!eligible) break;
|
|
60162
|
-
|
|
60967
|
+
const cleanForMs = attemptReadyAtMs === null ? 0 : Math.max(0, now() - attemptReadyAtMs);
|
|
60968
|
+
if (cleanForMs >= cleanRunMs) restarts = 0;
|
|
60969
|
+
if (explicitCeiling !== void 0 && restarts >= explicitCeiling) {
|
|
60163
60970
|
exhausted = true;
|
|
60164
60971
|
break;
|
|
60165
60972
|
}
|
|
60166
60973
|
restarts += 1;
|
|
60167
|
-
const
|
|
60974
|
+
const expiry = options.getCredentialExpiryMs?.() ?? null;
|
|
60975
|
+
const deadline = expiry === null ? null : expiry - RENEWAL_WINDOW_EXPIRY_MARGIN_MS;
|
|
60976
|
+
const renewalAt = options.getCredentialRenewalAt?.();
|
|
60977
|
+
const boundary = renewalAt !== null && expiry !== null && now() < expiry ? renewalAt !== void 0 && now() < renewalAt ? renewalAt : deadline : null;
|
|
60978
|
+
const proposedDelayMs = listenerRestartDelayMs(restarts, policy, restartRandom);
|
|
60979
|
+
const cappedDelayMs = boundary !== null ? Math.min(proposedDelayMs, Math.max(0, boundary - now())) : proposedDelayMs;
|
|
60980
|
+
const delayMs = Math.max(LISTENER_REQUEST_WAIT_FLOOR_MS, cappedDelayMs);
|
|
60168
60981
|
const restartCode = safeErrorCode(stop.error);
|
|
60169
60982
|
const restartStderrTail = takeTail();
|
|
60983
|
+
const nextAttemptAt = new Date(now() + delayMs).toISOString();
|
|
60170
60984
|
log({
|
|
60171
60985
|
ts: iso2(now),
|
|
60172
60986
|
event: "listener_restarting",
|
|
@@ -60178,16 +60992,22 @@ async function runListenerSupervisor(options) {
|
|
|
60178
60992
|
transition("starting", {
|
|
60179
60993
|
readyAt: null,
|
|
60180
60994
|
lastErrorCode: restartCode,
|
|
60995
|
+
lastRetryEdge: retryEdgeOf(stop.error),
|
|
60181
60996
|
lastErrorDetail: safeErrorDetail(stop.error),
|
|
60182
60997
|
...providerFailureFields(stop.error),
|
|
60183
60998
|
lastWorkerStderrTail: restartStderrTail,
|
|
60184
|
-
...providerStatusFields(options.getProviderVersionNotice?.() ?? null)
|
|
60999
|
+
...providerStatusFields(options.getProviderVersionNotice?.() ?? null),
|
|
61000
|
+
nextAttemptAt,
|
|
61001
|
+
credentialStopAt: null,
|
|
61002
|
+
credentialCheckEdge: null,
|
|
61003
|
+
claimRetryCount: 0
|
|
60185
61004
|
});
|
|
60186
|
-
await restartSleep(delayMs, controller.signal);
|
|
61005
|
+
if (delayMs > 0) await restartSleep(delayMs, controller.signal);
|
|
60187
61006
|
if (controller.signal.aborted) {
|
|
60188
61007
|
stop = { reason: "cancelled" };
|
|
60189
61008
|
break;
|
|
60190
61009
|
}
|
|
61010
|
+
transition("starting", { nextAttemptAt: null });
|
|
60191
61011
|
}
|
|
60192
61012
|
const stoppedAt = iso2(now);
|
|
60193
61013
|
if (stop.reason === "cancelled") {
|
|
@@ -60197,11 +61017,16 @@ async function runListenerSupervisor(options) {
|
|
|
60197
61017
|
lastErrorDetail: null,
|
|
60198
61018
|
lastErrorReasonCode: null,
|
|
60199
61019
|
lastWorkerStderrTail: null,
|
|
60200
|
-
providerMinimumRequiredVersion: null
|
|
61020
|
+
providerMinimumRequiredVersion: null,
|
|
61021
|
+
nextAttemptAt: null,
|
|
61022
|
+
credentialStopAt: null,
|
|
61023
|
+
renewalExpiresAt: null,
|
|
61024
|
+
credentialCheckEdge: null,
|
|
61025
|
+
claimRetryCount: 0
|
|
60201
61026
|
});
|
|
60202
61027
|
log({ ts: stoppedAt, event: "listener_stopped" });
|
|
60203
61028
|
} else {
|
|
60204
|
-
const code = stop.reason === "credential" ? "credential_stopped" : safeErrorCode(stop.error);
|
|
61029
|
+
const code = stop.reason === "credential" ? stop.error instanceof ListenerCredentialStateMismatchError ? stop.error.code : "credential_stopped" : safeErrorCode(stop.error);
|
|
60205
61030
|
const failedStderrTail = takeTail();
|
|
60206
61031
|
transition("failed", {
|
|
60207
61032
|
stoppedAt,
|
|
@@ -60209,7 +61034,12 @@ async function runListenerSupervisor(options) {
|
|
|
60209
61034
|
lastErrorDetail: safeErrorDetail(stop.error),
|
|
60210
61035
|
...providerFailureFields(stop.error),
|
|
60211
61036
|
...providerStatusFields(options.getProviderVersionNotice?.() ?? null),
|
|
60212
|
-
lastWorkerStderrTail: failedStderrTail
|
|
61037
|
+
lastWorkerStderrTail: failedStderrTail,
|
|
61038
|
+
nextAttemptAt: null,
|
|
61039
|
+
credentialStopAt: null,
|
|
61040
|
+
renewalExpiresAt: null,
|
|
61041
|
+
credentialCheckEdge: stop.reason === "credential" && !(stop.error instanceof ListenerCredentialStateMismatchError) ? status.credentialCheckEdge ?? null : null,
|
|
61042
|
+
claimRetryCount: 0
|
|
60213
61043
|
});
|
|
60214
61044
|
log({
|
|
60215
61045
|
ts: stoppedAt,
|
|
@@ -60237,7 +61067,11 @@ async function runListenerSupervisor(options) {
|
|
|
60237
61067
|
error2 instanceof Error ? error2 : new Error(String(error2))
|
|
60238
61068
|
),
|
|
60239
61069
|
...providerStatusFields(options.getProviderVersionNotice?.() ?? null),
|
|
60240
|
-
lastWorkerStderrTail: failedStderrTail
|
|
61070
|
+
lastWorkerStderrTail: failedStderrTail,
|
|
61071
|
+
nextAttemptAt: null,
|
|
61072
|
+
credentialStopAt: null,
|
|
61073
|
+
credentialCheckEdge: null,
|
|
61074
|
+
claimRetryCount: 0
|
|
60241
61075
|
});
|
|
60242
61076
|
log({
|
|
60243
61077
|
ts: stoppedAt,
|
|
@@ -60256,7 +61090,7 @@ async function effectiveListenerStatus(paths) {
|
|
|
60256
61090
|
return await queryListenerControl(paths, "status");
|
|
60257
61091
|
} catch {
|
|
60258
61092
|
const stored = await readListenerStatus(paths);
|
|
60259
|
-
if (stored && (stored.state
|
|
61093
|
+
if (stored && LISTENER_RUNNING_STATES.includes(stored.state)) {
|
|
60260
61094
|
const failed = {
|
|
60261
61095
|
...stored,
|
|
60262
61096
|
state: "failed",
|
|
@@ -60269,7 +61103,9 @@ async function effectiveListenerStatus(paths) {
|
|
|
60269
61103
|
says it is what the service reported. */
|
|
60270
61104
|
currentDeliverySignalId: null,
|
|
60271
61105
|
currentDeliverySince: null,
|
|
60272
|
-
heldBackDeliveries: []
|
|
61106
|
+
heldBackDeliveries: [],
|
|
61107
|
+
credentialStopAt: null,
|
|
61108
|
+
nextAttemptAt: null
|
|
60273
61109
|
};
|
|
60274
61110
|
await writeListenerStatus(paths, failed);
|
|
60275
61111
|
return failed;
|
|
@@ -60298,7 +61134,7 @@ async function waitForListenerReady(paths, options = {}) {
|
|
|
60298
61134
|
if (options.expectedPid !== void 0 && last.pid !== options.expectedPid) {
|
|
60299
61135
|
throw new ListenerAlreadyRunningError();
|
|
60300
61136
|
}
|
|
60301
|
-
if (last.state
|
|
61137
|
+
if (LISTENER_RUNNING_STATES.includes(last.state) && last.state !== "starting" && last.state !== "stopping") return last;
|
|
60302
61138
|
if (last.state === "failed" || last.state === "stopped") {
|
|
60303
61139
|
throw new ListenerStartupError(last.lastErrorCode ?? last.state);
|
|
60304
61140
|
}
|
|
@@ -60324,6 +61160,7 @@ async function waitForListenerReady(paths, options = {}) {
|
|
|
60324
61160
|
}
|
|
60325
61161
|
await sleep2(pollMs);
|
|
60326
61162
|
}
|
|
61163
|
+
if (last !== null && (options.expectedPid === void 0 || last.pid === options.expectedPid) && (!options.isProcessAlive || options.isProcessAlive()) && last.state === "starting") return last;
|
|
60327
61164
|
throw new ListenerStartupError(last?.lastErrorCode ?? "ready_timeout");
|
|
60328
61165
|
}
|
|
60329
61166
|
|
|
@@ -63873,8 +64710,8 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
63873
64710
|
]);
|
|
63874
64711
|
var UUID_RE24 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
63875
64712
|
function packageVersion() {
|
|
63876
|
-
if ("0.1.
|
|
63877
|
-
return "0.1.
|
|
64713
|
+
if ("0.1.73".length > 0) {
|
|
64714
|
+
return "0.1.73";
|
|
63878
64715
|
}
|
|
63879
64716
|
try {
|
|
63880
64717
|
const value = JSON.parse(
|
|
@@ -65827,7 +66664,7 @@ function accepted(label, result) {
|
|
|
65827
66664
|
);
|
|
65828
66665
|
}
|
|
65829
66666
|
}
|
|
65830
|
-
async function agentSession(cloud, workspaceId2, agent, fetcher) {
|
|
66667
|
+
async function agentSession(cloud, workspaceId2, agent, fetcher, listenerMode = false) {
|
|
65831
66668
|
let store2 = null;
|
|
65832
66669
|
try {
|
|
65833
66670
|
const candidate = await agentCredentialStore({
|
|
@@ -65854,6 +66691,7 @@ async function agentSession(cloud, workspaceId2, agent, fetcher) {
|
|
|
65854
66691
|
expiresAt: agent.expiresAt
|
|
65855
66692
|
},
|
|
65856
66693
|
store: store2,
|
|
66694
|
+
listenerMode,
|
|
65857
66695
|
...fetcher ? { fetcher } : {}
|
|
65858
66696
|
});
|
|
65859
66697
|
}
|
|
@@ -65975,7 +66813,7 @@ function listenerRouteConfiguration(routeValue, deferOverValue) {
|
|
|
65975
66813
|
}
|
|
65976
66814
|
return { routeMode, deferOverChars: null };
|
|
65977
66815
|
}
|
|
65978
|
-
var TURN_BUDGET_CREDENTIAL_MARGIN_MS =
|
|
66816
|
+
var TURN_BUDGET_CREDENTIAL_MARGIN_MS = RENEWAL_WINDOW_EXPIRY_MARGIN_MS;
|
|
65979
66817
|
function clampTurnBudgetToCredential(budgetMs, credentialExpiresAt, nowMs) {
|
|
65980
66818
|
if (credentialExpiresAt === null) return budgetMs;
|
|
65981
66819
|
const horizonMs = credentialExpiresAt - nowMs - TURN_BUDGET_CREDENTIAL_MARGIN_MS;
|
|
@@ -67165,7 +68003,7 @@ async function runInboxFollowCommand(args) {
|
|
|
67165
68003
|
signal: controller.signal,
|
|
67166
68004
|
refusalToleranceMs,
|
|
67167
68005
|
...pageLimit === void 0 ? {} : { pageLimit },
|
|
67168
|
-
isCredentialFailure:
|
|
68006
|
+
isCredentialFailure: isFollowRenewalCredentialFailure,
|
|
67169
68007
|
arm: async ({ after, limit }) => {
|
|
67170
68008
|
const credential = selected.session ? { kind: "agent", token: await selected.session.bearer() } : signalCredentialOf(selected);
|
|
67171
68009
|
if (credential.kind === "agent") renderedBearer = credential.token;
|
|
@@ -67428,9 +68266,9 @@ function emptyAttendanceEvidence() {
|
|
|
67428
68266
|
}
|
|
67429
68267
|
function listenerAttendanceState(status, evidence) {
|
|
67430
68268
|
const pending = status.pendingForMainCount ?? 0;
|
|
67431
|
-
const connected = status.state
|
|
68269
|
+
const connected = LISTENER_RUNNING_STATES.includes(status.state) && status.state !== "starting" && status.state !== "stopping" && status.state !== "credential_check" && status.state !== "claim_retry" && status.state !== "ack_retry" && status.readHealth?.currentEpisodeStartedAt == null;
|
|
67432
68270
|
const attendingSurfaces = evidence.attendingSurfaces ?? [];
|
|
67433
|
-
const hasSurface = attendingSurfaces.length > 0;
|
|
68271
|
+
const hasSurface = evidence.hookSurfaceExists || attendingSurfaces.length > 0;
|
|
67434
68272
|
const attendanceState = pending > 0 ? "unattended" : hasSurface && evidence.hookSurfaceAdvanced ? "attended" : hasSurface ? "unproven" : "unattended";
|
|
67435
68273
|
const attended = attendanceState === "attended" ? true : attendanceState === "unattended" ? false : null;
|
|
67436
68274
|
const lastAckOutcome = status.lastAckOutcome ?? null;
|
|
@@ -67455,26 +68293,25 @@ function listenerReadHealthSummary(status, nowMs) {
|
|
|
67455
68293
|
);
|
|
67456
68294
|
}
|
|
67457
68295
|
function listenerLapseNotices(status, summary) {
|
|
68296
|
+
const down = status.state === "stopped" || status.state === "failed";
|
|
67458
68297
|
const health = status.readHealth ?? emptyListenerReadHealth();
|
|
67459
68298
|
const notices = [];
|
|
67460
|
-
if (health.currentReasonCode === "host_ports_exhausted") {
|
|
68299
|
+
if (!down && health.currentReasonCode === "host_ports_exhausted") {
|
|
67461
68300
|
notices.push({
|
|
67462
68301
|
code: "listener_host_ports_exhausted",
|
|
67463
68302
|
message: "This host has run out of outbound ports. The listener is probing only once per minute so it does not amplify the outage.",
|
|
67464
68303
|
nextStep: "Find the consumer: lsof -nP -iTCP | awk '{print $1}' | sort | uniq -c | sort -rn"
|
|
67465
68304
|
});
|
|
67466
|
-
} else if (
|
|
67467
|
-
|
|
67468
|
-
|
|
67469
|
-
summary.currentEpisodeDurationMs !== null && summary.currentEpisodeDurationMs >= ARRIVAL_RETRY_NOTICE_THRESHOLD_MS
|
|
67470
|
-
) {
|
|
68305
|
+
} else if (!down && // Reuse arrival-watch.ts's 60s loud-lapse transition. The listener keeps
|
|
68306
|
+
// the episode in durable status instead of the monitor's process-local machine.
|
|
68307
|
+
summary.currentEpisodeDurationMs !== null && summary.currentEpisodeDurationMs >= ARRIVAL_RETRY_NOTICE_THRESHOLD_MS) {
|
|
67471
68308
|
notices.push({
|
|
67472
68309
|
code: "listener_read_retry_persisting",
|
|
67473
68310
|
message: `Listener reads have failed continuously for ${Math.floor(summary.currentEpisodeDurationMs / 1e3)}s. This is still in progress.`,
|
|
67474
|
-
nextStep: "
|
|
68311
|
+
nextStep: "Leave the listener running while it waits for the read service; check the target URL and CommonSwarm service."
|
|
67475
68312
|
});
|
|
67476
68313
|
}
|
|
67477
|
-
if (summary.throughputLapseHours.length > 0) {
|
|
68314
|
+
if (!down && summary.throughputLapseHours.length > 0) {
|
|
67478
68315
|
const latest = summary.throughputLapseHours.at(-1);
|
|
67479
68316
|
const pending = status.pendingDeliveryCount;
|
|
67480
68317
|
const pendingClause = pending === null ? " No pending count was recorded." : ` Pending deliveries now: ${pending}.`;
|
|
@@ -67635,6 +68472,75 @@ function listenerStatusJson(status, permissionMode, evidence = emptyAttendanceEv
|
|
|
67635
68472
|
host_limits: isLiveListenerRouteMode(status.routeMode ?? "main") ? listenerMainHostLimits() : listenerHostLimits(status.provider)
|
|
67636
68473
|
};
|
|
67637
68474
|
}
|
|
68475
|
+
var CSWARM_UPDATE_INSTALLER = "curl -fsSL https://commonswarm.com/install.sh | sh";
|
|
68476
|
+
var CSWARM_UPDATE_NPM = "npm install -g commonswarm";
|
|
68477
|
+
var CSWARM_UPGRADE_STOP = `The command edge requires a newer cswarm (upgrade_required). Update with ${CSWARM_UPDATE_INSTALLER} or ${CSWARM_UPDATE_NPM}. ${RENEWAL_UPGRADE_LISTENER_ACTION}`;
|
|
68478
|
+
function credentialStoppedSentence(edge = null) {
|
|
68479
|
+
const codes = (edge === "command" ? COMMAND_CONFIRMED_CREDENTIAL_LOSS_CODES : CONFIRMED_CREDENTIAL_LOSS_CODES).join(" or ");
|
|
68480
|
+
return `the server refused this credential (${codes} means revoked, expired, or unknown), a local renewal stop fired, or local credential state is missing. The listener has stopped and will not retry. Run cswarm whoami with this credential to see the grant state, then follow its next step`;
|
|
68481
|
+
}
|
|
68482
|
+
function credentialCheckSentence(status) {
|
|
68483
|
+
if (status.state !== "credential_check") return null;
|
|
68484
|
+
if (typeof status.credentialStopAt !== "string") return null;
|
|
68485
|
+
const codes = (status.credentialCheckEdge === "command" ? COMMAND_CONFIRMED_CREDENTIAL_LOSS_CODES : CONFIRMED_CREDENTIAL_LOSS_CODES).join(" or ");
|
|
68486
|
+
if (status.renewalExpiresAt && Date.parse(status.renewalExpiresAt) < Date.parse(status.credentialStopAt)) {
|
|
68487
|
+
return `The server refused this credential (${codes}). The listener is still running and retrying the credential check${status.nextAttemptAt ? ` at ${status.nextAttemptAt}` : ""}. The current token expires at ${status.renewalExpiresAt}; unless renewal succeeds first, the listener stops on the next renewal answer after expiry. Run cswarm whoami with this credential to see the grant state.`;
|
|
68488
|
+
}
|
|
68489
|
+
return `The server refused this credential (${codes}). The listener is still running. It will stop at ${status.credentialStopAt} if every check until then confirms the loss; a transient answer extends the check window. Run cswarm whoami with this credential to see the grant state.`;
|
|
68490
|
+
}
|
|
68491
|
+
function listenerRetrySentence(status) {
|
|
68492
|
+
if (status.lastErrorCode === "renewal_retry" && status.nextAttemptAt) {
|
|
68493
|
+
return `Credential renewal is retrying. The current token expires at ${status.renewalExpiresAt ?? "an unknown time"}. The listener will retry at ${status.nextAttemptAt} with backoff of at least one second. Reads and claims pause while renewal is unresolved because the successor may already have been issued. If renewal does not succeed before expiry, the listener stops and needs a new credential.`;
|
|
68494
|
+
}
|
|
68495
|
+
if (!LISTENER_RUNNING_STATES.includes(status.state) || typeof status.nextAttemptAt !== "string" || status.state !== "starting" && status.lastRetryEdge !== "read") {
|
|
68496
|
+
return null;
|
|
68497
|
+
}
|
|
68498
|
+
const code = status.lastErrorCode ?? "no code recorded";
|
|
68499
|
+
if (status.lastRetryEdge === "read" && (status.readHealth?.currentEpisodeAttempts ?? 0) > 0) {
|
|
68500
|
+
const failure = status.readHealth;
|
|
68501
|
+
const detail = failure.currentHttpStatus === null ? "" : ` (HTTP ${failure.currentHttpStatus})`;
|
|
68502
|
+
const next = ListenerCapabilityError.READ_EDGE_CODES.includes(code) ? `Check ${status.targetUrl ?? "the target URL"} and update the read edge before starting a model.` : `Check ${status.targetUrl ?? "the target URL"} and read edge version. Leave the listener running while the read service recovers.`;
|
|
68503
|
+
return `The read edge failed (${code}${detail}). The listener is still running and will try again at ${status.nextAttemptAt}. ${next}`;
|
|
68504
|
+
}
|
|
68505
|
+
return `The ${status.lastRetryEdge === "command" ? "command edge" : "last attempt"} failed (${code}). The listener is still running and will try again at ${status.nextAttemptAt}. Leave it running. To stop it now: cswarm listen stop --workspace-id ${status.workspaceId} --principal-id ${status.principalId}`;
|
|
68506
|
+
}
|
|
68507
|
+
function listenerDownSentence(status) {
|
|
68508
|
+
if (status.state === "stopped") {
|
|
68509
|
+
return `This listener is stopped and is not reading signals. Start it again by piping the same agent credential into: ${listenerRestartCommand(status)}`;
|
|
68510
|
+
}
|
|
68511
|
+
if (status.state !== "failed") return null;
|
|
68512
|
+
if (status.lastErrorCode === "credential_stopped") {
|
|
68513
|
+
return `This listener stopped because ${credentialStoppedSentence(status.credentialCheckEdge ?? null)}.`;
|
|
68514
|
+
}
|
|
68515
|
+
if (status.lastErrorCode === "local_credential_state_mismatch") {
|
|
68516
|
+
return "This listener stopped because its local credential state did not preserve the live credential. Check that its local state directory is writable and intact, then restart the listener with the credential.";
|
|
68517
|
+
}
|
|
68518
|
+
if (status.lastErrorCode === H0_SEAT_CLAIM_REFUSED_CODE) {
|
|
68519
|
+
return `${H0_SEAT_LISTENER_STOP_SENTENCE}.`;
|
|
68520
|
+
}
|
|
68521
|
+
if (status.lastErrorCode === "upgrade_required") return CSWARM_UPGRADE_STOP;
|
|
68522
|
+
const code = status.lastErrorCode ?? "no code recorded";
|
|
68523
|
+
return `This listener failed (${code}) and is not reading signals. Read ${status.logPath}, then restart it by piping the same agent credential into: ${listenerRestartCommand(status)}`;
|
|
68524
|
+
}
|
|
68525
|
+
function listenerDeliveryRetrySentence(status) {
|
|
68526
|
+
if (status.lastErrorCode === "renewal_retry") return null;
|
|
68527
|
+
if (status.lastRetryEdge === "read") return null;
|
|
68528
|
+
const when = status.nextAttemptAt ? ` at ${status.nextAttemptAt}` : " with backoff";
|
|
68529
|
+
const code = status.lastErrorCode ?? "no code recorded";
|
|
68530
|
+
if (status.state === "claim_retry") {
|
|
68531
|
+
if (DELIVERY_SESSION_PROOF_CODES.includes(code)) {
|
|
68532
|
+
return `The claim is refused (${code}); this managed seat needs a live session. CONNECTED is no while claims fail. Start or renew the seat's session, or stop the listener. The listener will try again${when}.`;
|
|
68533
|
+
}
|
|
68534
|
+
return `The claim failed (${code}) ${status.claimRetryCount ?? 0} times. ${code === "delivery_unreachable" ? "The server could not be reached." : "The command edge did not accept the claim."} The listener is running and will try again${when}, reading signals after repeated failures.`;
|
|
68535
|
+
}
|
|
68536
|
+
if (status.state === "ack_retry") {
|
|
68537
|
+
if (DELIVERY_SESSION_PROOF_CODES.includes(code)) {
|
|
68538
|
+
return `The delivery acknowledgement is refused (${code}); this managed seat needs a live session. CONNECTED is no while acknowledgements fail. Start or renew the seat's session, or stop the listener. The listener will try again${when}.`;
|
|
68539
|
+
}
|
|
68540
|
+
return `The delivery acknowledgement failed (${code}). The inbox is waiting on this acknowledgement. The listener will try again${when} and read signals after repeated failures.`;
|
|
68541
|
+
}
|
|
68542
|
+
return null;
|
|
68543
|
+
}
|
|
67638
68544
|
function renderListenerStatus(status, evidence = emptyAttendanceEvidence(), nowMs = Date.now(), installed = null) {
|
|
67639
68545
|
const routeMode = status.routeMode ?? "main";
|
|
67640
68546
|
const deliveryFailureRun = status.consecutiveAckFailureCount ?? 0;
|
|
@@ -67645,13 +68551,24 @@ function renderListenerStatus(status, evidence = emptyAttendanceEvidence(), nowM
|
|
|
67645
68551
|
const readHealth = status.readHealth ?? emptyListenerReadHealth();
|
|
67646
68552
|
const readSummary = listenerReadHealthSummary(status, nowMs);
|
|
67647
68553
|
const lapseNotices = listenerLapseNotices(status, readSummary);
|
|
68554
|
+
const down = status.state === "stopped" || status.state === "failed";
|
|
68555
|
+
const retrying = LISTENER_RUNNING_STATES.includes(status.state) && (status.state === "starting" || status.lastRetryEdge === "read") && typeof status.nextAttemptAt === "string";
|
|
68556
|
+
const credentialCheck = credentialCheckSentence(status);
|
|
68557
|
+
const retrySentence = listenerRetrySentence(status);
|
|
68558
|
+
const deliveryRetrySentence = listenerDeliveryRetrySentence(status);
|
|
68559
|
+
const downSentence = listenerDownSentence(status);
|
|
67648
68560
|
const lines = [
|
|
67649
|
-
lapseNotices.length > 0 ? `Listener LAPSE for agent ${status.principalId}: ${lapseNotices.map((notice) => notice.code).join(", ")}.` : pendingForMainCount > 0 ? `Listener WARNING for agent ${status.principalId}: ${unattendedCount}.` : `Listener ${status.state} for agent ${status.principalId}.`,
|
|
68561
|
+
down ? `Listener ${status.state} for agent ${status.principalId}.` : credentialCheck !== null ? `Listener credential check for agent ${status.principalId}.` : retrying ? `Listener retrying for agent ${status.principalId}.` : lapseNotices.length > 0 ? `Listener LAPSE for agent ${status.principalId}: ${lapseNotices.map((notice) => notice.code).join(", ")}.` : pendingForMainCount > 0 ? `Listener WARNING for agent ${status.principalId}: ${unattendedCount}.` : `Listener ${status.state} for agent ${status.principalId}.`,
|
|
68562
|
+
...credentialCheck === null ? [] : [credentialCheck],
|
|
68563
|
+
...deliveryRetrySentence === null ? [] : [deliveryRetrySentence],
|
|
68564
|
+
...retrySentence === null ? [] : [retrySentence],
|
|
68565
|
+
...downSentence === null ? [] : [downSentence],
|
|
67650
68566
|
`CONNECTED: ${attendance.connected ? "yes" : "no"}. Transport state is ${status.state}.`,
|
|
67651
68567
|
listenerAttendingSentence(evidence.attendingSurfaces ?? []),
|
|
67652
68568
|
`ATTENDED: ${attendance.attendanceState === "attended" ? "yes. The session hook has surfaced messages on this host" : attendance.attendanceState === "unattended" ? (evidence.attendingSurfaces ?? []).length === 0 ? `no. ${LISTENER_NONE_ATTENDING_SENTENCE.replace(/\.$/, "")}` : "no. The main-session queue is not draining" : "not yet proven on this host"}.`,
|
|
67653
68569
|
`HANDLED: ${attendance.handledState === "handled" ? `yes. The newest delivery acknowledgement was ${status.lastAckOutcome}` : attendance.handledState === "not_handled" ? routeMode === "worker" ? deliveryFailureRun >= LISTENER_DELIVERY_FAILING_THRESHOLD ? `no. ${deliveryFailureRun} ${deliveryFailureRun === 1 ? "delivery has" : "deliveries have"} failed since the last reply; the newest delivery acknowledgement was ${status.lastAckOutcome ?? "not recorded"}${status.lastErrorCode ? ` (${status.lastErrorCode})` : ""}` : `no. The newest delivery acknowledgement was ${status.lastAckOutcome ?? "not recorded"}${status.lastErrorCode ? ` (${status.lastErrorCode})` : ""}` : "no. Queued messages have not reached the session hook" : "not yet measured"}.`,
|
|
67654
68570
|
`Provider: ${status.provider}; process: ${status.pid}; started: ${status.startedAt}.`,
|
|
68571
|
+
`Target URL: ${status.targetUrl ?? "not recorded"}.`,
|
|
67655
68572
|
`Provider executable: ${status.providerExecutable ?? "not measured"}.`,
|
|
67656
68573
|
`Connections opened: ${status.connectionsOpened ?? "not measured"}.`,
|
|
67657
68574
|
`Connection reuse ratio: ${status.connectionReuseRatio ?? "not measured"}.`,
|
|
@@ -67668,7 +68585,7 @@ function renderListenerStatus(status, evidence = emptyAttendanceEvidence(), nowM
|
|
|
67668
68585
|
status.idlePollMs === void 0 || status.idlePollMs === null ? "Current idle poll interval has not been reported yet." : idlePollStatusSentence(status.idlePollMs),
|
|
67669
68586
|
listenerWakeStatusSentence(
|
|
67670
68587
|
status.wake ?? emptyListenerWakeStatus(),
|
|
67671
|
-
status.idlePollMs && status.idlePollMs > 0 ? status.idlePollMs : IDLE_POLL_DEFAULT_MS,
|
|
68588
|
+
status.wake?.mode === LISTENER_WAKE_MODE_PUSH ? status.pushReconcileWaitMs && status.pushReconcileWaitMs > 0 ? status.pushReconcileWaitMs : LISTENER_RECONCILE_POLL_MS : status.idlePollMs && status.idlePollMs > 0 ? status.idlePollMs : IDLE_POLL_DEFAULT_MS,
|
|
67672
68589
|
status.wake?.lastWakeAt ? relativeAge(status.wake.lastWakeAt, nowMs) : null
|
|
67673
68590
|
)
|
|
67674
68591
|
];
|
|
@@ -67704,7 +68621,7 @@ function renderListenerStatus(status, evidence = emptyAttendanceEvidence(), nowM
|
|
|
67704
68621
|
}
|
|
67705
68622
|
if (status.providerVersion && status.providerLastMeasuredVersion) {
|
|
67706
68623
|
lines.push(
|
|
67707
|
-
status.providerVersion === status.providerLastMeasuredVersion ? `Provider version: ${status.providerVersion} (last measured: ${status.providerLastMeasuredVersion}).` : status.state
|
|
68624
|
+
status.providerVersion === status.providerLastMeasuredVersion ? `Provider version: ${status.providerVersion} (last measured: ${status.providerLastMeasuredVersion}).` : LISTENER_RUNNING_STATES.includes(status.state) && status.readyAt !== null ? `Provider version ${status.providerVersion} is newer than the last measured version ${status.providerLastMeasuredVersion}. It is unverified but allowed because the startup permission canary passed. Next: verify this provider release with CommonSwarm and update the last-measured version.` : status.state === "starting" ? `Provider version ${status.providerVersion} is newer than the last measured version ${status.providerLastMeasuredVersion}. It is still starting; compatibility was not established. Next: check the listener status after it is ready.` : `Provider version ${status.providerVersion} is newer than the last measured version ${status.providerLastMeasuredVersion}. It was measured before startup failed; compatibility was not established. Next: resolve the startup failure before verifying this provider release.`
|
|
67708
68625
|
);
|
|
67709
68626
|
} else {
|
|
67710
68627
|
lines.push("Provider version: not measured.");
|
|
@@ -67794,6 +68711,18 @@ function renderListenerStatus(status, evidence = emptyAttendanceEvidence(), nowM
|
|
|
67794
68711
|
}
|
|
67795
68712
|
return lines.join("\n");
|
|
67796
68713
|
}
|
|
68714
|
+
function listenerStartPendingMessage(status) {
|
|
68715
|
+
if (status.state === "starting" && status.lastErrorCode) {
|
|
68716
|
+
const code = status.lastErrorCode;
|
|
68717
|
+
const capability = ListenerCapabilityError.READ_EDGE_CODES.includes(code);
|
|
68718
|
+
const target2 = status.targetUrl ?? "the target URL";
|
|
68719
|
+
if (status.lastRetryEdge !== "read") {
|
|
68720
|
+
return `Listener ${status.lastRetryEdge === "command" ? "command edge" : "startup"} failed (${code}); check ${target2}. Use cswarm listen status to follow retries.`;
|
|
68721
|
+
}
|
|
68722
|
+
return capability ? `Listener read edge failed (${code}); check ${target2}. ${listenerFailureMessage(code)}. Use cswarm listen status to follow retries.` : `Listener read edge failed (${code}); check ${target2} and read edge version. Use cswarm listen status to follow retries.`;
|
|
68723
|
+
}
|
|
68724
|
+
return "Listener is still starting or checking; use cswarm listen status to follow it.";
|
|
68725
|
+
}
|
|
67797
68726
|
async function unsurfacedPendingMainStats(instanceDirectory, fallback) {
|
|
67798
68727
|
try {
|
|
67799
68728
|
const queue = new FilePendingMainQueue(instanceDirectory);
|
|
@@ -67841,7 +68770,8 @@ function listenerProviderIdentitySummary(status) {
|
|
|
67841
68770
|
}
|
|
67842
68771
|
return parts.join("; ");
|
|
67843
68772
|
}
|
|
67844
|
-
function listenerFailureMessage(code, provider, detail, reasonCode, minimumRequiredVersion) {
|
|
68773
|
+
function listenerFailureMessage(code, provider, detail, reasonCode, minimumRequiredVersion, credentialEdge = null) {
|
|
68774
|
+
if (code === "upgrade_required") return CSWARM_UPGRADE_STOP;
|
|
67845
68775
|
if (code === "version_below_floor") {
|
|
67846
68776
|
if (provider === "codex") {
|
|
67847
68777
|
return "the Codex listener requires codex-acp 1.1.9 or newer; update the bridge, then retry";
|
|
@@ -67893,11 +68823,17 @@ function listenerFailureMessage(code, provider, detail, reasonCode, minimumRequi
|
|
|
67893
68823
|
if (code.startsWith("opencode_auth_") || code === "opencode_project_config_active" || code === "opencode_config_probe_failed") {
|
|
67894
68824
|
return `OpenCode host safety check failed (${code}); re-authenticate and ensure OPENCODE_DISABLE_PROJECT_CONFIG keeps project allow from merging`;
|
|
67895
68825
|
}
|
|
67896
|
-
if (code
|
|
68826
|
+
if (ListenerCapabilityError.READ_EDGE_CODES.includes(code)) {
|
|
67897
68827
|
return `the deployed read service lacks the safe listener capability (${code}); update/deploy the read edge before starting a model`;
|
|
67898
68828
|
}
|
|
67899
68829
|
if (code === "credential_stopped") {
|
|
67900
|
-
return
|
|
68830
|
+
return credentialStoppedSentence(credentialEdge);
|
|
68831
|
+
}
|
|
68832
|
+
if (code === "local_credential_state_mismatch") {
|
|
68833
|
+
return "the listener's local credential state did not preserve the live credential; check the local state directory, then restart with the credential";
|
|
68834
|
+
}
|
|
68835
|
+
if (code === H0_SEAT_CLAIM_REFUSED_CODE) {
|
|
68836
|
+
return H0_SEAT_LISTENER_STOP_SENTENCE;
|
|
67901
68837
|
}
|
|
67902
68838
|
if (code === "permission_canary_failed") {
|
|
67903
68839
|
if (provider === "claude") {
|
|
@@ -68053,7 +68989,8 @@ async function runConfiguredListener(options) {
|
|
|
68053
68989
|
options.cloud,
|
|
68054
68990
|
options.workspaceId,
|
|
68055
68991
|
options.agent,
|
|
68056
|
-
boundFetch
|
|
68992
|
+
boundFetch,
|
|
68993
|
+
true
|
|
68057
68994
|
);
|
|
68058
68995
|
} catch (error2) {
|
|
68059
68996
|
if (managedContextPath !== null) {
|
|
@@ -68064,6 +69001,15 @@ async function runConfiguredListener(options) {
|
|
|
68064
69001
|
}
|
|
68065
69002
|
let storedCredential = null;
|
|
68066
69003
|
const credentialSession = {
|
|
69004
|
+
get expiry() {
|
|
69005
|
+
return liveCredentialSession.expiry;
|
|
69006
|
+
},
|
|
69007
|
+
get renewalDue() {
|
|
69008
|
+
return liveCredentialSession.renewalDue;
|
|
69009
|
+
},
|
|
69010
|
+
get renewalAt() {
|
|
69011
|
+
return liveCredentialSession.renewalAt;
|
|
69012
|
+
},
|
|
68067
69013
|
bearer: async () => {
|
|
68068
69014
|
const credential = await liveCredentialSession.bearer();
|
|
68069
69015
|
if (credential !== storedCredential) {
|
|
@@ -68078,7 +69024,7 @@ async function runConfiguredListener(options) {
|
|
|
68078
69024
|
}
|
|
68079
69025
|
const stored = await readListenerCredentialState(paths.instanceDirectory);
|
|
68080
69026
|
if (stored === null || stored.credential !== credential) {
|
|
68081
|
-
throw new
|
|
69027
|
+
throw new ListenerCredentialStateMismatchError();
|
|
68082
69028
|
}
|
|
68083
69029
|
return stored.credential;
|
|
68084
69030
|
}
|
|
@@ -68215,11 +69161,15 @@ async function runConfiguredListener(options) {
|
|
|
68215
69161
|
profileId: options.cloud.profileId,
|
|
68216
69162
|
workspaceId: options.workspaceId,
|
|
68217
69163
|
principalId: options.principalId,
|
|
69164
|
+
projectDirectory: options.cwd,
|
|
69165
|
+
targetUrl: options.cloud.url,
|
|
68218
69166
|
provider: options.provider,
|
|
68219
69167
|
cswarmVersion: CLI_BUILD_VERSION,
|
|
68220
69168
|
permissionMode: options.permissionMode,
|
|
68221
69169
|
routeMode,
|
|
68222
69170
|
deferOverChars,
|
|
69171
|
+
getCredentialExpiryMs: () => credentialSession.expiry,
|
|
69172
|
+
getCredentialRenewalAt: () => credentialSession.renewalAt,
|
|
68223
69173
|
// The bound a timeout event reports: the last turn's clamped budget when
|
|
68224
69174
|
// one has run, else the configured cap.
|
|
68225
69175
|
getTurnBudgetMs: () => lastAppliedTurnBudgetMs ?? turnBudgetMs,
|
|
@@ -68389,7 +69339,7 @@ async function runListenStart(args) {
|
|
|
68389
69339
|
...stateDirectory2 ? { stateDirectory: stateDirectory2 } : {}
|
|
68390
69340
|
});
|
|
68391
69341
|
const existing = await effectiveListenerStatus(paths);
|
|
68392
|
-
if (existing && (existing.state
|
|
69342
|
+
if (existing && LISTENER_RUNNING_STATES.includes(existing.state)) {
|
|
68393
69343
|
throw new Error(
|
|
68394
69344
|
`a listener is already ${existing.state} for agent ${principalId}`
|
|
68395
69345
|
);
|
|
@@ -68500,7 +69450,8 @@ async function runListenStart(args) {
|
|
|
68500
69450
|
provider,
|
|
68501
69451
|
detail,
|
|
68502
69452
|
reasonCode,
|
|
68503
|
-
failedStatus?.providerMinimumRequiredVersion
|
|
69453
|
+
failedStatus?.providerMinimumRequiredVersion,
|
|
69454
|
+
failedStatus?.credentialCheckEdge ?? null
|
|
68504
69455
|
);
|
|
68505
69456
|
throw new Error(
|
|
68506
69457
|
failedStatus === null ? message : `${message}. ${listenerProviderIdentitySummary(failedStatus)}`
|
|
@@ -68516,7 +69467,8 @@ async function runListenStart(args) {
|
|
|
68516
69467
|
provider,
|
|
68517
69468
|
status.lastErrorDetail,
|
|
68518
69469
|
status.lastErrorReasonCode,
|
|
68519
|
-
status.providerMinimumRequiredVersion
|
|
69470
|
+
status.providerMinimumRequiredVersion,
|
|
69471
|
+
status.credentialCheckEdge ?? null
|
|
68520
69472
|
)}. ${listenerProviderIdentitySummary(status)}`
|
|
68521
69473
|
);
|
|
68522
69474
|
}
|
|
@@ -68550,7 +69502,7 @@ async function runListenStart(args) {
|
|
|
68550
69502
|
const hostNote = `--provider ${provider} names the attendance surface kind for this seat. ${workerAudience}
|
|
68551
69503
|
`;
|
|
68552
69504
|
process.stdout.write(
|
|
68553
|
-
`${args.has("foreground") ? "Listener stopped." : (status.pendingForMainCount ?? 0) > 0 ? "Listener transport is connected, but queued messages are unattended." : "Listener is ready and will keep receiving after this command exits."}
|
|
69505
|
+
`${args.has("foreground") ? "Listener stopped." : LISTENER_RUNNING_STATES.includes(status.state) && status.state !== "ready" ? listenerStartPendingMessage(status) : (status.pendingForMainCount ?? 0) > 0 ? "Listener transport is connected, but queued messages are unattended." : "Listener is ready and will keep receiving after this command exits."}
|
|
68554
69506
|
${renderListenerStatus(status, attendanceEvidence)}
|
|
68555
69507
|
The short credential rotates while this process remains alive and secure local state is available. Run cswarm whoami with this credential to see whether its grant is timeboxed or standing.
|
|
68556
69508
|
` + routingNote + hostNote + `Use listen status/stop with the same agent credential, --workspace-id ${workspaceId2}, and the same Cloud target. --principal-id ${principalId} remains available when no credential is supplied.
|
|
@@ -68693,7 +69645,7 @@ async function runListenStatusOrStop(args, command2) {
|
|
|
68693
69645
|
};
|
|
68694
69646
|
const attendanceEvidence = await collectListenerAttendanceEvidence({
|
|
68695
69647
|
instanceDirectory: paths.instanceDirectory,
|
|
68696
|
-
cwd: process.cwd(),
|
|
69648
|
+
cwd: listenerAttendanceProjectDirectory(status, process.cwd()),
|
|
68697
69649
|
principalId,
|
|
68698
69650
|
cloud,
|
|
68699
69651
|
workspaceId: workspaceId2,
|
|
@@ -68995,15 +69947,13 @@ function settingsHaveScopedClaudeHook(settings, principalId) {
|
|
|
68995
69947
|
);
|
|
68996
69948
|
});
|
|
68997
69949
|
}
|
|
68998
|
-
async function
|
|
68999
|
-
const surface = await new FileHookSurfaceStore(instanceDirectory).evidence();
|
|
69000
|
-
if (surface.exists) return true;
|
|
69950
|
+
async function listenerSettingsHookInstalled(cwd, principalId) {
|
|
69001
69951
|
const repositoryRoot = gitRepositoryRoot(cwd) ?? cwd;
|
|
69002
|
-
const settingsPaths =
|
|
69952
|
+
const settingsPaths = [
|
|
69003
69953
|
(0, import_node_path24.join)(repositoryRoot, CLAUDE_PROJECT_SETTINGS_IGNORE_LINE),
|
|
69004
69954
|
(0, import_node_path24.join)(repositoryRoot, CLAUDE_REPO_SETTINGS_IGNORE_LINE),
|
|
69005
69955
|
userClaudeSettingsTarget().path
|
|
69006
|
-
]
|
|
69956
|
+
];
|
|
69007
69957
|
for (const path of settingsPaths) {
|
|
69008
69958
|
if (settingsHaveScopedClaudeHook(readClaudeSettings(path), principalId)) {
|
|
69009
69959
|
return true;
|
|
@@ -69011,6 +69961,11 @@ async function listenerHookSurfacePresent(instanceDirectory, cwd, principalId) {
|
|
|
69011
69961
|
}
|
|
69012
69962
|
return false;
|
|
69013
69963
|
}
|
|
69964
|
+
async function listenerHookSurfacePresent(instanceDirectory, cwd, principalId) {
|
|
69965
|
+
const surface = await new FileHookSurfaceStore(instanceDirectory).evidence();
|
|
69966
|
+
if (surface.exists) return true;
|
|
69967
|
+
return await listenerSettingsHookInstalled(cwd, principalId);
|
|
69968
|
+
}
|
|
69014
69969
|
async function listenerWatcherSurfacePresent(cloud, workspaceId2, principalId) {
|
|
69015
69970
|
return await arrivalWatchLockHeld(
|
|
69016
69971
|
arrivalWatchLockPath(cloud, workspaceId2, principalId)
|
|
@@ -69029,9 +69984,11 @@ async function listenerHasAttendanceSurface(options) {
|
|
|
69029
69984
|
options.principalId
|
|
69030
69985
|
);
|
|
69031
69986
|
}
|
|
69987
|
+
function listenerAttendanceProjectDirectory(status, callerDirectory) {
|
|
69988
|
+
return status.projectDirectory ?? callerDirectory;
|
|
69989
|
+
}
|
|
69032
69990
|
async function collectListenerAttendanceEvidence(options) {
|
|
69033
|
-
const
|
|
69034
|
-
options.instanceDirectory,
|
|
69991
|
+
const settingsHook = await listenerSettingsHookInstalled(
|
|
69035
69992
|
options.cwd,
|
|
69036
69993
|
options.principalId
|
|
69037
69994
|
);
|
|
@@ -69042,10 +69999,10 @@ async function collectListenerAttendanceEvidence(options) {
|
|
|
69042
69999
|
);
|
|
69043
70000
|
return {
|
|
69044
70001
|
pendingForMainOldestAt: options.pendingForMainOldestAt,
|
|
69045
|
-
hookSurfaceExists:
|
|
70002
|
+
hookSurfaceExists: options.hookSurfaceExists,
|
|
69046
70003
|
hookSurfaceAdvanced: options.hookSurfaceAdvanced,
|
|
69047
70004
|
watcherLockHeld: watcher,
|
|
69048
|
-
attendingSurfaces: listenerAttendingSurfaces(
|
|
70005
|
+
attendingSurfaces: listenerAttendingSurfaces(settingsHook, watcher)
|
|
69049
70006
|
};
|
|
69050
70007
|
}
|
|
69051
70008
|
function claudeUserPromptHookSnippet(principalId) {
|
|
@@ -70678,6 +71635,9 @@ ${usage()}
|
|
|
70678
71635
|
process.exitCode = exitCodeFor(error2);
|
|
70679
71636
|
});
|
|
70680
71637
|
}
|
|
71638
|
+
function isFollowRenewalCredentialFailure(error2) {
|
|
71639
|
+
return isFollowCredentialFailure(error2) || error2 instanceof RenewalReauthorisationRequired || error2 instanceof RenewalCredentialCheckError || error2 instanceof RenewalRevoked || error2 instanceof RenewalSuspended;
|
|
71640
|
+
}
|
|
70681
71641
|
// Annotate the CommonJS export names for ESM import in node:
|
|
70682
71642
|
0 && (module.exports = {
|
|
70683
71643
|
AGENT_COMMANDS,
|
|
@@ -70711,12 +71671,15 @@ ${usage()}
|
|
|
70711
71671
|
agentToolsForTransport,
|
|
70712
71672
|
clampTurnBudgetToCredential,
|
|
70713
71673
|
claudeUserPromptHookSnippet,
|
|
71674
|
+
collectListenerAttendanceEvidence,
|
|
70714
71675
|
describeAudience,
|
|
70715
71676
|
formatBodySourceConflict,
|
|
70716
71677
|
formatBodySourceMissing,
|
|
70717
71678
|
formatBodyUsage,
|
|
70718
71679
|
formatOrList,
|
|
70719
71680
|
isCliMain,
|
|
71681
|
+
isFollowRenewalCredentialFailure,
|
|
71682
|
+
listenerAttendanceProjectDirectory,
|
|
70720
71683
|
listenerFailureMessage,
|
|
70721
71684
|
listenerHostLimits,
|
|
70722
71685
|
listenerMainHostLimits,
|
|
@@ -70724,6 +71687,8 @@ ${usage()}
|
|
|
70724
71687
|
listenerPollIntervalMs,
|
|
70725
71688
|
listenerProviderInstallEvidence,
|
|
70726
71689
|
listenerRouteConfiguration,
|
|
71690
|
+
listenerSettingsHookInstalled,
|
|
71691
|
+
listenerStartPendingMessage,
|
|
70727
71692
|
listenerStatusJson,
|
|
70728
71693
|
messageFormatAdvisory,
|
|
70729
71694
|
postSignalAllowedFlags,
|