@cotal-ai/core 0.50.1 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth-provider.d.ts +86 -0
- package/dist/auth-provider.d.ts.map +1 -1
- package/dist/auth-provider.js +6 -0
- package/dist/auth-provider.js.map +1 -1
- package/dist/command.d.ts +7 -0
- package/dist/command.d.ts.map +1 -1
- package/dist/command.js.map +1 -1
- package/dist/connector.d.ts +6 -2
- package/dist/connector.d.ts.map +1 -1
- package/dist/connector.js.map +1 -1
- package/dist/endpoint-serve.d.ts +8 -1
- package/dist/endpoint-serve.d.ts.map +1 -1
- package/dist/endpoint-serve.js +13 -2
- package/dist/endpoint-serve.js.map +1 -1
- package/dist/endpoint.d.ts +12 -1
- package/dist/endpoint.d.ts.map +1 -1
- package/dist/endpoint.js +44 -1
- package/dist/endpoint.js.map +1 -1
- package/dist/environment.d.ts +302 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +58 -0
- package/dist/environment.js.map +1 -0
- package/dist/evict.d.ts +9 -5
- package/dist/evict.d.ts.map +1 -1
- package/dist/evict.js +24 -16
- package/dist/evict.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/launch-material.d.ts +2 -0
- package/dist/launch-material.d.ts.map +1 -1
- package/dist/launch-material.js +5 -0
- package/dist/launch-material.js.map +1 -1
- package/dist/launch.d.ts +3 -0
- package/dist/launch.d.ts.map +1 -1
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/endpoint.js
CHANGED
|
@@ -249,6 +249,11 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
249
249
|
presenceRebindAt = 0;
|
|
250
250
|
status = "idle";
|
|
251
251
|
activity;
|
|
252
|
+
condition;
|
|
253
|
+
/** Advances on every condition change so an older in-flight put cannot be the final KV state. */
|
|
254
|
+
conditionRevision = 0;
|
|
255
|
+
/** Read once at construction. Core publishes this opaque provider reference and never parses it. */
|
|
256
|
+
environment;
|
|
252
257
|
/** Mirror of the connector's authoritative attention state, published in presence (advisory). The
|
|
253
258
|
* endpoint never reads these back into delivery — they exist only to broadcast. */
|
|
254
259
|
attentionMode;
|
|
@@ -300,6 +305,8 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
300
305
|
* only evidence the split rate exists. Always on, never behind a flag — a counter you have to
|
|
301
306
|
* enable is not there when the thing you needed it for happened. */
|
|
302
307
|
splitsRecovered = 0;
|
|
308
|
+
/** Presence rows rejected because their embedded id did not match the ACL-scoped KV key. */
|
|
309
|
+
presenceBindingDrops = 0;
|
|
303
310
|
/** This endpoint's wire principal (owner + actor tokens, §13.2) — what its minted grant rows
|
|
304
311
|
* pin. Public so a caller can build owner-mode target blocks for {@link invokeService}. */
|
|
305
312
|
get principal() {
|
|
@@ -310,6 +317,10 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
310
317
|
get splitRecoveryCount() {
|
|
311
318
|
return this.splitsRecovered;
|
|
312
319
|
}
|
|
320
|
+
/** Mis-keyed presence rows this reader rejected. The warning event may be missed; the count cannot. */
|
|
321
|
+
get presenceBindingDropCount() {
|
|
322
|
+
return this.presenceBindingDrops;
|
|
323
|
+
}
|
|
313
324
|
/** The endpoint's own lifecycle UID, REQUIRED for every lifecycle-keyed messaging resource; absent
|
|
314
325
|
* ⇒ loud refusal naming the operation (the hard cut of SPEC §13.1 — no alias-keyed fallback). */
|
|
315
326
|
requireLifecycleUid(what) {
|
|
@@ -419,6 +430,7 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
419
430
|
// principalKey validates both tokens.
|
|
420
431
|
const principal = principalKey(this.owner, this.actor);
|
|
421
432
|
this.card = { ...opts.card, id: principal.key, owner: this.owner, actor: this.actor };
|
|
433
|
+
this.environment = process.env.COTAL_ENVIRONMENT?.trim() || undefined;
|
|
422
434
|
this.servers = opts.servers ?? DEFAULT_SERVER;
|
|
423
435
|
this.token = opts.token;
|
|
424
436
|
this.user = opts.user;
|
|
@@ -1189,6 +1201,10 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
1189
1201
|
this.subs.length = 0;
|
|
1190
1202
|
if (!failedNc)
|
|
1191
1203
|
return;
|
|
1204
|
+
// The old status iterator is stale after nc is cleared, so its close cannot report this edge.
|
|
1205
|
+
// As in doRebuild, teardown itself must announce the no-nc window before closing the socket.
|
|
1206
|
+
this.emit("transport", { connected: false });
|
|
1207
|
+
this.emit("connection", { connected: false });
|
|
1192
1208
|
// Layered teardown, comments kept OUT of the code span below on purpose: the mutation fixture
|
|
1193
1209
|
// bin/smoke/mutations/failed-bind-cleanup.json anchors on that span verbatim and the fixture
|
|
1194
1210
|
// census (bin/smoke/mutation-fixtures.smoke.ts) reddens an anchor that crosses a comment line.
|
|
@@ -2057,6 +2073,12 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
2057
2073
|
this.status = status;
|
|
2058
2074
|
await this.publishPresence();
|
|
2059
2075
|
}
|
|
2076
|
+
/** Publish a harness-reported condition, or clear it. Core stores the relay without interpretation. */
|
|
2077
|
+
async setCondition(condition) {
|
|
2078
|
+
this.condition = condition ?? undefined;
|
|
2079
|
+
this.conditionRevision++;
|
|
2080
|
+
await this.publishPresence();
|
|
2081
|
+
}
|
|
2060
2082
|
/** Publish the agent's global attention mode into presence (advisory observability). Mirror only —
|
|
2061
2083
|
* delivery decisions stay in the connector's authoritative state. */
|
|
2062
2084
|
async setAttention(attention) {
|
|
@@ -5148,6 +5170,8 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
5148
5170
|
// omitted only where the endpoint has none (a pure operator/daemon connection never registers).
|
|
5149
5171
|
...(this.ownLifecycleUid !== undefined ? { lifecycleUid: this.ownLifecycleUid } : {}),
|
|
5150
5172
|
status: this.status,
|
|
5173
|
+
condition: this.condition,
|
|
5174
|
+
environment: this.environment,
|
|
5151
5175
|
activity: this.activity,
|
|
5152
5176
|
attention: this.attentionMode,
|
|
5153
5177
|
channelModes: this.channelModes,
|
|
@@ -5164,6 +5188,7 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
5164
5188
|
// it, a heartbeat put (default 2s) whose ~5s JetStream timeout elapses after a rebuild plants a
|
|
5165
5189
|
// refusal on the connection that just published successfully.
|
|
5166
5190
|
const epoch = this.presenceEpoch;
|
|
5191
|
+
const conditionRevision = this.conditionRevision;
|
|
5167
5192
|
try {
|
|
5168
5193
|
await this.kv.put(this.card.id, JSON.stringify(record));
|
|
5169
5194
|
}
|
|
@@ -5188,6 +5213,13 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
5188
5213
|
// the record with a fresh `since`. Tracked in #1461, not repaired here.
|
|
5189
5214
|
if (epoch !== this.presenceEpoch || this.stopped)
|
|
5190
5215
|
return;
|
|
5216
|
+
// Presence writes may overlap. If this put carried an older condition, repair the KV with the
|
|
5217
|
+
// latest local state before returning so a late failure publish cannot resurrect after a new
|
|
5218
|
+
// turn cleared it. The revision is condition-specific; unrelated heartbeat overlap is unchanged.
|
|
5219
|
+
if (conditionRevision !== this.conditionRevision) {
|
|
5220
|
+
await this.publishPresence();
|
|
5221
|
+
return;
|
|
5222
|
+
}
|
|
5191
5223
|
this.clearPresenceWriteFailure();
|
|
5192
5224
|
}
|
|
5193
5225
|
/** #1356: drop the presence-refusal record when the connection that OBSERVED those refusals goes
|
|
@@ -5440,8 +5472,11 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
5440
5472
|
// with its bucket key is forged or corrupt. Drop it rather than surface a spoofed roster identity.
|
|
5441
5473
|
// The write-side scoping ($KV.<presenceBucket>.<own-id>) is the primary guard; this rejects a
|
|
5442
5474
|
// mis-keyed record even if a broad writer slips one in under another agent's key.
|
|
5443
|
-
if (raw.card?.id !== id)
|
|
5475
|
+
if (raw.card?.id !== id) {
|
|
5476
|
+
this.presenceBindingDrops++;
|
|
5477
|
+
this.emitRecoverable(new Error(`dropped presence entry for key ${JSON.stringify(id)}: card.id ${JSON.stringify(raw.card?.id)} does not match its KV key`));
|
|
5444
5478
|
return;
|
|
5479
|
+
}
|
|
5445
5480
|
const prev = this.roster.get(id);
|
|
5446
5481
|
const stale = Date.now() - raw.ts > this.ttlMs;
|
|
5447
5482
|
// A watch recovering from a stall replays the bucket. Those PUTs still carry the publisher's
|
|
@@ -5481,6 +5516,8 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
5481
5516
|
prev.lifecycleUid === p.lifecycleUid &&
|
|
5482
5517
|
prev.status === p.status &&
|
|
5483
5518
|
prev.activity === p.activity &&
|
|
5519
|
+
sameCondition(prev.condition, p.condition) &&
|
|
5520
|
+
prev.environment === p.environment &&
|
|
5484
5521
|
prev.attention === p.attention &&
|
|
5485
5522
|
sameChannelModes(prev.channelModes, p.channelModes)) {
|
|
5486
5523
|
this.roster.set(id, p);
|
|
@@ -5711,6 +5748,12 @@ function sameChannelModes(a, b) {
|
|
|
5711
5748
|
return false;
|
|
5712
5749
|
return ak.every((k) => a[k] === b?.[k]);
|
|
5713
5750
|
}
|
|
5751
|
+
function sameCondition(a, b) {
|
|
5752
|
+
return a?.code === b?.code
|
|
5753
|
+
&& a?.source === b?.source
|
|
5754
|
+
&& a?.message === b?.message
|
|
5755
|
+
&& a?.since === b?.since;
|
|
5756
|
+
}
|
|
5714
5757
|
function authOpts(a) {
|
|
5715
5758
|
const tls = a.tls ? {} : undefined;
|
|
5716
5759
|
// USER MODE: present the shared auth-account sentinel creds AND the user bearer as `auth_token` (an
|