instar 1.3.613 → 1.3.615

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.
Files changed (40) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +58 -1
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  5. package/dist/config/ConfigDefaults.js +11 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/AccountFollowMeRevocationStore.d.ts +34 -0
  8. package/dist/core/AccountFollowMeRevocationStore.d.ts.map +1 -0
  9. package/dist/core/AccountFollowMeRevocationStore.js +76 -0
  10. package/dist/core/AccountFollowMeRevocationStore.js.map +1 -0
  11. package/dist/core/EnrollmentWizard.d.ts +48 -0
  12. package/dist/core/EnrollmentWizard.d.ts.map +1 -1
  13. package/dist/core/EnrollmentWizard.js +66 -7
  14. package/dist/core/EnrollmentWizard.js.map +1 -1
  15. package/dist/core/FrameworkLoginDriver.d.ts +7 -0
  16. package/dist/core/FrameworkLoginDriver.d.ts.map +1 -1
  17. package/dist/core/FrameworkLoginDriver.js +12 -3
  18. package/dist/core/FrameworkLoginDriver.js.map +1 -1
  19. package/dist/core/PostUpdateMigrator.d.ts +9 -0
  20. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  21. package/dist/core/PostUpdateMigrator.js +30 -0
  22. package/dist/core/PostUpdateMigrator.js.map +1 -1
  23. package/dist/core/accountFollowMeCooperativeWipe.d.ts +66 -0
  24. package/dist/core/accountFollowMeCooperativeWipe.d.ts.map +1 -0
  25. package/dist/core/accountFollowMeCooperativeWipe.js +179 -0
  26. package/dist/core/accountFollowMeCooperativeWipe.js.map +1 -0
  27. package/dist/server/AgentServer.d.ts +1 -0
  28. package/dist/server/AgentServer.d.ts.map +1 -1
  29. package/dist/server/AgentServer.js +1 -0
  30. package/dist/server/AgentServer.js.map +1 -1
  31. package/dist/server/routes.d.ts +6 -0
  32. package/dist/server/routes.d.ts.map +1 -1
  33. package/dist/server/routes.js +72 -1
  34. package/dist/server/routes.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/data/builtin-manifest.json +64 -64
  37. package/upgrades/1.3.614.md +22 -0
  38. package/upgrades/1.3.615.md +35 -0
  39. package/upgrades/side-effects/ws52-account-follow-me-r6b-reliability.md +66 -0
  40. package/upgrades/side-effects/ws52-account-follow-me-revocation-wiring.md +104 -0
@@ -6515,7 +6515,48 @@ export function createRoutes(ctx) {
6515
6515
  res.status(404).json({ error: `mandate "${req.params.id}" not found` });
6516
6516
  return;
6517
6517
  }
6518
- res.json({ revoked: true, mandate: m });
6518
+ // WS5.2 R12 Account Follow-Me revocation data-plane trigger (PER-SERVER model, OQ6). The
6519
+ // control-plane revoke above already fired (every subsequent MandateGate.evaluate denies). If
6520
+ // the revoked mandate carried an `account-follow-me` authority, run THIS machine's OWN local
6521
+ // data-plane wipe (the operator revoked on the target's OWN dashboard ⇒ the target IS this
6522
+ // machine ⇒ cooperative-online posture). Non-account-follow-me mandates are completely
6523
+ // unaffected. Strict no-op when the executor is unwired OR the feature gate resolves dark
6524
+ // (revoke() returns feature-disabled and runs nothing). Surfaces the honest data-plane outcome
6525
+ // on the response so the operator/dashboard never sees a false "removed".
6526
+ let accountFollowMeRevocation;
6527
+ try {
6528
+ const followMeAuthority = (m.authorities ?? []).find((a) => a.action === 'account-follow-me');
6529
+ if (followMeAuthority && ctx.accountFollowMeRevocation) {
6530
+ const bounds = (followMeAuthority.bounds ?? {});
6531
+ const accountId = typeof bounds.accountId === 'string' ? bounds.accountId : '';
6532
+ const targetMachineId = typeof bounds.targetMachineId === 'string' ? bounds.targetMachineId : '';
6533
+ const mechanism = bounds.mechanism === 'credential-transport' ? 'credential-transport' : 're-mint';
6534
+ if (accountId && targetMachineId) {
6535
+ const acct = ctx.subscriptionPool?.get(accountId) ?? null;
6536
+ accountFollowMeRevocation = ctx.accountFollowMeRevocation.revoke({
6537
+ accountId,
6538
+ accountEmail: acct?.email ?? accountId,
6539
+ targetMachineId,
6540
+ targetMachineNickname: typeof bounds.targetMachineNickname === 'string' ? bounds.targetMachineNickname : targetMachineId,
6541
+ provider: acct?.provider ?? (typeof bounds.provider === 'string' ? bounds.provider : 'the provider'),
6542
+ mandateId: m.id,
6543
+ mechanism,
6544
+ },
6545
+ // PER-SERVER: the operator revoked on the target's own dashboard ⇒ target is online &
6546
+ // cooperative (this very machine). The local wipe runs; an offline/de-paired posture is
6547
+ // only reachable on the cross-machine path, which the per-server model does not use.
6548
+ 'cooperative-online');
6549
+ }
6550
+ }
6551
+ }
6552
+ catch {
6553
+ // @silent-fallback-ok: the data-plane effect must never break the control-plane revoke (which
6554
+ // already succeeded). A wipe error is surfaced honestly INSIDE the executor (fail-closed to
6555
+ // pending) for the normal path; this catch is the last-resort backstop so the route always
6556
+ // returns the successful revoke.
6557
+ accountFollowMeRevocation = undefined;
6558
+ }
6559
+ res.json({ revoked: true, mandate: m, ...(accountFollowMeRevocation ? { accountFollowMeRevocation } : {}) });
6519
6560
  });
