instar 1.3.930 → 1.3.932
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/dashboard/subscriptions.js +60 -6
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +41 -10
- package/dist/commands/server.js.map +1 -1
- package/dist/coordination/FollowMeConsumerBackoffStore.d.ts +36 -0
- package/dist/coordination/FollowMeConsumerBackoffStore.d.ts.map +1 -0
- package/dist/coordination/FollowMeConsumerBackoffStore.js +96 -0
- package/dist/coordination/FollowMeConsumerBackoffStore.js.map +1 -0
- package/dist/core/QuotaPoller.d.ts.map +1 -1
- package/dist/core/QuotaPoller.js +3 -14
- package/dist/core/QuotaPoller.js.map +1 -1
- package/dist/core/SubscriptionAccountEmailRepair.d.ts +19 -0
- package/dist/core/SubscriptionAccountEmailRepair.d.ts.map +1 -0
- package/dist/core/SubscriptionAccountEmailRepair.js +58 -0
- package/dist/core/SubscriptionAccountEmailRepair.js.map +1 -0
- package/dist/core/SubscriptionPool.d.ts +80 -6
- package/dist/core/SubscriptionPool.d.ts.map +1 -1
- package/dist/core/SubscriptionPool.js +201 -29
- package/dist/core/SubscriptionPool.js.map +1 -1
- package/dist/core/WriteDomainRegistry.d.ts.map +1 -1
- package/dist/core/WriteDomainRegistry.js +4 -0
- package/dist/core/WriteDomainRegistry.js.map +1 -1
- package/dist/core/resolveFollowMeEnrollTarget.d.ts +1 -0
- package/dist/core/resolveFollowMeEnrollTarget.d.ts.map +1 -1
- package/dist/core/resolveFollowMeEnrollTarget.js +37 -19
- package/dist/core/resolveFollowMeEnrollTarget.js.map +1 -1
- package/dist/messaging/slack/SlackApiClient.d.ts +8 -0
- package/dist/messaging/slack/SlackApiClient.d.ts.map +1 -1
- package/dist/messaging/slack/SlackApiClient.js +44 -2
- package/dist/messaging/slack/SlackApiClient.js.map +1 -1
- package/dist/server/AgentServer.d.ts +5 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +74 -24
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +17 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +202 -29
- package/dist/server/routes.js.map +1 -1
- package/dist/testing/selfActionRegistry.d.ts.map +1 -1
- package/dist/testing/selfActionRegistry.js +28 -0
- package/dist/testing/selfActionRegistry.js.map +1 -1
- package/package.json +2 -1
- package/src/data/builtin-manifest.json +47 -47
- package/upgrades/1.3.931.md +46 -0
- package/upgrades/1.3.932.md +29 -0
- package/upgrades/side-effects/slack-outbound-transport-recovery.md +14 -0
- package/upgrades/side-effects/subscription-account-email-invariant.md +169 -0
|
@@ -471,6 +471,7 @@ export function renderPendingLogins(doc, target, logins, now = Date.now(), outco
|
|
|
471
471
|
/** Pivot the pool-scope + pending-scope bodies into a grid model. Pure + testable. */
|
|
472
472
|
export function buildMatrixModel(poolScope, pendingScope, transient = {}) {
|
|
473
473
|
const accountRows = (poolScope && Array.isArray(poolScope.accounts)) ? poolScope.accounts : [];
|
|
474
|
+
const gapRows = (poolScope && Array.isArray(poolScope.emailGaps)) ? poolScope.emailGaps : [];
|
|
474
475
|
const pendingRows = (pendingScope && Array.isArray(pendingScope.logins)) ? pendingScope.logins : [];
|
|
475
476
|
const failed = (poolScope && poolScope.pool && Array.isArray(poolScope.pool.failed)) ? poolScope.pool.failed : [];
|
|
476
477
|
const selfMachineId = (poolScope && poolScope.pool && poolScope.pool.selfMachineId) || null;
|
|
@@ -485,6 +486,15 @@ export function buildMatrixModel(poolScope, pendingScope, transient = {}) {
|
|
|
485
486
|
if (!mid || offlineMachineIds.has(mid)) continue;
|
|
486
487
|
if (!machines.has(mid)) machines.set(mid, { machineId: mid, nickname: (a.machineNickname || mid), offline: false });
|
|
487
488
|
}
|
|
489
|
+
for (const gap of gapRows) {
|
|
490
|
+
const mid = gap && gap.machineId;
|
|
491
|
+
if (!mid || offlineMachineIds.has(mid)) continue;
|
|
492
|
+
if (!machines.has(mid)) machines.set(mid, {
|
|
493
|
+
machineId: mid,
|
|
494
|
+
nickname: gap.machineNickname || mid,
|
|
495
|
+
offline: false,
|
|
496
|
+
});
|
|
497
|
+
}
|
|
488
498
|
for (const f of failed) {
|
|
489
499
|
const mid = f && f.machineId;
|
|
490
500
|
if (!mid) continue;
|
|
@@ -500,6 +510,13 @@ export function buildMatrixModel(poolScope, pendingScope, transient = {}) {
|
|
|
500
510
|
if (!accounts.has(id)) accounts.set(id, { accountId: id, email: a.email || id });
|
|
501
511
|
else if (!accounts.get(id).email && a.email) accounts.get(id).email = a.email;
|
|
502
512
|
}
|
|
513
|
+
for (const gap of gapRows) {
|
|
514
|
+
const id = gap && gap.accountId;
|
|
515
|
+
if (id && !accounts.has(id)) accounts.set(id, {
|
|
516
|
+
accountId: id,
|
|
517
|
+
email: gap.nickname || id,
|
|
518
|
+
});
|
|
519
|
+
}
|
|
503
520
|
// A pending matrix login can reference an account not yet in any pool row — surface its row too.
|
|
504
521
|
for (const l of pendingRows) {
|
|
505
522
|
const id = l && l.id;
|
|
@@ -529,6 +546,11 @@ export function buildMatrixModel(poolScope, pendingScope, transient = {}) {
|
|
|
529
546
|
for (const l of pendingRows) {
|
|
530
547
|
if (l && l.id && l.machineId) inProgress.set(`${l.id}::${l.machineId}`, l);
|
|
531
548
|
}
|
|
549
|
+
const emailMissing = new Set(
|
|
550
|
+
gapRows
|
|
551
|
+
.filter((gap) => gap && gap.accountId && gap.machineId)
|
|
552
|
+
.map((gap) => `${gap.accountId}::${gap.machineId}`),
|
|
553
|
+
);
|
|
532
554
|
|
|
533
555
|
const machineList = Array.from(machines.values());
|
|
534
556
|
const accountList = Array.from(accounts.values());
|
|
@@ -552,6 +574,7 @@ export function buildMatrixModel(poolScope, pendingScope, transient = {}) {
|
|
|
552
574
|
if (m.offline) state = 'offline'; // whole column offline (FD6)
|
|
553
575
|
else if (t && t.state === 'held') state = 'held';
|
|
554
576
|
else if (t && t.state === 'cant-resolve') state = 'cant-resolve';
|
|
577
|
+
else if (emailMissing.has(key) || (t && t.state === 'email-missing')) state = 'email-missing';
|
|
555
578
|
// Durable pending state wins over enrollment bookkeeping after restart: the
|
|
556
579
|
// full flow rehydrates into its cell even if the pool row still says Active.
|
|
557
580
|
// broken (D5): the server says this attempt's sign-in pane is DEAD (record ⟂ pane
|
|
@@ -586,12 +609,13 @@ export function buildMatrixModel(poolScope, pendingScope, transient = {}) {
|
|
|
586
609
|
|
|
587
610
|
const MATRIX_CELL_GLYPH = {
|
|
588
611
|
active: '✓', 'needs-reauth': '⟳', 'in-progress': '◷', offline: '—', held: '⚠', 'cant-resolve': '✗',
|
|
589
|
-
expired: '✗', 'just-verified': '✓', broken: '✗',
|
|
612
|
+
'email-missing': '⚠', expired: '✗', 'just-verified': '✓', broken: '✗',
|
|
590
613
|
};
|
|
591
614
|
const MATRIX_CELL_WORD = {
|
|
592
615
|
active: 'Active', 'needs-reauth': 'Needs sign-in', 'in-progress': 'Signing in…',
|
|
593
616
|
offline: 'Machine offline', held: 'Didn’t match — re-try', 'cant-resolve': 'Can’t set up', other: 'Set up',
|
|
594
|
-
|
|
617
|
+
'email-missing': 'Account record is missing its email', expired: 'Sign-in link expired',
|
|
618
|
+
'just-verified': 'Set up complete', broken: 'Sign-in needs a restart',
|
|
595
619
|
};
|
|
596
620
|
|
|
597
621
|
/** D5 wording floor: never show a raw internal machine id (m_<hex>) to the operator —
|
|
@@ -700,17 +724,21 @@ export function renderAccountMatrix(doc, target, poolScope, pendingScope, transi
|
|
|
700
724
|
const td = el(doc, 'td', `sub-matrix-cell sub-matrix-${c.state}${justVerified && c.state !== 'just-verified' ? ' sub-matrix-just-verified' : ''}`);
|
|
701
725
|
// Stable cell identity for the interaction-hold rule + targeted merge updates (F9).
|
|
702
726
|
td.setAttribute('data-cell-key', sanitizeForDisplay(`${c.accountId}::${c.machineId}`, 'url'));
|
|
703
|
-
if (c.state === 'empty' || c.state === 'needs-reauth' || c.state === 'held' || c.state === 'cant-resolve' || c.state === 'expired' || c.state === 'broken') {
|
|
727
|
+
if (c.state === 'empty' || c.state === 'needs-reauth' || c.state === 'held' || c.state === 'cant-resolve' || c.state === 'email-missing' || c.state === 'expired' || c.state === 'broken') {
|
|
704
728
|
// An actionable cell → a button that runs the SAME in-dashboard sign-in flow (PIN → link →
|
|
705
729
|
// paste code). empty → "Set up"; needs-reauth (an existing account whose login expired) →
|
|
706
730
|
// "Sign in"; held/cant-resolve/expired/broken → "Retry". A needs-reauth account already
|
|
707
731
|
// resolves to its email, so the start-cell orchestrator drives a real re-auth — never a
|
|
708
732
|
// cosmetic button, and a broken (dead-pane) attempt is superseded server-side on Retry.
|
|
709
|
-
const label = c.state === 'empty' ? 'Set up'
|
|
733
|
+
const label = c.state === 'empty' ? 'Set up'
|
|
734
|
+
: c.state === 'needs-reauth' ? 'Sign in'
|
|
735
|
+
: c.state === 'email-missing' ? 'Repair identity'
|
|
736
|
+
: 'Retry';
|
|
710
737
|
const btn = el(doc, 'button', 'sub-matrix-setup', label);
|
|
711
738
|
btn.setAttribute('data-matrix-setup', '1');
|
|
712
739
|
btn.setAttribute('data-account-id', sanitizeForDisplay(c.accountId, 'label'));
|
|
713
740
|
btn.setAttribute('data-machine-id', sanitizeForDisplay(c.machineId, 'label'));
|
|
741
|
+
if (c.state === 'email-missing') btn.setAttribute('data-email-repair', '1');
|
|
714
742
|
if (c.state !== 'empty') {
|
|
715
743
|
// Show the status word ("⟳ Needs sign-in" / "⚠ Didn't match…") ABOVE the button.
|
|
716
744
|
td.appendChild(el(doc, 'div', 'sub-matrix-glyph', `${MATRIX_CELL_GLYPH[c.state]} ${MATRIX_CELL_WORD[c.state]}`));
|
|
@@ -1197,6 +1225,7 @@ export function createController(opts) {
|
|
|
1197
1225
|
if (!cell) return;
|
|
1198
1226
|
const accountId = btn.getAttribute('data-account-id');
|
|
1199
1227
|
const machineId = btn.getAttribute('data-machine-id');
|
|
1228
|
+
const emailRepair = btn.getAttribute('data-email-repair') === '1';
|
|
1200
1229
|
if (!accountId || !machineId) return;
|
|
1201
1230
|
// A retry clears the previous attempt's terminal presentation for this cell.
|
|
1202
1231
|
delete state.matrixTransient[`${accountId}::${machineId}`];
|
|
@@ -1212,6 +1241,7 @@ export function createController(opts) {
|
|
|
1212
1241
|
confirm.setAttribute('data-matrix-confirm', '1');
|
|
1213
1242
|
confirm.setAttribute('data-account-id', accountId);
|
|
1214
1243
|
confirm.setAttribute('data-machine-id', machineId);
|
|
1244
|
+
if (emailRepair) confirm.setAttribute('data-email-repair', '1');
|
|
1215
1245
|
cell.appendChild(confirm);
|
|
1216
1246
|
// An explicit way OUT of the interaction (the hold would otherwise pin the cell
|
|
1217
1247
|
// forever if the operator changes their mind) — client-side only, nothing started yet.
|
|
@@ -1237,6 +1267,7 @@ export function createController(opts) {
|
|
|
1237
1267
|
if (!cell) return;
|
|
1238
1268
|
const accountId = btn.getAttribute('data-account-id');
|
|
1239
1269
|
const machineId = btn.getAttribute('data-machine-id');
|
|
1270
|
+
const emailRepair = btn.getAttribute('data-email-repair') === '1';
|
|
1240
1271
|
const pinInput = cell.querySelector('.sub-matrix-pin');
|
|
1241
1272
|
const pin = pinInput ? pinInput.value.trim() : '';
|
|
1242
1273
|
if (!accountId || !machineId) { setCellStatus(cell, 'Couldn’t prepare this — please refresh.'); return; }
|
|
@@ -1245,6 +1276,22 @@ export function createController(opts) {
|
|
|
1245
1276
|
btn.setAttribute('disabled', '1');
|
|
1246
1277
|
void (async () => {
|
|
1247
1278
|
try {
|
|
1279
|
+
if (emailRepair) {
|
|
1280
|
+
const r = await postJson(`/subscription-pool/${encodeURIComponent(accountId)}/repair-email`, { pin });
|
|
1281
|
+
if (pinInput) pinInput.value = '';
|
|
1282
|
+
if (r.ok) {
|
|
1283
|
+
cell.removeAttribute('data-interaction-open');
|
|
1284
|
+
setCellStatus(cell, '✓ Account identity repaired.');
|
|
1285
|
+
await tick();
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
const msg = r.json && r.json.error
|
|
1289
|
+
? r.json.error
|
|
1290
|
+
: 'Couldn’t verify this account from its signed-in credential.';
|
|
1291
|
+
setCellStatus(cell, msg);
|
|
1292
|
+
btn.removeAttribute('disabled');
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1248
1295
|
const r = await postJson(URLS.startCell, { accountId, machineId, pin });
|
|
1249
1296
|
if (pinInput) pinInput.value = ''; // PIN is memory-only — clear it immediately
|
|
1250
1297
|
if (r.ok && r.json && r.json.verificationUrl) {
|
|
@@ -1257,8 +1304,15 @@ export function createController(opts) {
|
|
|
1257
1304
|
ttlExpiresAt: r.json.ttlExpiresAt, notice: r.json.notice, kind: r.json.kind,
|
|
1258
1305
|
});
|
|
1259
1306
|
} else if (r.status === 409) {
|
|
1260
|
-
|
|
1261
|
-
|
|
1307
|
+
const code = r.json && r.json.code;
|
|
1308
|
+
state.matrixTransient[`${accountId}::${machineId}`] = {
|
|
1309
|
+
state: code === 'account-record-missing-email' ? 'email-missing' : 'cant-resolve',
|
|
1310
|
+
at: now(),
|
|
1311
|
+
};
|
|
1312
|
+
const message = r.json && r.json.error
|
|
1313
|
+
? r.json.error
|
|
1314
|
+
: 'Can’t set this account up here — its identity details could not be verified.';
|
|
1315
|
+
setCellStatus(cell, message);
|
|
1262
1316
|
btn.removeAttribute('disabled');
|
|
1263
1317
|
} else {
|
|
1264
1318
|
const msg = (r.json && (r.json.error || r.json.reason)) ? (r.json.error || r.json.reason) : `failed (${r.status})`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA4EH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAU3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AA0BjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AA8H7D,OAAO,KAAK,EAAW,oBAAoB,EAAe,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAgFtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AAuID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA+rDD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,YAAY,EACpB,YAAY,EAAE,oBAAoB,GAAG,IAAI,GACxC;IACD,YAAY,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAqBA;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,EAQrD,oBAAoB,CAAC,EAAE,MAAM;IAC3B,YAAY,EAAE,OAAO,kBAAkB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,GACP,IAAI,CAwtBN;AAgmBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA4EH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAU3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AA0BjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AA8H7D,OAAO,KAAK,EAAW,oBAAoB,EAAe,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAgFtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AAuID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA+rDD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,YAAY,EACpB,YAAY,EAAE,oBAAoB,GAAG,IAAI,GACxC;IACD,YAAY,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAqBA;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,EAQrD,oBAAoB,CAAC,EAAE,MAAM;IAC3B,YAAY,EAAE,OAAO,kBAAkB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,GACP,IAAI,CAwtBN;AAgmBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAs7pBtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
|
package/dist/commands/server.js
CHANGED
|
@@ -12165,6 +12165,7 @@ export async function startServer(options) {
|
|
|
12165
12165
|
// compat); only UNKNOWN mode (corrupt on-disk) raises a HIGH attention item, never throws.
|
|
12166
12166
|
const { CredentialLocationLedger, shouldBootSeedCredentialLedger, shouldRunIdentityAudit } = await import('../core/CredentialLocationLedger.js');
|
|
12167
12167
|
const { CredentialIdentityOracle } = await import('../core/CredentialIdentityOracle.js');
|
|
12168
|
+
const credentialIdentityOracle = new CredentialIdentityOracle();
|
|
12168
12169
|
const { CredentialLocationGate } = await import('../core/CredentialLocationGate.js');
|
|
12169
12170
|
const credentialGateEmitAttention = telegram
|
|
12170
12171
|
? (item) => void telegram.createAttentionItem({
|
|
@@ -12180,9 +12181,24 @@ export async function startServer(options) {
|
|
|
12180
12181
|
const credentialLocationLedger = new CredentialLocationLedger({
|
|
12181
12182
|
stateDir: config.stateDir,
|
|
12182
12183
|
pool: subscriptionPool,
|
|
12183
|
-
oracle:
|
|
12184
|
+
oracle: credentialIdentityOracle,
|
|
12184
12185
|
emitAttention: credentialGateEmitAttention,
|
|
12185
12186
|
});
|
|
12187
|
+
// One-shot legacy identity reconciliation. It reads only each record's own
|
|
12188
|
+
// credential slot through the real provider oracle; unresolved gaps remain
|
|
12189
|
+
// quarantined and visible instead of being guessed from metadata.
|
|
12190
|
+
const { repairMissingSubscriptionEmails } = await import('../core/SubscriptionAccountEmailRepair.js');
|
|
12191
|
+
const { SubscriptionAccountEmailRegistrar, SubscriptionEmailReconciliationBarrier, } = await import('../core/SubscriptionPool.js');
|
|
12192
|
+
const subscriptionEmailBarrier = new SubscriptionEmailReconciliationBarrier();
|
|
12193
|
+
const subscriptionEmailRegistrar = new SubscriptionAccountEmailRegistrar(subscriptionPool, credentialIdentityOracle, credentialLocationLedger);
|
|
12194
|
+
const runSubscriptionEmailRepair = async () => {
|
|
12195
|
+
const emailRepair = await repairMissingSubscriptionEmails(subscriptionPool, credentialIdentityOracle, credentialLocationLedger);
|
|
12196
|
+
subscriptionEmailBarrier.finish(emailRepair.unresolved);
|
|
12197
|
+
if (emailRepair.repaired.length > 0 || emailRepair.unresolved.length > 0) {
|
|
12198
|
+
console.log(pc.yellow(` Subscription email reconciliation: ${emailRepair.repaired.length} repaired, ` +
|
|
12199
|
+
`${emailRepair.unresolved.length} unresolved`));
|
|
12200
|
+
}
|
|
12201
|
+
};
|
|
12186
12202
|
// The §2.10 env-token gate (Step 8): the §0.b applicability precondition, enforced. Evaluates
|
|
12187
12203
|
// BOTH `config.anthropicApiKey` (read LIVE per call — restartless) AND the live running fleet's
|
|
12188
12204
|
// durable per-session `credentialSource` flag, so a mid-run flip to an env token cannot silently
|
|
@@ -12424,9 +12440,10 @@ export async function startServer(options) {
|
|
|
12424
12440
|
// their respective awaits. isSeeded() does NOT protect this (seedFromOracle bumps version at
|
|
12425
12441
|
// 'begin', so isSeeded() flips true mid-seed), so the audit gate also checks this flag.
|
|
12426
12442
|
let credSeedInFlight = false;
|
|
12427
|
-
|
|
12443
|
+
const shouldSeedCredentialLedger = shouldBootSeedCredentialLedger(resolveDevAgentGate(config.subscriptionPool?.credentialRepointing?.enabled, config), credentialLocationLedger.isSeeded());
|
|
12444
|
+
const seedCredentialLedger = () => {
|
|
12428
12445
|
credSeedInFlight = true;
|
|
12429
|
-
|
|
12446
|
+
return credentialLocationLedger
|
|
12430
12447
|
.seedFromOracle()
|
|
12431
12448
|
.then((outcomes) => {
|
|
12432
12449
|
const assigned = outcomes.filter((o) => o.result === 'assigned').length;
|
|
@@ -12434,7 +12451,21 @@ export async function startServer(options) {
|
|
|
12434
12451
|
})
|
|
12435
12452
|
.catch((e) => console.warn(`[CredentialLedger] boot seed failed: ${e instanceof Error ? e.message : String(e)}`))
|
|
12436
12453
|
.finally(() => { credSeedInFlight = false; });
|
|
12437
|
-
}
|
|
12454
|
+
};
|
|
12455
|
+
// A legacy email gap must be repaired against an already-existing,
|
|
12456
|
+
// independent slot→tenant binding. seedFromOracle derives its candidates
|
|
12457
|
+
// from complete pool rows and clears assignments first, so running it before
|
|
12458
|
+
// repair could erase the only proof for an email-less row. Preserve that
|
|
12459
|
+
// evidence: seed only when there are no quarantined gaps.
|
|
12460
|
+
let credentialSeedReady = shouldSeedCredentialLedger && subscriptionPool.listEmailGaps().length === 0
|
|
12461
|
+
? seedCredentialLedger()
|
|
12462
|
+
: Promise.resolve();
|
|
12463
|
+
void credentialSeedReady
|
|
12464
|
+
.then(() => runSubscriptionEmailRepair())
|
|
12465
|
+
.catch((error) => {
|
|
12466
|
+
subscriptionEmailBarrier.finish(subscriptionPool.listEmailGaps().length);
|
|
12467
|
+
console.warn(`[subscription-email] reconciliation degraded: ${error instanceof Error ? error.message : String(error)}`);
|
|
12468
|
+
});
|
|
12438
12469
|
// B3b — the periodic balancer pass. tick() is a strict no-op while the feature resolves dark
|
|
12439
12470
|
// (so the timer can always run; the gate lives INSIDE tick()), and on a dev agent it runs the
|
|
12440
12471
|
// full decision loop in dry-run (zero writes). REENTRANCY-GUARDED: a slow tick never overlaps
|
|
@@ -12600,8 +12631,8 @@ export async function startServer(options) {
|
|
|
12600
12631
|
// WS5.2 §5.3/S7 — the follow-me completion gate reads the minted login's account email
|
|
12601
12632
|
// from its config-home slot (the Anthropic OAuth profile endpoint) and validates it against
|
|
12602
12633
|
// operator expectation before the account is selectable. Same oracle the credential-location
|
|
12603
|
-
// ledger uses;
|
|
12604
|
-
oracle:
|
|
12634
|
+
// ledger uses; one process-wide oracle keeps identity evidence coherent.
|
|
12635
|
+
oracle: credentialIdentityOracle,
|
|
12605
12636
|
// A HELD follow-me completion (surprise/mismatched/unverifiable email) raises a HIGH
|
|
12606
12637
|
// attention item for the operator. Map the email-gate's {id,title,body,priority,source}
|
|
12607
12638
|
// shape onto the telegram attention-queue createAttentionItem shape.
|
|
@@ -12683,13 +12714,13 @@ export async function startServer(options) {
|
|
|
12683
12714
|
// Upsert (D5): a re-auth of an EXISTING pool account updates it back to
|
|
12684
12715
|
// active; only a genuinely-new account is added (add() refuses dup ids).
|
|
12685
12716
|
if (subscriptionPool.get(login.id)) {
|
|
12686
|
-
|
|
12687
|
-
nickname: login.label, status: 'active',
|
|
12717
|
+
subscriptionEmailRegistrar.completeValidated(login.id, email, {
|
|
12718
|
+
nickname: login.label, status: 'active',
|
|
12688
12719
|
...(login.configHome ? { configHome: login.configHome } : {}),
|
|
12689
12720
|
});
|
|
12690
12721
|
}
|
|
12691
12722
|
else {
|
|
12692
|
-
|
|
12723
|
+
subscriptionEmailRegistrar.completeNewValidated({
|
|
12693
12724
|
id: login.id, nickname: login.label, provider: login.provider,
|
|
12694
12725
|
framework: login.framework, configHome: login.configHome ?? '', status: 'active', email,
|
|
12695
12726
|
});
|
|
@@ -23272,7 +23303,7 @@ export async function startServer(options) {
|
|
|
23272
23303
|
catch (err) { /* @silent-fallback-ok: fleet-dark optional observer; failure is logged and adds no authority */
|
|
23273
23304
|
console.warn('[AutonomousThroughputFloor] init failed:', err.message);
|
|
23274
23305
|
}
|
|
23275
|
-
const server = new AgentServer({ config, sessionManager, llmQueue: sharedLlmQueue, state, scheduler, telegram, relationships, feedback, feedbackAnomalyDetector, dispatches, updateChecker, autoUpdater, autoDispatcher, quotaTracker, quotaManager, publisher, viewer, tunnel, evolution, watchdog, topicMemory, triageNurse, projectMapper, cartographer: cartographer ?? undefined, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, subscriptionPool, accountFollowMePeerViews: async () => { const nickById = new Map((_listPoolMachines?.() ?? []).map((m) => [m.machineId, m.nickname ?? m.machineId])); let peers = (_resolvePeerUrls?.() ?? []).map((p) => ({ machineId: p.machineId, nickname: nickById.get(p.machineId) ?? p.machineId, url: p.url })); if (peers.length === 0) {
|
|
23306
|
+
const server = new AgentServer({ config, subscriptionEmailBinding: credentialLocationLedger, subscriptionEmailBarrier, subscriptionIdentityOracle: credentialIdentityOracle, sessionManager, llmQueue: sharedLlmQueue, state, scheduler, telegram, relationships, feedback, feedbackAnomalyDetector, dispatches, updateChecker, autoUpdater, autoDispatcher, quotaTracker, quotaManager, publisher, viewer, tunnel, evolution, watchdog, topicMemory, triageNurse, projectMapper, cartographer: cartographer ?? undefined, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, subscriptionPool, accountFollowMePeerViews: async () => { const nickById = new Map((_listPoolMachines?.() ?? []).map((m) => [m.machineId, m.nickname ?? m.machineId])); let peers = (_resolvePeerUrls?.() ?? []).map((p) => ({ machineId: p.machineId, nickname: nickById.get(p.machineId) ?? p.machineId, url: p.url })); if (peers.length === 0) {
|
|
23276
23307
|
peers = (_listPoolMachines?.() ?? []).filter((m) => m.machineId !== _meshSelfId && !!m.lastKnownUrl).map((m) => ({ machineId: m.machineId, nickname: m.nickname ?? m.machineId, url: m.lastKnownUrl }));
|
|
23277
23308
|
} if (peers.length === 0)
|
|
23278
23309
|
return []; const { fetchPeerSubscriptionViews } = await import('../core/fetchPeerSubscriptionViews.js'); return fetchPeerSubscriptionViews({ peers: () => peers, fetchImpl: fetch, authToken: config.authToken ?? '' }); }, quotaPoller, quotaAwareScheduler: _quotaAwareScheduler ?? undefined, proactiveSwapMonitor: _proactiveSwapMonitor ?? undefined, inUseAccountResolver, enrollmentWizard, accountFollowMeRevocation, credentialRepointing, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, greenPrAutoMerger: greenPrAutoMerger ?? undefined, guardLatchStore: guardLatchStore ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, topicProfile: _topicProfileCtx ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, meshBindActive: coordinator.managers.identityManager.hasIdentity() && config.multiMachine?.meshTransport?.enabled !== false, localSigningKeyPem, leaseTransport, peerEndpointRecorder, getSelfMeshEndpoints, onLeasePullRequest: () => leaseCoordinatorRef?.currentLease() ?? null, liveTailReceiver, handoffWireTransport, onHandoffBegin, onHandoffInitiate: handoffInitiate, handoffInProgress: handoffSentinelInProgress, messageLedger, currentInboundByTopic, replyMarkerTransport, onReplyMarker: messageLedger ? (marker) => { const m = marker; messageLedger.applyRemoteReplyMarker(m.dedupeKey, { platform: m.platform, replyIdempotencyKey: m.replyIdempotencyKey, epoch: m.epoch, topic: m.topic ?? null }); } : undefined, whatsapp: whatsappAdapter, slack: slackAdapter, imessage: imessageAdapter, conversationRegistry, conversationBindAuth, conversationFollowThrough, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, conversationStore, threadLog, threadMessageRecorder, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, a2aDeliveryTracker: a2aDeliveryTracker ?? undefined, responseReviewGate, reviewCanaryBattery, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, machinePoolRegistry, ropeHealthMonitor, writeAdmission: writeAdmission ?? undefined, getInboundQueue: () => _inboundQueue, getMachineCoherence: () => _machineCoherenceSentinel, getSingleMachineFailoverGap: () => _singleMachineFailoverGap, getMissingLoginSession: () => _missingLoginSession, getSessionPoolFailoverRunner: () => _sessionPoolFailoverRunnerDriver?.status() ?? null, sessionPoolPromotionActivation: _sessionPoolPromotionActivation, meshRpcDispatcher, deliverA2aToMachine: _deliverA2aToMachine ?? undefined, workingSetPullCoordinator, workingSetArtifactManager, orchestratorPoller, commitmentReplicaStore, preferenceReplicaStore, replicatedRecordEmitter, conflictStore, rollbackUnmerge, droppedOriginRegistry, preferencesUnionReader, forwardCommitmentMutate, sessionOwnershipRegistry, sendDrain: _sendDrain ?? undefined, topicPinStore: _topicPinStore ?? undefined, topicPinSkewQuarantine: _topicPinSkewQuarantine ?? undefined, topicPinFoldView: _topicPinFoldView ?? undefined, ownershipReconciler: _ownershipReconciler ?? undefined, staleOwnerEngine: _staleOwnerEngine ?? undefined, duplicateReconciler: _duplicateReconciler ?? undefined, ownerDarkLadder: _ownerDarkLadder ?? undefined, spawnAdmission: _spawnAdmission ?? undefined, judgmentProvenance: _judgmentProvenance ?? undefined, leaseHandback: _leaseHandbackCtx ?? undefined, streamTicketStore: _streamTicketStore ?? undefined, poolStreamAllowRemoteInput: config.dashboard?.poolStream?.allowRemoteInput ?? false, poolStreamConnector: _poolStreamConnector ?? undefined, secretSync: _secretSyncHandle ?? undefined, meshSelfId: _meshSelfId ?? undefined, resolveRouterUrl: _resolveRouterUrl ?? undefined, resolvePeerUrls: _resolvePeerUrls ?? undefined, guardRegistry, listPoolMachines: _listPoolMachines ?? undefined, deliverMandateToMachine: _deliverMandateToMachine ?? undefined, poolLink: _poolLink ?? undefined, poolPollCache: _poolPollCache ?? undefined, sessionPoolE2EResultStore, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, agentWorktreeReaper, externalHogSentinel, orphanedWorkSentinel, mcpProcessReaper, geminiLoopRunner, sleepController, agentActivityState, reapLog, resumeQueue, resumeDrainer, autonomousLivenessReconciler, enforcedTerminationStatus: () => enforcedTerminationWatchdog?.guardStatus() ?? null, prHandLease: prHandLease ?? undefined, operatorStopRecorder: recordOperatorStop, sleepWakeDetector, unjustifiedStopGate, stopGateDb, stopNotifier, liveTestGate, liveTestGateMode, liveTestRunnerCtx }); // Resolve the late-bound topic-operator getter (increment 2e): routing was
|