instar 1.3.1319 → 1.3.1321

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 (110) hide show
  1. package/dist/commands/machine.d.ts +20 -0
  2. package/dist/commands/machine.d.ts.map +1 -1
  3. package/dist/commands/machine.js +135 -21
  4. package/dist/commands/machine.js.map +1 -1
  5. package/dist/commands/server.d.ts.map +1 -1
  6. package/dist/commands/server.js +86 -5
  7. package/dist/commands/server.js.map +1 -1
  8. package/dist/commands/setup.d.ts +6 -0
  9. package/dist/commands/setup.d.ts.map +1 -1
  10. package/dist/commands/setup.js +8 -0
  11. package/dist/commands/setup.js.map +1 -1
  12. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  13. package/dist/config/ConfigDefaults.js +6 -0
  14. package/dist/config/ConfigDefaults.js.map +1 -1
  15. package/dist/core/Config.d.ts +12 -0
  16. package/dist/core/Config.d.ts.map +1 -1
  17. package/dist/core/Config.js +38 -1
  18. package/dist/core/Config.js.map +1 -1
  19. package/dist/core/JevReviewFlagShadow.d.ts +161 -0
  20. package/dist/core/JevReviewFlagShadow.d.ts.map +1 -0
  21. package/dist/core/JevReviewFlagShadow.js +456 -0
  22. package/dist/core/JevReviewFlagShadow.js.map +1 -0
  23. package/dist/core/MachineIdentity.d.ts +10 -0
  24. package/dist/core/MachineIdentity.d.ts.map +1 -1
  25. package/dist/core/MachineIdentity.js +15 -4
  26. package/dist/core/MachineIdentity.js.map +1 -1
  27. package/dist/core/PostUpdateMigrator.d.ts +8 -0
  28. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  29. package/dist/core/PostUpdateMigrator.js +138 -3
  30. package/dist/core/PostUpdateMigrator.js.map +1 -1
  31. package/dist/core/SubscriptionPool.d.ts +30 -0
  32. package/dist/core/SubscriptionPool.d.ts.map +1 -1
  33. package/dist/core/SubscriptionPool.js +52 -1
  34. package/dist/core/SubscriptionPool.js.map +1 -1
  35. package/dist/core/SubscriptionPoolAuthority.d.ts +33 -0
  36. package/dist/core/SubscriptionPoolAuthority.d.ts.map +1 -1
  37. package/dist/core/SubscriptionPoolAuthority.js +150 -0
  38. package/dist/core/SubscriptionPoolAuthority.js.map +1 -1
  39. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  40. package/dist/core/devGatedFeatures.js +6 -0
  41. package/dist/core/devGatedFeatures.js.map +1 -1
  42. package/dist/core/shutdownDeadline.d.ts +26 -0
  43. package/dist/core/shutdownDeadline.d.ts.map +1 -0
  44. package/dist/core/shutdownDeadline.js +25 -0
  45. package/dist/core/shutdownDeadline.js.map +1 -0
  46. package/dist/core/types.d.ts +18 -0
  47. package/dist/core/types.d.ts.map +1 -1
  48. package/dist/core/types.js.map +1 -1
  49. package/dist/data/standards-guard-index.json +1 -1
  50. package/dist/data/standards-guard-index.meta.json +2 -2
  51. package/dist/data/standards-registry.meta.json +1 -1
  52. package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
  53. package/dist/messaging/TelegramAdapter.js +12 -1
  54. package/dist/messaging/TelegramAdapter.js.map +1 -1
  55. package/dist/monitoring/CodexRolloutScan.worker.d.ts +16 -0
  56. package/dist/monitoring/CodexRolloutScan.worker.d.ts.map +1 -0
  57. package/dist/monitoring/CodexRolloutScan.worker.js +49 -0
  58. package/dist/monitoring/CodexRolloutScan.worker.js.map +1 -0
  59. package/dist/monitoring/QuotaCollector.d.ts +8 -0
  60. package/dist/monitoring/QuotaCollector.d.ts.map +1 -1
  61. package/dist/monitoring/QuotaCollector.js +73 -32
  62. package/dist/monitoring/QuotaCollector.js.map +1 -1
  63. package/dist/monitoring/TokenLedger.d.ts +11 -1
  64. package/dist/monitoring/TokenLedger.d.ts.map +1 -1
  65. package/dist/monitoring/TokenLedger.js +79 -37
  66. package/dist/monitoring/TokenLedger.js.map +1 -1
  67. package/dist/scaffold/templates.d.ts +4 -0
  68. package/dist/scaffold/templates.d.ts.map +1 -1
  69. package/dist/scaffold/templates.js +17 -4
  70. package/dist/scaffold/templates.js.map +1 -1
  71. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  72. package/dist/server/CapabilityIndex.js +1 -0
  73. package/dist/server/CapabilityIndex.js.map +1 -1
  74. package/dist/server/machineRoutes.d.ts.map +1 -1
  75. package/dist/server/machineRoutes.js +16 -0
  76. package/dist/server/machineRoutes.js.map +1 -1
  77. package/dist/server/routes.d.ts.map +1 -1
  78. package/dist/server/routes.js +16 -3
  79. package/dist/server/routes.js.map +1 -1
  80. package/dist/threadline/ThreadlineBootstrap.d.ts +9 -0
  81. package/dist/threadline/ThreadlineBootstrap.d.ts.map +1 -1
  82. package/dist/threadline/ThreadlineBootstrap.js +5 -1
  83. package/dist/threadline/ThreadlineBootstrap.js.map +1 -1
  84. package/dist/threadline/client/ThreadlineClient.d.ts +14 -0
  85. package/dist/threadline/client/ThreadlineClient.d.ts.map +1 -1
  86. package/dist/threadline/client/ThreadlineClient.js +18 -0
  87. package/dist/threadline/client/ThreadlineClient.js.map +1 -1
  88. package/package.json +1 -1
  89. package/src/data/builtin-manifest.json +64 -64
  90. package/src/data/standards-guard-index.json +1 -1
  91. package/src/data/standards-guard-index.meta.json +2 -2
  92. package/src/data/standards-registry.meta.json +1 -1
  93. package/src/scaffold/templates.ts +18 -4
  94. package/upgrades/1.3.1320.md +47 -0
  95. package/upgrades/1.3.1321.md +153 -0
  96. package/upgrades/luna-stack-ci-ratchets.eli16.md +9 -0
  97. package/upgrades/side-effects/agent-health-reopen-duplicate.md +58 -0
  98. package/upgrades/side-effects/auth-read-after-secret-migration.md +56 -0
  99. package/upgrades/side-effects/codex-rollout-scan-yield.md +58 -0
  100. package/upgrades/side-effects/jev-review-flag-shadow.md +175 -0
  101. package/upgrades/side-effects/join-autostart-lifeline.md +59 -0
  102. package/upgrades/side-effects/join-refuses-copied-identity.md +62 -0
  103. package/upgrades/side-effects/luna-stack-ci-ratchets.md +24 -0
  104. package/upgrades/side-effects/quota-jsonl-off-event-loop.md +54 -0
  105. package/upgrades/side-effects/second-machine-copied-config.md +62 -0
  106. package/upgrades/side-effects/shutdown-hard-deadline.md +62 -0
  107. package/upgrades/side-effects/subscription-pool-legacy-migrate.md +68 -0
  108. package/upgrades/side-effects/threadline-relay-standby.md +54 -0
  109. package/upgrades/side-effects/threadline-wire-thread-id.md +60 -0
  110. package/upgrades/side-effects/wakeup-targets-awake-machine.md +58 -0
