instar 1.3.1320 → 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 (91) 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 +64 -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/core/Config.d.ts +12 -0
  13. package/dist/core/Config.d.ts.map +1 -1
  14. package/dist/core/Config.js +38 -1
  15. package/dist/core/Config.js.map +1 -1
  16. package/dist/core/MachineIdentity.d.ts +10 -0
  17. package/dist/core/MachineIdentity.d.ts.map +1 -1
  18. package/dist/core/MachineIdentity.js +15 -4
  19. package/dist/core/MachineIdentity.js.map +1 -1
  20. package/dist/core/PostUpdateMigrator.d.ts +8 -0
  21. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  22. package/dist/core/PostUpdateMigrator.js +129 -2
  23. package/dist/core/PostUpdateMigrator.js.map +1 -1
  24. package/dist/core/SubscriptionPool.d.ts +30 -0
  25. package/dist/core/SubscriptionPool.d.ts.map +1 -1
  26. package/dist/core/SubscriptionPool.js +52 -1
  27. package/dist/core/SubscriptionPool.js.map +1 -1
  28. package/dist/core/SubscriptionPoolAuthority.d.ts +33 -0
  29. package/dist/core/SubscriptionPoolAuthority.d.ts.map +1 -1
  30. package/dist/core/SubscriptionPoolAuthority.js +150 -0
  31. package/dist/core/SubscriptionPoolAuthority.js.map +1 -1
  32. package/dist/core/shutdownDeadline.d.ts +26 -0
  33. package/dist/core/shutdownDeadline.d.ts.map +1 -0
  34. package/dist/core/shutdownDeadline.js +25 -0
  35. package/dist/core/shutdownDeadline.js.map +1 -0
  36. package/dist/data/standards-guard-index.json +1 -1
  37. package/dist/data/standards-guard-index.meta.json +2 -2
  38. package/dist/data/standards-registry.meta.json +1 -1
  39. package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
  40. package/dist/messaging/TelegramAdapter.js +12 -1
  41. package/dist/messaging/TelegramAdapter.js.map +1 -1
  42. package/dist/monitoring/CodexRolloutScan.worker.d.ts +16 -0
  43. package/dist/monitoring/CodexRolloutScan.worker.d.ts.map +1 -0
  44. package/dist/monitoring/CodexRolloutScan.worker.js +49 -0
  45. package/dist/monitoring/CodexRolloutScan.worker.js.map +1 -0
  46. package/dist/monitoring/QuotaCollector.d.ts +8 -0
  47. package/dist/monitoring/QuotaCollector.d.ts.map +1 -1
  48. package/dist/monitoring/QuotaCollector.js +73 -32
  49. package/dist/monitoring/QuotaCollector.js.map +1 -1
  50. package/dist/monitoring/TokenLedger.d.ts +11 -1
  51. package/dist/monitoring/TokenLedger.d.ts.map +1 -1
  52. package/dist/monitoring/TokenLedger.js +79 -37
  53. package/dist/monitoring/TokenLedger.js.map +1 -1
  54. package/dist/scaffold/templates.d.ts.map +1 -1
  55. package/dist/scaffold/templates.js +7 -4
  56. package/dist/scaffold/templates.js.map +1 -1
  57. package/dist/server/machineRoutes.d.ts.map +1 -1
  58. package/dist/server/machineRoutes.js +16 -0
  59. package/dist/server/machineRoutes.js.map +1 -1
  60. package/dist/server/routes.d.ts.map +1 -1
  61. package/dist/server/routes.js +4 -3
  62. package/dist/server/routes.js.map +1 -1
  63. package/dist/threadline/ThreadlineBootstrap.d.ts +9 -0
  64. package/dist/threadline/ThreadlineBootstrap.d.ts.map +1 -1
  65. package/dist/threadline/ThreadlineBootstrap.js +5 -1
  66. package/dist/threadline/ThreadlineBootstrap.js.map +1 -1
  67. package/dist/threadline/client/ThreadlineClient.d.ts +14 -0
  68. package/dist/threadline/client/ThreadlineClient.d.ts.map +1 -1
  69. package/dist/threadline/client/ThreadlineClient.js +18 -0
  70. package/dist/threadline/client/ThreadlineClient.js.map +1 -1
  71. package/package.json +1 -1
  72. package/src/data/builtin-manifest.json +64 -64
  73. package/src/data/standards-guard-index.json +1 -1
  74. package/src/data/standards-guard-index.meta.json +2 -2
  75. package/src/data/standards-registry.meta.json +1 -1
  76. package/src/scaffold/templates.ts +7 -4
  77. package/upgrades/1.3.1321.md +153 -0
  78. package/upgrades/luna-stack-ci-ratchets.eli16.md +9 -0
  79. package/upgrades/side-effects/agent-health-reopen-duplicate.md +58 -0
  80. package/upgrades/side-effects/auth-read-after-secret-migration.md +56 -0
  81. package/upgrades/side-effects/codex-rollout-scan-yield.md +58 -0
  82. package/upgrades/side-effects/join-autostart-lifeline.md +59 -0
  83. package/upgrades/side-effects/join-refuses-copied-identity.md +62 -0
  84. package/upgrades/side-effects/luna-stack-ci-ratchets.md +24 -0
  85. package/upgrades/side-effects/quota-jsonl-off-event-loop.md +54 -0
  86. package/upgrades/side-effects/second-machine-copied-config.md +62 -0
  87. package/upgrades/side-effects/shutdown-hard-deadline.md +62 -0
  88. package/upgrades/side-effects/subscription-pool-legacy-migrate.md +68 -0
  89. package/upgrades/side-effects/threadline-relay-standby.md +54 -0
  90. package/upgrades/side-effects/threadline-wire-thread-id.md +60 -0
  91. 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,
