crewly 1.11.2 → 1.11.4

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 (178) hide show
  1. package/config/skills/agent/core/accept-task/SKILL.md +35 -7
  2. package/config/skills/agent/core/poll-tasks/execute.sh +44 -9
  3. package/config/skills/agent/core/poll-tasks/execute.test.sh +98 -0
  4. package/config/skills/agent/core/record-learning/execute.sh +92 -3
  5. package/config/skills/agent/core/register-self/SKILL.md +51 -8
  6. package/config/skills/agent/transcribe-audio/SKILL.md +110 -0
  7. package/config/skills/agent/transcribe-audio/execute.sh +223 -0
  8. package/config/skills/agent/transcribe-audio/instructions.md +92 -0
  9. package/config/skills/agent/transcribe-audio/skill.json +22 -0
  10. package/config/skills/orchestrator/assign-task/SKILL.md +40 -6
  11. package/config/skills/orchestrator/broadcast/SKILL.md +45 -8
  12. package/dist/backend/backend/src/constants.d.ts +0 -16
  13. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  14. package/dist/backend/backend/src/constants.js +0 -16
  15. package/dist/backend/backend/src/constants.js.map +1 -1
  16. package/dist/backend/backend/src/controllers/memory/memory.controller.d.ts.map +1 -1
  17. package/dist/backend/backend/src/controllers/memory/memory.controller.js +3 -10
  18. package/dist/backend/backend/src/controllers/memory/memory.controller.js.map +1 -1
  19. package/dist/backend/backend/src/controllers/system/system.controller.d.ts.map +1 -1
  20. package/dist/backend/backend/src/controllers/system/system.controller.js +24 -5
  21. package/dist/backend/backend/src/controllers/system/system.controller.js.map +1 -1
  22. package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
  23. package/dist/backend/backend/src/controllers/team/team.controller.js +57 -2
  24. package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
  25. package/dist/backend/backend/src/index.d.ts +2 -0
  26. package/dist/backend/backend/src/index.d.ts.map +1 -1
  27. package/dist/backend/backend/src/index.js +124 -1
  28. package/dist/backend/backend/src/index.js.map +1 -1
  29. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  30. package/dist/backend/backend/src/routes/api.routes.js +0 -3
  31. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  32. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  33. package/dist/backend/backend/src/services/agent/agent-registration.service.js +56 -20
  34. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  35. package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts +1 -0
  36. package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts.map +1 -1
  37. package/dist/backend/backend/src/services/ai/prompt-modules/index.js +1 -0
  38. package/dist/backend/backend/src/services/ai/prompt-modules/index.js.map +1 -1
  39. package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.d.ts.map +1 -1
  40. package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js +2 -0
  41. package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js.map +1 -1
  42. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts +79 -0
  43. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts.map +1 -0
  44. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js +118 -0
  45. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js.map +1 -0
  46. package/dist/backend/backend/src/services/boot/boot-announce.service.d.ts +88 -0
  47. package/dist/backend/backend/src/services/boot/boot-announce.service.d.ts.map +1 -0
  48. package/dist/backend/backend/src/services/boot/boot-announce.service.js +119 -0
  49. package/dist/backend/backend/src/services/boot/boot-announce.service.js.map +1 -0
  50. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -1
  51. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +14 -0
  52. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -1
  53. package/dist/backend/backend/src/services/mcp-server.d.ts.map +1 -1
  54. package/dist/backend/backend/src/services/mcp-server.js +0 -6
  55. package/dist/backend/backend/src/services/mcp-server.js.map +1 -1
  56. package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts +97 -0
  57. package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts.map +1 -0
  58. package/dist/backend/backend/src/services/memory/learning-format.validator.js +209 -0
  59. package/dist/backend/backend/src/services/memory/learning-format.validator.js.map +1 -0
  60. package/dist/backend/backend/src/services/memory/memory.service.d.ts +78 -41
  61. package/dist/backend/backend/src/services/memory/memory.service.d.ts.map +1 -1
  62. package/dist/backend/backend/src/services/memory/memory.service.js +209 -127
  63. package/dist/backend/backend/src/services/memory/memory.service.js.map +1 -1
  64. package/dist/backend/backend/src/services/memory/project-memory.service.d.ts.map +1 -1
  65. package/dist/backend/backend/src/services/memory/project-memory.service.js +37 -9
  66. package/dist/backend/backend/src/services/memory/project-memory.service.js.map +1 -1
  67. package/dist/backend/backend/src/services/orchestrator/commitment-approval-guard.d.ts +46 -0
  68. package/dist/backend/backend/src/services/orchestrator/commitment-approval-guard.d.ts.map +1 -1
  69. package/dist/backend/backend/src/services/orchestrator/commitment-approval-guard.js +51 -0
  70. package/dist/backend/backend/src/services/orchestrator/commitment-approval-guard.js.map +1 -1
  71. package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.d.ts.map +1 -1
  72. package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js +29 -0
  73. package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js.map +1 -1
  74. package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -1
  75. package/dist/backend/backend/src/services/session/pty/pty-session-backend.js +9 -0
  76. package/dist/backend/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
  77. package/dist/backend/backend/src/services/session/runtime-pid-registry.service.d.ts +86 -0
  78. package/dist/backend/backend/src/services/session/runtime-pid-registry.service.d.ts.map +1 -0
  79. package/dist/backend/backend/src/services/session/runtime-pid-registry.service.js +214 -0
  80. package/dist/backend/backend/src/services/session/runtime-pid-registry.service.js.map +1 -0
  81. package/dist/backend/backend/src/services/sop/sop.service.d.ts +70 -2
  82. package/dist/backend/backend/src/services/sop/sop.service.d.ts.map +1 -1
  83. package/dist/backend/backend/src/services/sop/sop.service.js +93 -3
  84. package/dist/backend/backend/src/services/sop/sop.service.js.map +1 -1
  85. package/dist/backend/backend/src/services/task-pool/claim.service.d.ts +41 -0
  86. package/dist/backend/backend/src/services/task-pool/claim.service.d.ts.map +1 -1
  87. package/dist/backend/backend/src/services/task-pool/claim.service.js +72 -0
  88. package/dist/backend/backend/src/services/task-pool/claim.service.js.map +1 -1
  89. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +16 -0
  90. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  91. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +20 -0
  92. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  93. package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.d.ts.map +1 -1
  94. package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.js +11 -0
  95. package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.js.map +1 -1
  96. package/dist/backend/backend/src/services/telegram/telegram.service.d.ts.map +1 -1
  97. package/dist/backend/backend/src/services/telegram/telegram.service.js +24 -2
  98. package/dist/backend/backend/src/services/telegram/telegram.service.js.map +1 -1
  99. package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts.map +1 -1
  100. package/dist/backend/backend/src/services/v3/mission-reminder.service.js +18 -18
  101. package/dist/backend/backend/src/services/v3/mission-reminder.service.js.map +1 -1
  102. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts +10 -0
  103. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -1
  104. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js +20 -12
  105. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js.map +1 -1
  106. package/dist/backend/backend/src/services/wiki/wiki-migrate.service.d.ts.map +1 -1
  107. package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js +12 -3
  108. package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js.map +1 -1
  109. package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts +15 -5
  110. package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts.map +1 -1
  111. package/dist/backend/backend/src/services/wiki/wiki-query.service.js +31 -50
  112. package/dist/backend/backend/src/services/wiki/wiki-query.service.js.map +1 -1
  113. package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts +16 -0
  114. package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -1
  115. package/dist/backend/backend/src/services/wiki/wiki-search.service.js +20 -0
  116. package/dist/backend/backend/src/services/wiki/wiki-search.service.js.map +1 -1
  117. package/dist/backend/backend/src/types/settings.types.d.ts +8 -0
  118. package/dist/backend/backend/src/types/settings.types.d.ts.map +1 -1
  119. package/dist/backend/backend/src/types/settings.types.js +2 -0
  120. package/dist/backend/backend/src/types/settings.types.js.map +1 -1
  121. package/dist/backend/backend/src/types/v2/work-item.types.d.ts +23 -0
  122. package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  123. package/dist/backend/backend/src/types/v2/work-item.types.js +29 -0
  124. package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
  125. package/dist/cli/backend/src/constants.d.ts +0 -16
  126. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  127. package/dist/cli/backend/src/constants.js +0 -16
  128. package/dist/cli/backend/src/constants.js.map +1 -1
  129. package/dist/cli/backend/src/services/mcp-server.d.ts.map +1 -1
  130. package/dist/cli/backend/src/services/mcp-server.js +0 -6
  131. package/dist/cli/backend/src/services/mcp-server.js.map +1 -1
  132. package/dist/cli/backend/src/services/memory/memory.service.d.ts +78 -41
  133. package/dist/cli/backend/src/services/memory/memory.service.d.ts.map +1 -1
  134. package/dist/cli/backend/src/services/memory/memory.service.js +209 -127
  135. package/dist/cli/backend/src/services/memory/memory.service.js.map +1 -1
  136. package/dist/cli/backend/src/services/memory/project-memory.service.d.ts.map +1 -1
  137. package/dist/cli/backend/src/services/memory/project-memory.service.js +37 -9
  138. package/dist/cli/backend/src/services/memory/project-memory.service.js.map +1 -1
  139. package/dist/cli/backend/src/services/task-pool/claim.service.d.ts +41 -0
  140. package/dist/cli/backend/src/services/task-pool/claim.service.d.ts.map +1 -1
  141. package/dist/cli/backend/src/services/task-pool/claim.service.js +72 -0
  142. package/dist/cli/backend/src/services/task-pool/claim.service.js.map +1 -1
  143. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +16 -0
  144. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  145. package/dist/cli/backend/src/services/task-pool/task-pool.service.js +20 -0
  146. package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  147. package/dist/cli/backend/src/services/wiki/schema-loader.service.d.ts +57 -0
  148. package/dist/cli/backend/src/services/wiki/schema-loader.service.d.ts.map +1 -0
  149. package/dist/cli/backend/src/services/wiki/schema-loader.service.js +183 -0
  150. package/dist/cli/backend/src/services/wiki/schema-loader.service.js.map +1 -0
  151. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts +100 -0
  152. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -0
  153. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js +212 -0
  154. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js.map +1 -0
  155. package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.d.ts +43 -0
  156. package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.d.ts.map +1 -0
  157. package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.js +67 -0
  158. package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.js.map +1 -0
  159. package/dist/cli/backend/src/services/wiki/wiki-search.service.d.ts +166 -0
  160. package/dist/cli/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -0
  161. package/dist/cli/backend/src/services/wiki/wiki-search.service.js +379 -0
  162. package/dist/cli/backend/src/services/wiki/wiki-search.service.js.map +1 -0
  163. package/dist/cli/backend/src/services/wiki/wiki.types.d.ts +84 -0
  164. package/dist/cli/backend/src/services/wiki/wiki.types.d.ts.map +1 -0
  165. package/dist/cli/backend/src/services/wiki/wiki.types.js +10 -0
  166. package/dist/cli/backend/src/services/wiki/wiki.types.js.map +1 -0
  167. package/dist/cli/backend/src/types/settings.types.d.ts +8 -0
  168. package/dist/cli/backend/src/types/settings.types.d.ts.map +1 -1
  169. package/dist/cli/backend/src/types/settings.types.js +2 -0
  170. package/dist/cli/backend/src/types/settings.types.js.map +1 -1
  171. package/dist/cli/backend/src/types/v2/work-item.types.d.ts +23 -0
  172. package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  173. package/dist/cli/backend/src/types/v2/work-item.types.js +29 -0
  174. package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
  175. package/frontend/dist/assets/{index-44266b5d.css → index-8205ea5e.css} +1 -1
  176. package/frontend/dist/assets/{index-4099a91c.js → index-890d3f9d.js} +289 -289
  177. package/frontend/dist/index.html +2 -2
  178. package/package.json +1 -1