@@ -256,6 +256,7 @@ import { loadTestIdentityKey } from '../users/testIdentityMarkers.js';
256
256
  import { formatUserContextForSession, hasUserContext } from '../users/UserContextBuilder.js';
257
257
  import { SafeFsExecutor } from '../core/SafeFsExecutor.js';
258
258
  import { mergeDefaults } from '../core/mergeDefaults.js';
259
+ import { shouldOwnTelegramPoll } from '../lifeline/telegramPollOwnership.js';
259
260
  // setup.ts uses @inquirer/prompts which requires Node 20.12+
260
261
  // Dynamic import to avoid breaking the server on older Node versions
261
262
  // import { installAutoStart } from './setup.js';
@@ -16951,6 +16952,10 @@ export async function startServer(options) {
16951
16952
  projectDir: config.projectDir,
16952
16953
  port: config.port,
16953
16954
  relayEnabled: config.threadline?.relayEnabled,
16955
+ // A quiet standby never connects to the relay: the relay admits one
16956
+ // connection per agent identity, and two machines displaced each other
16957
+ // (instar#2122). Same per-machine flag the lifeline uses for the poll.
16958
+ relayStandby: !shouldOwnTelegramPoll(config),
16954
16959
  relayUrl: config.threadline?.relayUrl,
16955
16960
  visibility: config.threadline?.visibility,
16956
16961
  capabilities: config.threadline?.capabilities,
@@ -17397,6 +17402,28 @@ export async function startServer(options) {
17397
17402
  catch (err) {
17398
17403
  console.log(pc.yellow(` Jev circles shadow: not constructed (${err?.message ?? 'unknown'})`));
17399
17404
  }
17405
+ // Jev review-flag shadow (docs/specs/jev-review-flag-shadow.md) — log-only,
17406
+ // delivers nothing. A 60 s unref'd timer tails the Telegram history; dev-gated
17407
+ // (live on a development agent, dark on the fleet), read live per tick, inert
17408
+ // without the vault typesafe_api_key.
17409
+ try {
17410
+ const { buildJevReviewFlagShadow, installJevReviewFlagShadow } = await import('../core/JevReviewFlagShadow.js');
17411
+ const { getFeatureMetricsRecorder } = await import('../core/CircuitBreakingIntelligenceProvider.js');
17412
+ const { SecretStore } = await import('../core/SecretStore.js');
17413
+ const shadow = buildJevReviewFlagShadow({
17414
+ readLiveIntelligence: () => liveConfig.get('intelligence', undefined),
17415
+ bootBlock: config.intelligence?.jevReviewFlagShadow,
17416
+ developmentAgent: config.developmentAgent === true,
17417
+ readSecret: (name) => new SecretStore({ stateDir: config.stateDir, forceFileKey: config.secrets?.forceFileKey }).get(name),
17418
+ stateDir: config.stateDir,
17419
+ metrics: { record: (r) => getFeatureMetricsRecorder()?.record(r) },
17420
+ });
17421
+ installJevReviewFlagShadow(shadow);
17422
+ shadow.start();
17423
+ }
17424
+ catch (err) {
17425
+ console.log(pc.yellow(` Jev review-flag shadow: not constructed (${err?.message ?? 'unknown'})`));
17426
+ }
17400
17427
  // Outbound dedup gate — deterministic near-duplicate detection on every
17401
17428
  // outbound agent message. Catches respawn races and idempotency gaps.
17402
17429
  const { OutboundDedupGate } = await import('../core/OutboundDedupGate.js');
@@ -22751,7 +22778,7 @@ export async function startServer(options) {
22751
22778
  } };
22752
22779
  originRuntime.poolAudit = new OriginPoolAudit({
22753
22780
  operatorScopeRequired: true,
22754
- shardIds: () => [meshSelfId, ...Object.keys(meshIdMgr.loadRegistry().machines)],
22781
+ shardIds: () => [meshSelfId, ...meshIdMgr.getActiveMachines().map(m => m.machineId).filter(id => id !== meshSelfId)],
22755
22782
  readShardMetrics: async (machineId) => {
22756
22783
  if (machineId === meshSelfId)
22757
22784
  return originRuntime.store.getFederatedMetrics(machineId);
@@ -27410,7 +27437,8 @@ export async function startServer(options) {
27410
27437
  // If autostart isn't installed, install it silently. If it uses the old /bin/bash entry point
27411
27438
  // (vulnerable to macOS TCC/FDA restrictions), regenerate it with the node + JS wrapper.
27412
27439
  try {
27413
- const hasTelegram = !!telegram;
27440
+ const hasTelegramConfigured = (config.messaging ?? []).some((m) => m.type === 'telegram' && m.enabled !== false);
27441
+ let hasTelegramForInstall = false;
27414
27442
  const autostartInstalled = isAutostartInstalled(config.projectName);
27415
27443
  let needsReinstall = !autostartInstalled;
27416
27444
  // On macOS, keep node symlink fresh and check plist format
@@ -27422,6 +27450,7 @@ export async function startServer(options) {
27422
27450
  }
27423
27451
  catch { /* non-critical */ }
27424
27452
  if (!needsReinstall) {
27453
+ const { autoStartNeedsLifeline } = await import('./setup.js');
27425
27454
  const label = `ai.instar.${config.projectName}`;
27426
27455
  const plistPath = path.join(os.homedir(), 'Library', 'LaunchAgents', `${label}.plist`);
27427
27456
  try {
@@ -27436,6 +27465,15 @@ export async function startServer(options) {
27436
27465
  needsReinstall = true;
27437
27466
  console.log(pc.yellow(` Auto-start uses legacy format — upgrading to TCC-safe node entry point`));
27438
27467
  }
27468
+ else if (autoStartNeedsLifeline(plistContent, hasTelegramConfigured)) {
27469
+ // A joined standby is installed with `server start` (it has no
27470
+ // Telegram config at join time, and the lifeline needs one).
27471
+ // Once Telegram is configured, the lifeline must supervise the
27472
+ // server as it does on the first machine (instar#2122).
27473
+ needsReinstall = true;
27474
+ hasTelegramForInstall = true;
27475
+ console.log(pc.yellow(` Auto-start runs the bare server although Telegram is configured — switching to the lifeline supervisor`));
27476
+ }
27439
27477
  else if (!plistContent.includes('.instar/bin/node')) {
27440
27478
  needsReinstall = true;
27441
27479
  console.log(pc.yellow(` Auto-start uses direct node path — upgrading to stable symlink`));
@@ -27456,7 +27494,7 @@ export async function startServer(options) {
27456
27494
  }
27457
27495
  if (needsReinstall) {
27458
27496
  const { installAutoStart } = await import('./setup.js');
27459
- const installed = installAutoStart(config.projectName, config.projectDir, hasTelegram);
27497
+ const installed = installAutoStart(config.projectName, config.projectDir, !!telegram || hasTelegramForInstall);
27460
27498
  if (installed) {
27461
27499
  console.log(pc.green(` Auto-start self-healed: installed ${process.platform === 'darwin' ? 'LaunchAgent (node + JS wrapper)' : 'systemd service'}`));
27462
27500
  }
@@ -27491,13 +27529,50 @@ export async function startServer(options) {
27491
27529
  }
27492
27530
  // Graceful shutdown
27493
27531
  let _shuttingDown = false;
27532
+ let shutdownStep = 'start';
27494
27533
  const shutdown = async () => {
27495
27534
  // Re-entrancy guard: SIGINT+SIGTERM (or a restartDetected racing a signal)
27496
27535
  // must not run the teardown twice. closeAllSqlite() is itself idempotent,
27497
27536
  // but the resume-UUID save + sidecar flush should run once.
27498
- if (_shuttingDown)
27499
- return;
27537
+ if (_shuttingDown) {
27538
+ // A second signal while teardown is in flight means the operator (or
27539
+ // launchd) wants the process gone now: exit at once rather than wait on
27540
+ // whichever step is hanging (instar#2122: a standby that ignored SIGTERM).
27541
+ console.error(`[shutdown] second signal during step "${shutdownStep}" — exiting now`);
27542
+ try {
27543
+ closeAllSqlite();
27544
+ }
27545
+ catch { /* best effort */ }
27546
+ try {
27547
+ singleInstanceLock.release();
27548
+ }
27549
+ catch { /* best effort */ }
27550
+ process.exit(1);
27551
+ }
27500
27552
  _shuttingDown = true;
27553
+ // Hard deadline: the teardown below awaits many subsystems in sequence and
27554
+ // any one of them (an origin worker, a tunnel, a Threadline relay, a server
27555
+ // with an open long-poll) can hang; without a bound the process never
27556
+ // exits and only SIGKILL stops it. launchd/the lifeline expect SIGTERM to
27557
+ // work. The timer is unref'd so a fast teardown is never delayed by it.
27558
+ const { armShutdownDeadline, resolveShutdownDeadlineMs } = await import('../core/shutdownDeadline.js');
27559
+ armShutdownDeadline({
27560
+ deadlineMs: resolveShutdownDeadlineMs(process.env.INSTAR_SHUTDOWN_DEADLINE_MS),
27561
+ currentStep: () => shutdownStep,
27562
+ onExpire: (step, deadlineMs) => {
27563
+ console.error(`[shutdown] teardown exceeded ${deadlineMs}ms during step "${step}" — exiting now`);
27564
+ try {
27565
+ closeAllSqlite();
27566
+ }
27567
+ catch { /* best effort */ }
27568
+ try {
27569
+ singleInstanceLock.release();
27570
+ }
27571
+ catch { /* best effort */ }
27572
+ process.exit(1);
27573
+ },
27574
+ });
27575
+ shutdownStep = 'telegram-origin';
27501
27576
  try {
27502
27577
  await telegramOriginBoot?.close();
27503
27578
  }
@@ -27578,6 +27653,7 @@ export async function startServer(options) {
27578
27653
  coherenceMonitor.stop();
27579
27654
  commitmentTracker.stop();
27580
27655
  commitmentSentinel?.stop();
27656
+ shutdownStep = 'notification-flush';
27581
27657
  await notificationBatcher.flushAll(); // Drain pending notifications before exit
27582
27658
  notificationBatcher.stop();
27583
27659
  retryManager.stop();
@@ -27597,8 +27673,10 @@ export async function startServer(options) {
27597
27673
  autoUpdater.stop();
27598
27674
  autoDispatcher?.stop();
27599
27675
  sessionMonitor?.stop();
27676
+ shutdownStep = 'tunnel';
27600
27677
  if (tunnel)
27601
27678
  await tunnel.stop();
27679
+ shutdownStep = 'threadline';
27602
27680
  if (threadlineShutdown)
27603
27681
  await threadlineShutdown();
27604
27682
  wakeSocketServer?.stop();
@@ -27621,6 +27699,7 @@ export async function startServer(options) {
27621
27699
  }
27622
27700
  catch { /* ELOCKED is non-critical during shutdown */ }
27623
27701
  scheduler?.stop();
27702
+ shutdownStep = 'telegram';
27624
27703
  if (telegram)
27625
27704
  await telegram.stop();
27626
27705
  sessionManager.stopMonitoring();
@@ -27631,7 +27710,9 @@ export async function startServer(options) {
27631
27710
  sharedStateLedger?.shutdown();
27632
27711
  }
27633
27712
  catch { /* best effort */ }
27713
+ shutdownStep = 'http-server';
27634
27714
  await server.stop();
27715
+ shutdownStep = 'sqlite';
27635
27716
  // Close EVERY registered SQLite handle LAST — after all writers (server,
27636
27717
  // scheduler, sentinels, telegram) have stopped — to prevent the
27637
27718
  // "mutex lock failed" SIGABRT when better-sqlite3 static destructors fire