instar 1.3.1235 → 1.3.1237
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 +87 -8
- package/dist/coordination/AccountFollowMeMandateDelivery.d.ts +6 -0
- package/dist/coordination/AccountFollowMeMandateDelivery.d.ts.map +1 -1
- package/dist/coordination/AccountFollowMeMandateDelivery.js +16 -2
- package/dist/coordination/AccountFollowMeMandateDelivery.js.map +1 -1
- package/dist/coordination/DeliveredMandateStore.d.ts +4 -0
- package/dist/coordination/DeliveredMandateStore.d.ts.map +1 -1
- package/dist/coordination/DeliveredMandateStore.js +16 -2
- package/dist/coordination/DeliveredMandateStore.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +19 -1
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/data/standards-guard-index.json +1 -1
- package/dist/data/standards-guard-index.meta.json +2 -2
- package/dist/data/standards-registry.meta.json +1 -1
- package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
- package/dist/messaging/TelegramAdapter.js +25 -7
- package/dist/messaging/TelegramAdapter.js.map +1 -1
- package/dist/messaging/TelegramEditRejection.d.ts +17 -0
- package/dist/messaging/TelegramEditRejection.d.ts.map +1 -0
- package/dist/messaging/TelegramEditRejection.js +44 -0
- package/dist/messaging/TelegramEditRejection.js.map +1 -0
- package/dist/messaging/telegram-origin/OriginAwareness.d.ts +1 -0
- package/dist/messaging/telegram-origin/OriginAwareness.d.ts.map +1 -1
- package/dist/messaging/telegram-origin/OriginAwareness.js +3 -0
- package/dist/messaging/telegram-origin/OriginAwareness.js.map +1 -1
- package/dist/messaging/telegram-origin/TelegramOriginService.d.ts.map +1 -1
- package/dist/messaging/telegram-origin/TelegramOriginService.js +8 -2
- package/dist/messaging/telegram-origin/TelegramOriginService.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +3 -1
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +12 -1
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +2 -0
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts +5 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +240 -7
- package/dist/server/routes.js.map +1 -1
- package/package.json +2 -1
- package/src/data/builtin-manifest.json +64 -64
- package/src/data/standards-guard-index.json +1 -1
- package/src/data/standards-guard-index.meta.json +2 -2
- package/src/data/standards-registry.meta.json +1 -1
- package/src/scaffold/templates.ts +3 -1
- package/upgrades/1.3.1236.md +35 -0
- package/upgrades/1.3.1237.md +27 -0
- package/upgrades/relogin-pool-one-click.eli16.md +9 -0
- package/upgrades/side-effects/relogin-pool-one-click.md +86 -0
- package/upgrades/side-effects/telegram-dashboard-edit-rejection.md +192 -0
package/dist/server/routes.js
CHANGED
|
@@ -29426,8 +29426,8 @@ document.getElementById('mcpForm').addEventListener('submit', async function (e)
|
|
|
29426
29426
|
});
|
|
29427
29427
|
// Assisted subscription re-login: one verified approval, then the service
|
|
29428
29428
|
// owns the bounded autonomous flow. The store exposes closed metadata only.
|
|
29429
|
-
router.get('/subscription-relogin', (req, res) => {
|
|
29430
|
-
if (!ctx.subscriptionRelogin) {
|
|
29429
|
+
router.get('/subscription-relogin', async (req, res) => {
|
|
29430
|
+
if (!ctx.subscriptionRelogin && req.query.scope !== 'pool') {
|
|
29431
29431
|
res.status(503).json({ enabled: false, error: 'subscription re-login is not configured' });
|
|
29432
29432
|
return;
|
|
29433
29433
|
}
|
|
@@ -29435,10 +29435,66 @@ document.getElementById('mcpForm').addEventListener('submit', async function (e)
|
|
|
29435
29435
|
const state = typeof req.query.state === 'string' ? req.query.state : undefined;
|
|
29436
29436
|
const accountId = typeof req.query.accountId === 'string' ? req.query.accountId : undefined;
|
|
29437
29437
|
const limit = typeof req.query.limit === 'string' ? Number(req.query.limit) : undefined;
|
|
29438
|
-
|
|
29439
|
-
|
|
29440
|
-
|
|
29441
|
-
|
|
29438
|
+
const localEpisodes = ctx.subscriptionRelogin?.store.list({
|
|
29439
|
+
state: state,
|
|
29440
|
+
accountId, limit,
|
|
29441
|
+
}) ?? [];
|
|
29442
|
+
if (req.query.scope !== 'pool') {
|
|
29443
|
+
res.json({ enabled: true, episodes: localEpisodes });
|
|
29444
|
+
return;
|
|
29445
|
+
}
|
|
29446
|
+
const selfMachineId = ctx.meshSelfId ?? ctx.config.machineId ?? 'local';
|
|
29447
|
+
const selfMachineNickname = ctx.machinePoolRegistry?.getCapacity(selfMachineId)?.nickname;
|
|
29448
|
+
const failed = [];
|
|
29449
|
+
const unavailable = [];
|
|
29450
|
+
const episodes = localEpisodes
|
|
29451
|
+
.filter((episode) => {
|
|
29452
|
+
if (episode.machineId === selfMachineId)
|
|
29453
|
+
return true;
|
|
29454
|
+
failed.push({ machineId: selfMachineId, error: 'episode-machine-mismatch' });
|
|
29455
|
+
return false;
|
|
29456
|
+
})
|
|
29457
|
+
.map((episode) => ({ ...episode, machineNickname: selfMachineNickname, remote: false }));
|
|
29458
|
+
if (!ctx.subscriptionRelogin)
|
|
29459
|
+
unavailable.push({ machineId: selfMachineId, reason: 'feature-unavailable' });
|
|
29460
|
+
const query = new URLSearchParams();
|
|
29461
|
+
if (state)
|
|
29462
|
+
query.set('state', state);
|
|
29463
|
+
if (accountId)
|
|
29464
|
+
query.set('accountId', accountId);
|
|
29465
|
+
if (limit !== undefined)
|
|
29466
|
+
query.set('limit', String(limit));
|
|
29467
|
+
const suffix = query.size > 0 ? `?${query.toString()}` : '';
|
|
29468
|
+
await Promise.all((ctx.resolvePeerUrls?.() ?? []).map(async (peer) => {
|
|
29469
|
+
try {
|
|
29470
|
+
const response = await fetch(`${peer.url}/subscription-relogin${suffix}`, {
|
|
29471
|
+
headers: { Authorization: `Bearer ${ctx.config.authToken}` },
|
|
29472
|
+
signal: AbortSignal.timeout(5_000),
|
|
29473
|
+
});
|
|
29474
|
+
if (!response.ok) {
|
|
29475
|
+
if (response.status === 503) {
|
|
29476
|
+
unavailable.push({ machineId: peer.machineId, reason: 'feature-unavailable' });
|
|
29477
|
+
return;
|
|
29478
|
+
}
|
|
29479
|
+
failed.push({ machineId: peer.machineId, error: response.status === 401 || response.status === 403 ? 'unauthorized' : 'error' });
|
|
29480
|
+
return;
|
|
29481
|
+
}
|
|
29482
|
+
const body = await response.json();
|
|
29483
|
+
if (body.enabled === false) {
|
|
29484
|
+
unavailable.push({ machineId: peer.machineId, reason: 'feature-unavailable' });
|
|
29485
|
+
return;
|
|
29486
|
+
}
|
|
29487
|
+
const nickname = ctx.machinePoolRegistry?.getCapacity(peer.machineId)?.nickname;
|
|
29488
|
+
for (const episode of body.episodes ?? []) {
|
|
29489
|
+
episodes.push({ ...episode, machineId: peer.machineId, machineNickname: nickname, remote: true });
|
|
29490
|
+
}
|
|
29491
|
+
}
|
|
29492
|
+
catch (error) {
|
|
29493
|
+
const name = error instanceof Error ? error.name : '';
|
|
29494
|
+
failed.push({ machineId: peer.machineId, error: name === 'TimeoutError' || name === 'AbortError' ? 'timeout' : 'unreachable' });
|
|
29495
|
+
}
|
|
29496
|
+
}));
|
|
29497
|
+
res.json({ enabled: true, episodes, scope: 'pool', pool: { failed, unavailable } });
|
|
29442
29498
|
}
|
|
29443
29499
|
catch (error) {
|
|
29444
29500
|
res.status(400).json({ error: error instanceof Error ? error.message : 'invalid re-login query' });
|
|
@@ -29492,6 +29548,169 @@ document.getElementById('mcpForm').addEventListener('submit', async function (e)
|
|
|
29492
29548
|
res.status(status).json({ error: message });
|
|
29493
29549
|
}
|
|
29494
29550
|
});
|
|
29551
|
+
// Target-local point of use for a one-click account×machine repair. The
|
|
29552
|
+
// fronting dashboard has already verified recent operator presence and issued
|
|
29553
|
+
// the same exact-bounds re-mint mandate used by Account Follow-Me. This route
|
|
29554
|
+
// independently re-verifies that mandate for this account and this machine.
|
|
29555
|
+
router.post('/subscription-relogin/:episodeId/approve-with-mandate', async (req, res) => {
|
|
29556
|
+
if (!ctx.subscriptionRelogin || !ctx.coordination?.gate) {
|
|
29557
|
+
res.status(503).json({ enabled: false, error: 'subscription re-login or mandate gate is not configured' });
|
|
29558
|
+
return;
|
|
29559
|
+
}
|
|
29560
|
+
const mandateId = typeof req.body?.mandateId === 'string' ? req.body.mandateId : '';
|
|
29561
|
+
const accountId = typeof req.body?.accountId === 'string' ? req.body.accountId : '';
|
|
29562
|
+
const repairAction = typeof req.body?.action === 'string' ? req.body.action : 'approve';
|
|
29563
|
+
const targetMachineId = ctx.meshSelfId ?? ctx.config.machineId ?? 'local';
|
|
29564
|
+
if (!mandateId || !accountId || !['approve', 'retry', 'cancel'].includes(repairAction)) {
|
|
29565
|
+
res.status(400).json({ error: 'mandateId, accountId, and a valid action are required' });
|
|
29566
|
+
return;
|
|
29567
|
+
}
|
|
29568
|
+
const episode = ctx.subscriptionRelogin.store.get(req.params.episodeId);
|
|
29569
|
+
if (!episode) {
|
|
29570
|
+
res.status(404).json({ error: 're-login episode not found' });
|
|
29571
|
+
return;
|
|
29572
|
+
}
|
|
29573
|
+
if (episode.accountId !== accountId || episode.machineId !== targetMachineId) {
|
|
29574
|
+
res.status(409).json({ error: 're-login episode does not match the authorized account and machine' });
|
|
29575
|
+
return;
|
|
29576
|
+
}
|
|
29577
|
+
const actionAllowed = repairAction === 'approve' ? episode.state === 'suggested'
|
|
29578
|
+
: repairAction === 'retry' ? episode.state === 'failed'
|
|
29579
|
+
: !['succeeded', 'refused', 'cancelled'].includes(episode.state);
|
|
29580
|
+
if (!actionAllowed) {
|
|
29581
|
+
res.status(409).json({ error: 're-login episode is not eligible for this action' });
|
|
29582
|
+
return;
|
|
29583
|
+
}
|
|
29584
|
+
const verdict = ctx.coordination.gate.evaluate({
|
|
29585
|
+
action: 'account-follow-me',
|
|
29586
|
+
params: { accountId, targetMachineId, mechanism: 're-mint', episodeId: episode.id,
|
|
29587
|
+
inputDigest: episode.inputDigest, repairAction },
|
|
29588
|
+
agentFp: resolveAgentFingerprint(ctx), mandateId,
|
|
29589
|
+
});
|
|
29590
|
+
if (verdict.decision !== 'allow') {
|
|
29591
|
+
const delivered = ctx.verifyDeliveredMandate?.(mandateId);
|
|
29592
|
+
if (!delivered || delivered.accountId !== accountId || delivered.targetMachineId !== targetMachineId ||
|
|
29593
|
+
delivered.mechanism !== 're-mint' || delivered.episodeId !== episode.id ||
|
|
29594
|
+
delivered.inputDigest !== episode.inputDigest || delivered.repairAction !== repairAction) {
|
|
29595
|
+
res.status(403).json({ error: 'subscription re-login not authorized', reason: verdict.reason });
|
|
29596
|
+
return;
|
|
29597
|
+
}
|
|
29598
|
+
if (!ctx.consumeDeliveredMandate?.(mandateId)) {
|
|
29599
|
+
res.status(403).json({ error: 'subscription re-login authorization was already consumed' });
|
|
29600
|
+
return;
|
|
29601
|
+
}
|
|
29602
|
+
}
|
|
29603
|
+
else {
|
|
29604
|
+
const consumed = ctx.coordination.store.revoke(mandateId, 'consumed by subscription re-login');
|
|
29605
|
+
if (!consumed?.revoked) {
|
|
29606
|
+
res.status(403).json({ error: 'subscription re-login authorization could not be consumed' });
|
|
29607
|
+
return;
|
|
29608
|
+
}
|
|
29609
|
+
}
|
|
29610
|
+
try {
|
|
29611
|
+
const result = repairAction === 'approve' ? await ctx.subscriptionRelogin.approve(episode.id)
|
|
29612
|
+
: repairAction === 'retry' ? await ctx.subscriptionRelogin.retry?.(episode.id)
|
|
29613
|
+
: await ctx.subscriptionRelogin.cancel(episode.id);
|
|
29614
|
+
if (!result)
|
|
29615
|
+
throw new Error('re-login action is not configured');
|
|
29616
|
+
res.status(repairAction === 'cancel' ? 200 : 202).json({ enabled: true, accepted: true, episode: result });
|
|
29617
|
+
}
|
|
29618
|
+
catch (error) {
|
|
29619
|
+
const message = error instanceof Error ? error.message : 're-login approval failed';
|
|
29620
|
+
res.status(/mismatch|approvable|conflict|closed|expired/.test(message) ? 409 : 500).json({ error: message });
|
|
29621
|
+
}
|
|
29622
|
+
});
|
|
29623
|
+
// Fronting one-click route: recent dashboard unlock → exact account/machine
|
|
29624
|
+
// mandate → signed mesh delivery → target-local point-of-use verification.
|
|
29625
|
+
router.post('/subscription-relogin/repair-cell', async (req, res) => {
|
|
29626
|
+
if (!ctx.coordination) {
|
|
29627
|
+
res.status(503).json({ error: 'repair coordination is not configured' });
|
|
29628
|
+
return;
|
|
29629
|
+
}
|
|
29630
|
+
if (!requireReloginOperatorPin(req, res))
|
|
29631
|
+
return;
|
|
29632
|
+
const accountId = typeof req.body?.accountId === 'string' ? req.body.accountId.trim() : '';
|
|
29633
|
+
const machineId = typeof req.body?.machineId === 'string' ? req.body.machineId.trim() : '';
|
|
29634
|
+
const episodeId = typeof req.body?.episodeId === 'string' ? req.body.episodeId.trim() : '';
|
|
29635
|
+
const repairAction = typeof req.body?.action === 'string' ? req.body.action : 'approve';
|
|
29636
|
+
if (!accountId || !machineId || !episodeId || !['approve', 'retry', 'cancel'].includes(repairAction)) {
|
|
29637
|
+
res.status(400).json({ error: 'accountId, machineId, episodeId, and a valid action are required' });
|
|
29638
|
+
return;
|
|
29639
|
+
}
|
|
29640
|
+
const selfMachineId = ctx.meshSelfId ?? ctx.config.machineId ?? 'local';
|
|
29641
|
+
const isSelf = machineId === selfMachineId;
|
|
29642
|
+
const peer = isSelf ? null : (ctx.resolvePeerUrls?.() ?? []).find((candidate) => candidate.machineId === machineId);
|
|
29643
|
+
if (!isSelf && !peer) {
|
|
29644
|
+
res.status(502).json({ error: 'target machine is not reachable right now', retryable: true });
|
|
29645
|
+
return;
|
|
29646
|
+
}
|
|
29647
|
+
const base = isSelf ? `http://${ctx.config.host || '127.0.0.1'}:${ctx.config.port}` : peer.url;
|
|
29648
|
+
let targetEpisode = null;
|
|
29649
|
+
if (isSelf) {
|
|
29650
|
+
targetEpisode = ctx.subscriptionRelogin?.store.get(episodeId) ?? null;
|
|
29651
|
+
}
|
|
29652
|
+
else {
|
|
29653
|
+
try {
|
|
29654
|
+
const response = await fetch(`${base}/subscription-relogin/${encodeURIComponent(episodeId)}/events`, {
|
|
29655
|
+
headers: { Authorization: `Bearer ${ctx.config.authToken}` }, signal: AbortSignal.timeout(5_000),
|
|
29656
|
+
});
|
|
29657
|
+
if (response.ok)
|
|
29658
|
+
targetEpisode = (await response.json()).episode ?? null;
|
|
29659
|
+
}
|
|
29660
|
+
catch { /* typed unreachable response below */ }
|
|
29661
|
+
}
|
|
29662
|
+
if (!targetEpisode) {
|
|
29663
|
+
res.status(isSelf && !ctx.subscriptionRelogin ? 503 : 404).json({ error: 'target repair episode is unavailable' });
|
|
29664
|
+
return;
|
|
29665
|
+
}
|
|
29666
|
+
const targetActionAllowed = repairAction === 'approve' ? targetEpisode.state === 'suggested'
|
|
29667
|
+
: repairAction === 'retry' ? targetEpisode.state === 'failed'
|
|
29668
|
+
: !['succeeded', 'refused', 'cancelled'].includes(targetEpisode.state);
|
|
29669
|
+
if (targetEpisode.accountId !== accountId || targetEpisode.machineId !== machineId || !targetActionAllowed) {
|
|
29670
|
+
res.status(409).json({ error: 'target repair episode does not match this one-click approval' });
|
|
29671
|
+
return;
|
|
29672
|
+
}
|
|
29673
|
+
let mandateId;
|
|
29674
|
+
try {
|
|
29675
|
+
const mandate = ctx.coordination.store.issue({
|
|
29676
|
+
scope: 'subscription-relogin',
|
|
29677
|
+
agents: [resolveAgentFingerprint(ctx), resolveAgentFingerprint(ctx)],
|
|
29678
|
+
authorities: [{ action: 'account-follow-me', bounds: {
|
|
29679
|
+
accountId, targetMachineId: machineId, mechanism: 're-mint', episodeId,
|
|
29680
|
+
inputDigest: targetEpisode.inputDigest, repairAction,
|
|
29681
|
+
} }],
|
|
29682
|
+
author: 'justin', expiresAt: new Date(Date.now() + 15 * 60_000).toISOString(),
|
|
29683
|
+
});
|
|
29684
|
+
mandateId = mandate.id;
|
|
29685
|
+
if (!isSelf) {
|
|
29686
|
+
if (!ctx.packageMandateForDelivery || !ctx.deliverMandateToMachine) {
|
|
29687
|
+
res.status(503).json({ error: 'cross-machine authorization delivery unavailable' });
|
|
29688
|
+
return;
|
|
29689
|
+
}
|
|
29690
|
+
const outcome = await ctx.deliverMandateToMachine({ targetMachineId: machineId, portable: ctx.packageMandateForDelivery(mandate) });
|
|
29691
|
+
if (!outcome.ok) {
|
|
29692
|
+
res.status(502).json({ error: 'could not deliver repair authorization to the target machine', retryable: true });
|
|
29693
|
+
return;
|
|
29694
|
+
}
|
|
29695
|
+
}
|
|
29696
|
+
}
|
|
29697
|
+
catch (error) {
|
|
29698
|
+
res.status(500).json({ error: error instanceof Error ? error.message : 'repair authorization failed' });
|
|
29699
|
+
return;
|
|
29700
|
+
}
|
|
29701
|
+
try {
|
|
29702
|
+
const response = await fetch(`${base}/subscription-relogin/${encodeURIComponent(episodeId)}/approve-with-mandate`, {
|
|
29703
|
+
method: 'POST',
|
|
29704
|
+
headers: { Authorization: `Bearer ${ctx.config.authToken}`, 'Content-Type': 'application/json' },
|
|
29705
|
+
body: JSON.stringify({ mandateId, accountId, action: repairAction }), signal: AbortSignal.timeout(15_000),
|
|
29706
|
+
});
|
|
29707
|
+
const body = await response.json().catch(() => ({}));
|
|
29708
|
+
res.status(response.status).json(body);
|
|
29709
|
+
}
|
|
29710
|
+
catch {
|
|
29711
|
+
res.status(502).json({ error: 'could not reach the machine doing the repair', retryable: true });
|
|
29712
|
+
}
|
|
29713
|
+
});
|
|
29495
29714
|
router.post('/subscription-relogin/:episodeId/cancel', async (req, res) => {
|
|
29496
29715
|
if (!ctx.subscriptionRelogin) {
|
|
29497
29716
|
res.status(503).json({ enabled: false, error: 'subscription re-login is not configured' });
|
|
@@ -30042,6 +30261,17 @@ document.getElementById('mcpForm').addEventListener('submit', async function (e)
|
|
|
30042
30261
|
}
|
|
30043
30262
|
const { mandateId, accountId } = b;
|
|
30044
30263
|
const targetMachineId = ctx.meshSelfId ?? ctx.config.machineId ?? 'local';
|
|
30264
|
+
// Authority separation: assisted-relogin mandates intentionally reuse the
|
|
30265
|
+
// signed delivery transport, but they MUST NOT authorize generic enrollment.
|
|
30266
|
+
// Reject any local mandate carrying the repair-only binding fields before
|
|
30267
|
+
// consulting the generic gate (which evaluates only the generic subset).
|
|
30268
|
+
const localMandate = ctx.coordination.store?.get?.(mandateId);
|
|
30269
|
+
const localAuthority = localMandate?.authorities?.find((authority) => authority.action === 'account-follow-me');
|
|
30270
|
+
const localBounds = (localAuthority?.bounds ?? {});
|
|
30271
|
+
if (localBounds.episodeId !== undefined || localBounds.inputDigest !== undefined || localBounds.repairAction !== undefined) {
|
|
30272
|
+
res.status(403).json({ error: 'repair-only mandate cannot authorize account enrollment' });
|
|
30273
|
+
return;
|
|
30274
|
+
}
|
|
30045
30275
|
// THE AUTHORIZATION (deny-by-default): consult the operator mandate for THIS exact
|
|
30046
30276
|
// (account, this machine, mechanism). A non-allow verdict STOPS — UNLESS a cross-machine
|
|
30047
30277
|
// DELIVERED mandate authorizes it (the one-dashboard path, R4a). Never work around a deny.
|
|
@@ -30062,7 +30292,10 @@ document.getElementById('mcpForm').addEventListener('submit', async function (e)
|
|
|
30062
30292
|
const deliveredOk = !!deliveredBounds &&
|
|
30063
30293
|
deliveredBounds.accountId === accountId &&
|
|
30064
30294
|
deliveredBounds.targetMachineId === targetMachineId &&
|
|
30065
|
-
deliveredBounds.mechanism === 're-mint'
|
|
30295
|
+
deliveredBounds.mechanism === 're-mint' &&
|
|
30296
|
+
deliveredBounds.episodeId === undefined &&
|
|
30297
|
+
deliveredBounds.inputDigest === undefined &&
|
|
30298
|
+
deliveredBounds.repairAction === undefined;
|
|
30066
30299
|
if (!deliveredOk) {
|
|
30067
30300
|
res.status(403).json({ error: 'account follow-me not authorized', reason: verdict.reason });
|
|
30068
30301
|
return;
|