@@ -15,6 +15,7 @@ import os from 'os';
15
15
  import { fileURLToPath } from 'url';
16
16
  import { StorageService, TmuxService, SchedulerService, MessageSchedulerService, ActivityMonitorService, TeamActivityWebSocketService, TeamsJsonWatcherService, } from './services/index.js';
17
17
  import { getSessionBackend, getSessionBackendSync, getSessionStatePersistence, destroySessionBackend, PtySessionBackend, } from './services/session/index.js';
18
+ import { RuntimePidRegistry } from './services/session/runtime-pid-registry.service.js';
18
19
  import { ApiController } from './controllers/api.controller.js';
19
20
  import { createApiRoutes } from './routes/api.routes.js';
20
21
  import { TerminalGateway, setTerminalGateway } from './websocket/terminal.gateway.js';
@@ -36,12 +37,13 @@ import { EventBusService } from './services/event-bus/index.js';
36
37
  import { EventToWorkItemBridge } from './services/event-bus/event-to-workitem-bridge.service.js';
37
38
  import { AutoLearningSubscriber } from './services/memory/auto-learning.subscriber.js';
38
39
  import { MilestoneNotificationSubscriber } from './services/notification/milestone-notification.subscriber.js';
39
- import { RequestSlaSubscriber, setRequestSlaSubscriber, } from './services/v3/request-sla.subscriber.js';
40
+ import { RequestSlaSubscriber, setRequestSlaSubscriber, getRequestSlaSubscriber, } from './services/v3/request-sla.subscriber.js';
40
41
  import { RequestDecomposeSubscriber, setRequestDecomposeSubscriber, } from './services/v3/request-decompose.subscriber.js';