6520
6561
  // Add user→agent authority grant(s) to a mandate — PIN-GATED (the same human-
6521
6562
  // authenticated surface as issuance; an agent's Bearer token cannot mint a grant).
@@ -19111,6 +19152,14 @@ export function createRoutes(ctx) {
19111
19152
  res.status(201).json({ enabled: true, login });
19112
19153
  }
19113
19154
  catch (err) {
19155
+ // WS5.2 R6b — a DRIVE failure is honest + retry-able (502), NOT an opaque 500.
19156
+ // No pending-login was issued (the store is written only after the drive
19157
+ // succeeds), so the caller can simply retry.
19158
+ const { EnrollmentDriveError } = await import('../core/EnrollmentWizard.js');
19159
+ if (err instanceof EnrollmentDriveError) {
19160
+ res.status(502).json({ error: 'login-did-not-start', retryable: true, message: err.operatorMessage });
19161
+ return;
19162
+ }
19114
19163
  res.status(500).json({ error: err instanceof Error ? err.message : 'failed to start enrollment' });
19115
19164
  }
19116
19165
  });
@@ -19220,6 +19269,14 @@ export function createRoutes(ctx) {
19220
19269
  // Allocate this account's own config-home slot on THIS machine (one home per credential).
19221
19270
  const safeAccountId = accountId.replace(/[^a-z0-9-]/gi, '-');
19222
19271
  const configHome = path.join(os.homedir(), `.claude-followme-${safeAccountId}`);
19272
+ // WS5.2 R6b — this IS the remote/cloud (follow-me) enrollment path, so use the
19273
+ // remote-aware kind selection (device-code single-code flow where supported) and
19274
+ // thread the LARGER scrape-timeout budget (cloud→provider latency + the two-code
19275
+ // window). The budget comes from the config knob (default 180000); omitted ⇒ the
19276
+ // driver's local-LAN default.
19277
+ const remoteScrapeTimeoutMs = typeof afmCfg?.remoteScrapeTimeoutMs === 'number' && Number.isFinite(afmCfg.remoteScrapeTimeoutMs)
19278
+ ? afmCfg.remoteScrapeTimeoutMs
19279
+ : undefined;
19223
19280
  const login = await ctx.enrollmentWizard.start({
19224
19281
  id: accountId,
19225
19282
  label: target.label,
@@ -19227,10 +19284,24 @@ export function createRoutes(ctx) {
19227
19284
  framework: target.framework,
19228
19285
  configHome,
19229
19286
  expectedEmail: target.expectedEmail,
19287
+ remote: true,
19288
+ remoteScrapeTimeoutMs,
19230
19289
  });
19231
19290
  res.status(201).json({ enabled: true, login });
19232
19291
  }
19233
19292
  catch (err) {
19293
+ // WS5.2 R6b — a DRIVE failure is honest + retry-able (502), NOT an opaque 500.
19294
+ // The store is written ONLY after the drive succeeds, so a drive throw leaves NO
19295
+ // stuck pending-login behind — the caller can simply retry the enrollment.
19296
+ const { EnrollmentDriveError } = await import('../core/EnrollmentWizard.js');
19297
+ if (err instanceof EnrollmentDriveError) {
19298
+ res.status(502).json({
19299
+ error: 'login-did-not-start',
19300
+ retryable: true,
19301
+ message: `couldn’t start the login on the target — ${err.operatorMessage}`,
19302
+ });
19303
+ return;
19304
+ }
19234
19305
  res.status(500).json({ error: err instanceof Error ? err.message : 'follow-me enroll start failed' });
19235
19306
  }
19236
19307
  });