@@ -22773,7 +22778,7 @@ export async function startServer(options) {
22773
22778
  } };
22774
22779
  originRuntime.poolAudit = new OriginPoolAudit({
22775
22780
  operatorScopeRequired: true,
22776
- shardIds: () => [meshSelfId, ...Object.keys(meshIdMgr.loadRegistry().machines)],
22781
+ shardIds: () => [meshSelfId, ...meshIdMgr.getActiveMachines().map(m => m.machineId).filter(id => id !== meshSelfId)],
22777
22782
  readShardMetrics: async (machineId) => {
22778
22783
  if (machineId === meshSelfId)
22779
22784
  return originRuntime.store.getFederatedMetrics(machineId);
@@ -27432,7 +27437,8 @@ export async function startServer(options) {
27432
27437
  // If autostart isn't installed, install it silently. If it uses the old /bin/bash entry point
27433
27438
  // (vulnerable to macOS TCC/FDA restrictions), regenerate it with the node + JS wrapper.
27434
27439
  try {
27435
- const hasTelegram = !!telegram;
27440
+ const hasTelegramConfigured = (config.messaging ?? []).some((m) => m.type === 'telegram' && m.enabled !== false);
27441
+ let hasTelegramForInstall = false;
27436
27442
  const autostartInstalled = isAutostartInstalled(config.projectName);
27437
27443
  let needsReinstall = !autostartInstalled;
27438
27444
  // On macOS, keep node symlink fresh and check plist format
@@ -27444,6 +27450,7 @@ export async function startServer(options) {
27444
27450
  }
27445
27451
  catch { /* non-critical */ }
27446
27452
  if (!needsReinstall) {
27453
+ const { autoStartNeedsLifeline } = await import('./setup.js');
27447
27454
  const label = `ai.instar.${config.projectName}`;
27448
27455
  const plistPath = path.join(os.homedir(), 'Library', 'LaunchAgents', `${label}.plist`);
27449
27456
  try {
@@ -27458,6 +27465,15 @@ export async function startServer(options) {
27458
27465
  needsReinstall = true;
27459
27466
  console.log(pc.yellow(` Auto-start uses legacy format — upgrading to TCC-safe node entry point`));
27460
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
+ }
27461
27477
  else if (!plistContent.includes('.instar/bin/node')) {
27462
27478
  needsReinstall = true;
27463
27479
  console.log(pc.yellow(` Auto-start uses direct node path — upgrading to stable symlink`));
@@ -27478,7 +27494,7 @@ export async function startServer(options) {
27478
27494
  }
27479
27495
  if (needsReinstall) {
27480
27496
  const { installAutoStart } = await import('./setup.js');
27481
- const installed = installAutoStart(config.projectName, config.projectDir, hasTelegram);
27497
+ const installed = installAutoStart(config.projectName, config.projectDir, !!telegram || hasTelegramForInstall);
27482
27498
  if (installed) {
27483
27499
  console.log(pc.green(` Auto-start self-healed: installed ${process.platform === 'darwin' ? 'LaunchAgent (node + JS wrapper)' : 'systemd service'}`));
27484
27500
  }
@@ -27513,13 +27529,50 @@ export async function startServer(options) {
27513
27529
  }
27514
27530
  // Graceful shutdown
27515
27531
  let _shuttingDown = false;
27532
+ let shutdownStep = 'start';
27516
27533
  const shutdown = async () => {
27517
27534
  // Re-entrancy guard: SIGINT+SIGTERM (or a restartDetected racing a signal)
27518
27535
  // must not run the teardown twice. closeAllSqlite() is itself idempotent,
27519
27536
  // but the resume-UUID save + sidecar flush should run once.
27520
- if (_shuttingDown)
27521
- 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
+ }
27522
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';
27523
27576
  try {
27524
27577
  await telegramOriginBoot?.close();
27525
27578
  }
@@ -27600,6 +27653,7 @@ export async function startServer(options) {
27600
27653
  coherenceMonitor.stop();
27601
27654
  commitmentTracker.stop();
27602
27655
  commitmentSentinel?.stop();
27656
+ shutdownStep = 'notification-flush';
27603
27657
  await notificationBatcher.flushAll(); // Drain pending notifications before exit
27604
27658
  notificationBatcher.stop();
27605
27659
  retryManager.stop();
@@ -27619,8 +27673,10 @@ export async function startServer(options) {
27619
27673
  autoUpdater.stop();
27620
27674
  autoDispatcher?.stop();
27621
27675
  sessionMonitor?.stop();
27676
+ shutdownStep = 'tunnel';
27622
27677
  if (tunnel)
27623
27678
  await tunnel.stop();
27679
+ shutdownStep = 'threadline';
27624
27680
  if (threadlineShutdown)
27625
27681
  await threadlineShutdown();
27626
27682
  wakeSocketServer?.stop();
@@ -27643,6 +27699,7 @@ export async function startServer(options) {
27643
27699
  }
27644
27700
  catch { /* ELOCKED is non-critical during shutdown */ }
27645
27701
  scheduler?.stop();
27702
+ shutdownStep = 'telegram';
27646
27703
  if (telegram)
27647
27704
  await telegram.stop();
27648
27705
  sessionManager.stopMonitoring();
@@ -27653,7 +27710,9 @@ export async function startServer(options) {
27653
27710
  sharedStateLedger?.shutdown();
27654
27711
  }
27655
27712
  catch { /* best effort */ }
27713
+ shutdownStep = 'http-server';
27656
27714
  await server.stop();
27715
+ shutdownStep = 'sqlite';
27657
27716
  // Close EVERY registered SQLite handle LAST — after all writers (server,
27658
27717
  // scheduler, sentinels, telegram) have stopped — to prevent the
27659
27718
  // "mutex lock failed" SIGABRT when better-sqlite3 static destructors fire