41
42
  import { RequestStatusUpdateSubscriber } from './services/v3/request-status-update.subscriber.js';
42
43
  import { RequestCascadeSubscriber } from './services/v3/request-cascade.subscriber.js';
43
44
  import { setRequestServiceEventBus, RequestService } from './services/v3/request.service.js';
44
45
  import { getSlackService } from './services/slack/slack.service.js';
46
+ import { sendBootAnnouncement, isFirstBoot, markBooted } from './services/boot/boot-announce.service.js';
45
47
  import { SlackThreadStoreService, setSlackThreadStore, getSlackThreadStore } from './services/slack/slack-thread-store.service.js';
46
48
  import { GoogleChatThreadStoreService, setGchatThreadStore } from './services/messaging/gchat-thread-store.service.js';
47
49
  import { SlackImageService, setSlackImageService } from './services/slack/slack-image.service.js';
@@ -125,6 +127,8 @@ export class CrewlyServer {
125
127
  io;
126
128
  config;
127
129
  logger = LoggerService.getInstance().createComponentLogger('CrewlyServer');
130
+ /** Offline-replay summary from this boot, surfaced in the boot announcement. */
131
+ lastOfflineReplay;
128
132
  storageService;
129
133
  tmuxService;
130
134
  schedulerService;
@@ -903,6 +907,41 @@ export class CrewlyServer {
903
907
  shadowMode: watchdog.getLastSweep()?.shadowMode ?? null,
904
908
  }
905
909
  : { status: 'warming', last_sweep_age_ms: -1, shadowMode: null };
910
+ // Orchestrator-liveness signal (issue #686). The silent 假死 symptom is
911
+ // "inbound user messages queue but nobody answers": no active agent AND
912
+ // outstanding `respond_to_user` SLA trackers. Surface it as a body block
913
+ // — we deliberately keep top-level status:"healthy" / HTTP 200 so a load
914
+ // balancer doesn't drop the node on this (the LB keys on the status code;
915
+ // this signal is for dashboards/monitoring to read from the body).
916
+ const slaSub = getRequestSlaSubscriber();
917
+ const pendingUserRequests = slaSub ? slaSub.getPendingUserRequestCount() : 0;
918
+ // "Down" — no active agent while user work is queued (issue #686).
919
+ const orchestratorDown = agentCount === 0 && pendingUserRequests > 0;
920
+ // "Up but hung" — the orchestrator process is alive yet its session keeps
921
+ // claiming work and never heartbeats (claims get grace-revoked in a loop).
922
+ // agentCount>0 hides this from the "down" check, so detect it explicitly
923
+ // via the claim-service hung signal (the Irissair 假死).
924
+ let orchestratorHung = false;
925
+ try {
926
+ orchestratorHung = TaskPoolService.getInstance()
927
+ .getHungAgents()
928
+ .includes(ORCHESTRATOR_SESSION_NAME);
929
+ }
930
+ catch {
931
+ // Task pool not ready yet — treat as not-hung.
932
+ }
933
+ const orchestratorStalled = orchestratorDown || orchestratorHung;
934
+ const orchestratorBlock = {
935
+ status: orchestratorStalled ? 'degraded' : 'ok',
936
+ activeAgents: agentCount,
937
+ pendingUserRequests,
938
+ hung: orchestratorHung,
939
+ reason: orchestratorHung
940
+ ? 'orchestrator session is hung — claiming work but not heartbeating (repeated grace-revokes)'
941
+ : orchestratorDown
942
+ ? `no active agent with ${pendingUserRequests} pending user request(s) — orchestrator may be down`
943
+ : null,
944
+ };
906
945
  res.json({
907
946
  status: 'healthy',
908
947
  timestamp: new Date().toISOString(),
@@ -916,6 +955,7 @@ export class CrewlyServer {
916
955
  total: agentCount,
917
956
  },
918
957
  team_health: teamHealthBlock,
958
+ orchestrator: orchestratorBlock,
919
959
  });
920
960
  });
