instar 1.3.605 → 1.3.607

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 (86) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +140 -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 +29 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/coordination/CrossMachineMandate.d.ts +53 -0
  8. package/dist/coordination/CrossMachineMandate.d.ts.map +1 -0
  9. package/dist/coordination/CrossMachineMandate.js +76 -0
  10. package/dist/coordination/CrossMachineMandate.js.map +1 -0
  11. package/dist/core/AccountCredentialShare.d.ts +115 -0
  12. package/dist/core/AccountCredentialShare.d.ts.map +1 -0
  13. package/dist/core/AccountCredentialShare.js +113 -0
  14. package/dist/core/AccountCredentialShare.js.map +1 -0
  15. package/dist/core/AccountFollowMeGrants.d.ts +92 -0
  16. package/dist/core/AccountFollowMeGrants.d.ts.map +1 -0
  17. package/dist/core/AccountFollowMeGrants.js +106 -0
  18. package/dist/core/AccountFollowMeGrants.js.map +1 -0
  19. package/dist/core/AutonomousSessions.d.ts +24 -0
  20. package/dist/core/AutonomousSessions.d.ts.map +1 -1
  21. package/dist/core/AutonomousSessions.js +22 -0
  22. package/dist/core/AutonomousSessions.js.map +1 -1
  23. package/dist/core/CoherenceJournal.d.ts +1 -1
  24. package/dist/core/CoherenceJournal.d.ts.map +1 -1
  25. package/dist/core/CoherenceJournal.js +12 -2
  26. package/dist/core/CoherenceJournal.js.map +1 -1
  27. package/dist/core/PairingEpochManager.d.ts +68 -0
  28. package/dist/core/PairingEpochManager.d.ts.map +1 -0
  29. package/dist/core/PairingEpochManager.js +88 -0
  30. package/dist/core/PairingEpochManager.js.map +1 -0
  31. package/dist/core/PostUpdateMigrator.d.ts +13 -0
  32. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  33. package/dist/core/PostUpdateMigrator.js +105 -0
  34. package/dist/core/PostUpdateMigrator.js.map +1 -1
  35. package/dist/core/SecretStore.d.ts +44 -0
  36. package/dist/core/SecretStore.d.ts.map +1 -1
  37. package/dist/core/SecretStore.js +126 -0
  38. package/dist/core/SecretStore.js.map +1 -1
  39. package/dist/core/SecretSync.d.ts.map +1 -1
  40. package/dist/core/SecretSync.js +6 -0
  41. package/dist/core/SecretSync.js.map +1 -1
  42. package/dist/core/SubscriptionAccountMetaReplicatedStore.d.ts +106 -0
  43. package/dist/core/SubscriptionAccountMetaReplicatedStore.d.ts.map +1 -0
  44. package/dist/core/SubscriptionAccountMetaReplicatedStore.js +263 -0
  45. package/dist/core/SubscriptionAccountMetaReplicatedStore.js.map +1 -0
  46. package/dist/core/SubscriptionPool.d.ts +23 -5
  47. package/dist/core/SubscriptionPool.d.ts.map +1 -1
  48. package/dist/core/SubscriptionPool.js +30 -6
  49. package/dist/core/SubscriptionPool.js.map +1 -1
  50. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  51. package/dist/core/devGatedFeatures.js +12 -0
  52. package/dist/core/devGatedFeatures.js.map +1 -1
  53. package/dist/core/types.d.ts +29 -0
  54. package/dist/core/types.d.ts.map +1 -1
  55. package/dist/core/types.js.map +1 -1
  56. package/dist/monitoring/AutonomousProgressHeartbeat.d.ts +169 -0
  57. package/dist/monitoring/AutonomousProgressHeartbeat.d.ts.map +1 -0
  58. package/dist/monitoring/AutonomousProgressHeartbeat.js +296 -0
  59. package/dist/monitoring/AutonomousProgressHeartbeat.js.map +1 -0
  60. package/dist/monitoring/ProxyCoordinator.d.ts +1 -1
  61. package/dist/monitoring/ProxyCoordinator.d.ts.map +1 -1
  62. package/dist/monitoring/autonomousHeartbeatScrub.d.ts +44 -0
  63. package/dist/monitoring/autonomousHeartbeatScrub.d.ts.map +1 -0
  64. package/dist/monitoring/autonomousHeartbeatScrub.js +81 -0
  65. package/dist/monitoring/autonomousHeartbeatScrub.js.map +1 -0
  66. package/dist/monitoring/sentinelWiring.d.ts +14 -0
  67. package/dist/monitoring/sentinelWiring.d.ts.map +1 -1
  68. package/dist/monitoring/sentinelWiring.js +19 -0
  69. package/dist/monitoring/sentinelWiring.js.map +1 -1
  70. package/dist/scaffold/templates.d.ts.map +1 -1
  71. package/dist/scaffold/templates.js +10 -0
  72. package/dist/scaffold/templates.js.map +1 -1
  73. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  74. package/dist/server/CapabilityIndex.js +9 -0
  75. package/dist/server/CapabilityIndex.js.map +1 -1
  76. package/dist/server/routes.d.ts.map +1 -1
  77. package/dist/server/routes.js +15 -0
  78. package/dist/server/routes.js.map +1 -1
  79. package/package.json +1 -1
  80. package/src/data/builtin-manifest.json +63 -63
  81. package/src/scaffold/templates.ts +10 -0
  82. package/upgrades/1.3.606.md +28 -0
  83. package/upgrades/1.3.607.md +25 -0
  84. package/upgrades/side-effects/autonomous-progress-heartbeat-ratchet-fix.md +36 -0
  85. package/upgrades/side-effects/autonomous-progress-heartbeat.md +40 -0
  86. package/upgrades/side-effects/ws52-account-follow-me-pr1.md +74 -0
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAoCH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAS3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AAwBjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAkH7D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAsBtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AAyID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAg4CD,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,GACpD,IAAI,CA8eN;AA2lBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAo4dtE;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"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAoCH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAS3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AAwBjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAkH7D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAsBtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AAyID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAg4CD,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,GACpD,IAAI,CA8eN;AA2lBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA6ietE;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"}
@@ -3440,6 +3440,17 @@ export async function startServer(options) {
3440
3440
  // verification-failed propagates as a tombstone (ThreadlinePairingReplicatedStore).
3441
3441
  const { THREADLINE_PAIRING_KIND_REGISTRATION } = await import('../core/ThreadlinePairingReplicatedStore.js');
3442
3442
  replicatedKindRegistry.register(THREADLINE_PAIRING_KIND_REGISTRATION);
3443
+ // WS5.2 Account Follow-Me §6.1a — register the `subscription-account-meta` kind onto the
3444
+ // registry: registry follow-me = METADATA ONLY (a redacted, credential-free projection of a
3445
+ // SubscriptionAccount; configHome + every credential field STRIPPED). Dual-registry's dynamic
3446
+ // half (the static half is CoherenceJournal.JOURNAL_KINDS, which now lists
3447
+ // 'subscription-account-meta'). Registration is INERT — emission/serve/pull stay gated behind
3448
+ // `multiMachine.accountFollowMe.enabled` (default false ⇒ strict no-op, NO account metadata
3449
+ // crosses a machine boundary). The recordKey is the account id (charset-clamped). This kind
3450
+ // carries NO login: the credential half is the SEPARATE account-credential-share verb +
3451
+ // re-mint-per-machine default (Mechanism B); see ws52-account-follow-me-security.md.
3452
+ const { SUBSCRIPTION_ACCOUNT_META_KIND_REGISTRATION } = await import('../core/SubscriptionAccountMetaReplicatedStore.js');
3453
+ replicatedKindRegistry.register(SUBSCRIPTION_ACCOUNT_META_KIND_REGISTRATION);
3443
3454
  // ── WS2 SEND-SIDE wiring (docs/specs/WS2-SEND-SIDE-EMISSION-SPEC.md). The
3444
3455
  // substrate above ships the registry + receive/serve machinery + advert; THIS
3445
3456
  // wires the SEND half that was deferred ("the journal-backed emitter is attached
@@ -3542,7 +3553,17 @@ export async function startServer(options) {
3542
3553
  // `enabled` is already the resolved boolean — the funnels keep their unchanged
3543
3554
  // `enabled === true` semantics but now see a live flag on a dev agent. An explicit
3544
3555
  // operator `enabled` in config still wins (force-dark false / fleet-flip true).
3545
- const _stateSyncStoresResolved = resolveStateSyncStores(config);
3556
+ const _stateSyncStoresBase = resolveStateSyncStores(config);
3557
+ // WS5.2 §6.1a — the `subscriptionAccountMeta` store gates on `multiMachine.accountFollowMe`
3558
+ // (NOT a `stateSync.*` flag). Inject its dev-gate-resolved enabled-state into the SAME
3559
+ // store-flags map the generic emitter + receive-advert consult, so account-meta emission +
3560
+ // the receive capability gate on accountFollowMe (dev-live / fleet-dark) coherently. When the
3561
+ // gate resolves OFF the entry is absent ⇒ the emitter's `enabled===true` check fails ⇒ strict
3562
+ // no-op (no account metadata ever crosses), exactly like the dark stateSync stores.
3563
+ const _accountFollowMeEnabled = resolveDevAgentGate(config.multiMachine?.accountFollowMe?.enabled, config);
3564
+ const _stateSyncStoresResolved = _accountFollowMeEnabled
3565
+ ? { ...(_stateSyncStoresBase ?? {}), subscriptionAccountMeta: { enabled: true } }
3566
+ : _stateSyncStoresBase;
3546
3567
  // WS2 send-side: the generic journal-backed record emitter (the concrete emitter
3547
3568
  // the per-store managers' emit hooks call). Needs the journal sink, the HLC clock,
3548
3569
  // the registry (store → kind), this machine's origin id, the resolved stateSync
@@ -8841,6 +8862,11 @@ export async function startServer(options) {
8841
8862
  let socketRecoveryActive;
8842
8863
  let silenceRecoveryActive;
8843
8864
  let wedgeRecoveryActive;
8865
+ // Lifted out of the trio block so AutonomousProgressHeartbeat (wired later,
8866
+ // near PromiseBeacon) can read ActiveWorkSilenceSentinel's ALREADY-COMPUTED
8867
+ // lastOutputAt snapshot (predicate #8 — a shared/cached read, never its own
8868
+ // tmux capture). undefined when the silence sentinel is disabled.
8869
+ let sharedOutputTracker;
8844
8870
  {
8845
8871
  const { SocketDisconnectSentinel } = await import('../monitoring/SocketDisconnectSentinel.js');
8846
8872
  const { ActiveWorkSilenceSentinel } = await import('../monitoring/ActiveWorkSilenceSentinel.js');
@@ -8894,6 +8920,9 @@ export async function startServer(options) {
8894
8920
  const silenceCfg = config.monitoring?.activeWorkSilenceSentinel ?? { enabled: true };
8895
8921
  if (silenceCfg.enabled !== false) {
8896
8922
  const tracker = new OutputActivityTracker(sessionSurface);
8923
+ // Share this tracker's snapshot with AutonomousProgressHeartbeat
8924
+ // (predicate #8 reads its lastOutputAt — never its own capture).
8925
+ sharedOutputTracker = tracker;
8897
8926
  // Auto-heal ladder (DARK, off by default): when a confirmed-silent session
8898
8927
  // can't be nudged back, respawn it fresh (conversation preserved via
8899
8928
  // --resume) instead of only asking the user. Gated by autoRecover; the
@@ -9220,6 +9249,20 @@ export async function startServer(options) {
9220
9249
  if (subscriptionPool.size() > 0) {
9221
9250
  console.log(pc.green(` Subscription pool: ${subscriptionPool.size()} account(s) registered`));
9222
9251
  }
9252
+ // WS5.2 §6.1a — wire cross-machine registry follow-me (METADATA ONLY). When the generic
9253
+ // record emitter exists AND accountFollowMe resolves enabled (the entry was injected into
9254
+ // _stateSyncStoresResolved above), attach the emit adapter so an account add/status/quota
9255
+ // change/remove replicates a REDACTED projection (projectAccountToMeta strips configHome +
9256
+ // every credential field by allowlist). The emitter itself re-checks the store-flag gate, so
9257
+ // a dark/fleet agent is a strict no-op even if the adapter is attached. NO login crosses.
9258
+ if (replicatedRecordEmitter && _accountFollowMeEnabled) {
9259
+ const emitter = replicatedRecordEmitter;
9260
+ const { SUBSCRIPTION_ACCOUNT_META_STORE_KEY, deriveSubscriptionAccountMetaRecordKey, buildSubscriptionAccountMetaData, buildSubscriptionAccountMetaTombstoneData, } = await import('../core/SubscriptionAccountMetaReplicatedStore.js');
9261
+ subscriptionPool.setMetaReplicationEmitter({
9262
+ emitPut: (acct) => emitter.emit(SUBSCRIPTION_ACCOUNT_META_STORE_KEY, deriveSubscriptionAccountMetaRecordKey(acct.id), (hlc, origin, observed) => buildSubscriptionAccountMetaData({ account: acct, hlc, origin, observed })),
9263
+ emitDelete: (accountId, deletedAt) => emitter.emit(SUBSCRIPTION_ACCOUNT_META_STORE_KEY, deriveSubscriptionAccountMetaRecordKey(accountId), (hlc, origin, observed) => buildSubscriptionAccountMetaTombstoneData({ accountId, hlc, origin, deletedAt, observed })),
9264
+ });
9265
+ }
9223
9266
  // POOL-AWARE QUOTA THROTTLE wiring (docs/specs/POOL-AWARE-QUOTA-THROTTLE-SPEC.md):
9224
9267
  // give the global quota brake the SAME placeability predicate the placement layer
9225
9268
  // (selectAccount) uses, reading the LIVE SubscriptionPool. Effect: the brake never
@@ -10404,6 +10447,102 @@ export async function startServer(options) {
10404
10447
  });
10405
10448
  promiseBeacon.start();
10406
10449
  globalThis.__instarPromiseBeacon = promiseBeacon;
10450
+ // ── AutonomousProgressHeartbeat ──────────────────────────────────
10451
+ // Hedged, change-gated, sparse liveness BACKSTOP for an autonomous run
10452
+ // gone silent-to-user while its terminal output is STILL changing. NOT
10453
+ // the suppressed PromiseBeacon §B1 filler — much higher bar (long
10454
+ // user-silence gate + corroborated recent output change from
10455
+ // ActiveWorkSilenceSentinel's shared snapshot + per-topic cooldown +
10456
+ // widening per-run backoff + hard cap + the shared one-voice lease).
10457
+ // DEV-GATED dark: enabled via resolveDevAgentGate (LIVE on a dev agent,
10458
+ // DARK on the fleet); dryRun defaults true (would-emit log, no send).
10459
+ // Spec: docs/specs/autonomous-progress-heartbeat.md.
10460
+ try {
10461
+ const ahRawCfg = config.monitoring?.autonomousHeartbeat ?? {};
10462
+ const ahEnabled = resolveDevAgentGate(ahRawCfg.enabled, config);
10463
+ if (ahEnabled && telegram) {
10464
+ const { AutonomousProgressHeartbeat } = await import('../monitoring/AutonomousProgressHeartbeat.js');
10465
+ const { activeAutonomousJobs, autonomousRunRemainingForTopic, readAutonomousRunMarkers, } = await import('../core/AutonomousSessions.js');
10466
+ const { ParallelActivityIndex: AHParallelActivityIndex } = await import('../core/ParallelActivityIndex.js');
10467
+ // Own ParallelActivityIndex (focus source) — fetched ONCE per tick
10468
+ // and indexed by topic inside the deps closure.
10469
+ const ahActivityIndex = new AHParallelActivityIndex({ stateDir: config.stateDir });
10470
+ const localTelegram2 = telegram;
10471
+ const autonomousHeartbeat = new AutonomousProgressHeartbeat({
10472
+ listActiveAutonomousRuns: () => {
10473
+ const out = [];
10474
+ const now = Date.now();
10475
+ for (const job of activeAutonomousJobs(config.stateDir)) {
10476
+ if (job.topic == null)
10477
+ continue; // legacy single-file job has no topic
10478
+ const remaining = autonomousRunRemainingForTopic(config.stateDir, job.topic, now);
10479
+ if (!remaining)
10480
+ continue;
10481
+ const topicId = Number(job.topic);
10482
+ if (!Number.isFinite(topicId))
10483
+ continue;
10484
+ out.push({
10485
+ topicId,
10486
+ sessionName: localTelegram2.getSessionForTopic(topicId) ?? null,
10487
+ remainingSeconds: remaining.remainingSeconds,
10488
+ });
10489
+ }
10490
+ return out;
10491
+ },
10492
+ getRunMarkers: (topicId) => readAutonomousRunMarkers(config.stateDir, topicId),
10493
+ isSessionAlive: (name) => sessionManager.isSessionAlive(name),
10494
+ getTopicHistory: (topicId) => localTelegram2.getTopicHistory(topicId, 50).map((e) => ({
10495
+ fromUser: e.fromUser,
10496
+ at: new Date(e.timestamp).getTime(),
10497
+ })),
10498
+ // Predicate #8 — read ActiveWorkSilenceSentinel's ALREADY-computed
10499
+ // snapshot (the shared OutputActivityTracker). NEVER a capture.
10500
+ // undefined when the silence sentinel is disabled → fails closed.
10501
+ getSharedLastOutputAt: (name) => sharedOutputTracker ? sharedOutputTracker.lastOutputAtFor(name) : null,
10502
+ getFocusForTopic: (() => {
10503
+ // Index the cross-topic activities ONCE per tick (O(1)/topic).
10504
+ let cachedAt = 0;
10505
+ let cache = new Map();
10506
+ return (topicId) => {
10507
+ const now = Date.now();
10508
+ if (now - cachedAt > 5_000) {
10509
+ cache = new Map(ahActivityIndex.activities(now).map((a) => [a.topicId, a.focus]));
10510
+ cachedAt = now;
10511
+ }
10512
+ return cache.get(topicId) ?? null;
10513
+ };
10514
+ })(),
10515
+ proxyCoordinator,
10516
+ sendMessage: async (topicId, text, metadata) => {
10517
+ const url = `http://localhost:${config.port}/telegram/reply/${topicId}`;
10518
+ const response = await fetch(url, {
10519
+ method: 'POST',
10520
+ headers: {
10521
+ 'Content-Type': 'application/json',
10522
+ 'Authorization': `Bearer ${config.authToken}`,
10523
+ },
10524
+ body: JSON.stringify({ text, metadata }),
10525
+ });
10526
+ if (!response.ok)
10527
+ throw new Error(`Autonomous-heartbeat reply failed: ${response.status}`);
10528
+ },
10529
+ }, {
10530
+ enabled: true, // gate already resolved above
10531
+ dryRun: ahRawCfg.dryRun !== false,
10532
+ silenceThresholdMinutes: ahRawCfg.silenceThresholdMinutes,
10533
+ tickIntervalMs: ahRawCfg.tickIntervalMs,
10534
+ maxHeartbeatsPerRun: ahRawCfg.maxHeartbeatsPerRun,
10535
+ recentOutputChangeWindowMs: ahRawCfg.recentOutputChangeWindowMs,
10536
+ });
10537
+ autonomousHeartbeat.start();
10538
+ globalThis.__instarAutonomousHeartbeat = autonomousHeartbeat;
10539
+ guardRegistry.register('monitoring.autonomousHeartbeat.enabled', () => autonomousHeartbeat.guardStatus());
10540
+ console.log(pc.green(` AutonomousProgressHeartbeat enabled (silence backstop — ${(ahRawCfg.dryRun !== false) ? 'dry-run observe-only' : 'LIVE'})`));
10541
+ }
10542
+ }
10543
+ catch (err) {
10544
+ console.warn('[AutonomousProgressHeartbeat] init failed (non-fatal):', err.message);
10545
+ }
10407
10546
  // ── "keep watching" resume detector ─────────────────────────────
10408
10547
  // When a user replies on a topic that has any auto-paused beacons,
10409
10548
  // a literal "keep watching" match resumes them. Brittle detector