921
961
  // H5 quick entry static page (served regardless of headless mode)
@@ -1515,6 +1555,11 @@ export class CrewlyServer {
1515
1555
  const { MessageReplayService } = await import('./services/messaging/message-replay.service.js');
1516
1556
  const replayService = new MessageReplayService(this.messageQueueService, this.config.crewlyHome);
1517
1557
  const replayResult = await replayService.replayPendingMessages();
1558
+ // Stash for the boot announcement (surfaced after the orchestrator starts).
1559
+ this.lastOfflineReplay = {
1560
+ offlineDurationMs: replayResult.offlineDurationMs,
1561
+ replayedCount: replayResult.replayedCount,
1562
+ };
1518
1563
  if (replayResult.replayedCount > 0) {
1519
1564
  this.logger.info('Replayed pending messages from offline period (#247)', {
1520
1565
  replayed: replayResult.replayedCount,
@@ -1799,6 +1844,23 @@ export class CrewlyServer {
1799
1844
  error: dispatchErr instanceof Error ? dispatchErr.message : String(dispatchErr),
1800
1845
  });
1801
1846
  }
1847
+ // Bootstrap SOPService at boot (F8 — fix/f8-get-sops-graceful-fallback).
1848
+ // This materialises `~/.crewly/sops/{system,custom}/` and seeds the
1849
+ // `index.json` so the get-sops skill — which sits on every agent's
1850
+ // session-startup hot path — never hits a missing-file 500.
1851
+ // SOPService.initialize is internally idempotent and the service has
1852
+ // graceful in-memory fallbacks, so this is non-critical: failures here
1853
+ // will be tolerated by the API layer at request time.
1854
+ try {
1855
+ const { SOPService } = await import('./services/sop/sop.service.js');
1856
+ await SOPService.getInstance().initialize();
1857
+ this.logger.info('SOPService bootstrapped — get-sops endpoint ready');
1858
+ }
1859
+ catch (sopErr) {
1860
+ this.logger.warn('SOPService bootstrap failed (non-critical, runtime fallback active)', {
1861
+ error: sopErr instanceof Error ? sopErr.message : String(sopErr),
1862
+ });
1863
+ }
1802
1864
  // Start AgentAutoClaimService — auto-assign work to idle agents
1803
1865
  try {
1804
1866
  const { AgentAutoClaimService } = await import('./services/v3/agent-auto-claim.service.js');
@@ -1957,6 +2019,23 @@ export class CrewlyServer {
1957
2019
  this.registerSignalHandlers();
1958
2020
  // Start health monitoring
1959
2021
  this.startHealthMonitoring();
2022
+ // Reap orphaned runtime processes left by a previous, non-graceful
2023
+ // backend death (crash / OOM / force-exit) BEFORE we spawn any new
2024
+ // sessions below — otherwise stray `gemini --yolo` / `claude` runtimes
2025
+ // accumulate across restarts and inflate the process table (#715).
2026
+ // Identity-verified: only kills recorded PIDs whose live cmdline still
2027
+ // matches, so it never touches an unrelated reused PID.
2028
+ try {
2029
+ const reaped = RuntimePidRegistry.getInstance().reapOrphans();
2030
+ if (reaped > 0) {
2031
+ this.logger.warn('Reaped orphaned runtime processes at startup', { reaped });
2032
+ }
2033
+ }
2034
+ catch (err) {
2035
+ this.logger.warn('Orphan runtime reap failed (non-fatal)', {
2036
+ error: err instanceof Error ? err.message : String(err),
2037
+ });
2038
+ }
1960
2039
  // Auto-start orchestrator if enabled in settings
1961
2040
  await this.autoStartOrchestratorIfEnabled();
1962
2041
  // Auto-restore agent sessions that were running before the last shutdown
@@ -2302,6 +2381,50 @@ export class CrewlyServer {
2302
2381
  this.terminalGateway.startOrchestratorChatMonitoring(ORCHESTRATOR_SESSION_NAME);
2303
2382
  }
2304
2383
  this.logger.info('Orchestrator auto-started successfully');
2384
+ // Announce "back online" to the owner's channel (best-effort, never
2385
+ // blocks boot). Deterministic system message — reports startup + the
2386
+ // running version, enriched with offline duration + replayed count.
2387
+ try {
2388
+ const settings = await getSettingsService().getSettings();
2389
+ if (settings.general.announceOnBoot) {
2390
+ let version = 'unknown';
2391
+ try {
2392
+ version = VersionCheckService.getInstance().getLocalVersion();
2393
+ }
2394
+ catch {
2395
+ version = process.env.npm_package_version || 'unknown';
2396
+ }
2397
+ // First-ever boot → welcome; subsequent boots → "back online".
2398
+ const bootMarker = path.join(this.config.crewlyHome, '.boot-announced');
2399
+ const firstBoot = isFirstBoot(bootMarker);
2400
+ if (firstBoot)
2401
+ markBooted(bootMarker);
2402
+ await sendBootAnnouncement({
2403
+ version,
2404
+ firstBoot,
2405
+ offlineDurationMs: this.lastOfflineReplay?.offlineDurationMs,
2406
+ replayedCount: this.lastOfflineReplay?.replayedCount,
2407
+ }, {
2408
+ isSlackConnected: () => getSlackService().isConnected(),
2409
+ sendSlack: (msg) => getSlackService().sendNotification({
2410
+ type: 'project_update',
2411
+ title: msg.title,
2412
+ message: msg.message,
2413
+ urgency: 'normal',
2414
+ timestamp: new Date().toISOString(),
2415
+ }),
2416
+ logger: {
2417
+ info: (m, meta) => this.logger.info(m, meta),
2418
+ warn: (m, meta) => this.logger.warn(m, meta),
2419
+ },
2420
+ });
2421
+ }
2422
+ }
2423
+ catch (announceErr) {
2424
+ this.logger.warn('Boot announce skipped (non-critical)', {
2425
+ error: announceErr instanceof Error ? announceErr.message : String(announceErr),
2426
+ });
2427
+ }
2305
2428
  }
2306
2429
  catch (error) {
2307
2430
  this.logger.error('Failed to auto-start orchestrator', {