crewly 1.20.294 → 1.20.296

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 (125) hide show
  1. package/config/skills/_common/lib.sh +6 -0
  2. package/config/skills/agent/core/complete-task/SKILL.md +4 -2
  3. package/config/skills/agent/core/complete-task/execute.sh +7 -0
  4. package/config/skills/agent/core/complete-task/explicit-id.test.sh +56 -0
  5. package/config/skills/agent/core/poll-tasks/execute.sh +13 -1
  6. package/config/skills/agent/core/poll-tasks/execute.test.sh +37 -0
  7. package/config/skills/team-leader/delegate-task/execute.sh +13 -2
  8. package/config/skills/team-leader/verify-output/SKILL.md +9 -0
  9. package/dist/backend/backend/src/constants.d.ts +16 -2
  10. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  11. package/dist/backend/backend/src/constants.js +16 -2
  12. package/dist/backend/backend/src/constants.js.map +1 -1
  13. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
  14. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +28 -8
  15. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
  16. package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
  17. package/dist/backend/backend/src/controllers/slack/slack.controller.js +28 -1
  18. package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
  19. package/dist/backend/backend/src/controllers/team/team.controller.d.ts +1 -0
  20. package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
  21. package/dist/backend/backend/src/controllers/team/team.controller.js +5 -1
  22. package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
  23. package/dist/backend/backend/src/index.d.ts.map +1 -1
  24. package/dist/backend/backend/src/index.js +44 -6
  25. package/dist/backend/backend/src/index.js.map +1 -1
  26. package/dist/backend/backend/src/services/agent/resource-mode.service.d.ts +1 -0
  27. package/dist/backend/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
  28. package/dist/backend/backend/src/services/agent/resource-mode.service.js +4 -3
  29. package/dist/backend/backend/src/services/agent/resource-mode.service.js.map +1 -1
  30. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +52 -1
  31. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  32. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +101 -29
  33. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  34. package/dist/backend/backend/src/services/messaging/deferred-start-retry.d.ts +45 -0
  35. package/dist/backend/backend/src/services/messaging/deferred-start-retry.d.ts.map +1 -0
  36. package/dist/backend/backend/src/services/messaging/deferred-start-retry.js +70 -0
  37. package/dist/backend/backend/src/services/messaging/deferred-start-retry.js.map +1 -0
  38. package/dist/backend/backend/src/services/messaging/sub-agent-message-queue.service.d.ts +18 -4
  39. package/dist/backend/backend/src/services/messaging/sub-agent-message-queue.service.d.ts.map +1 -1
  40. package/dist/backend/backend/src/services/messaging/sub-agent-message-queue.service.js +36 -8
  41. package/dist/backend/backend/src/services/messaging/sub-agent-message-queue.service.js.map +1 -1
  42. package/dist/backend/backend/src/services/orc/reply-destination-resolver.d.ts +6 -0
  43. package/dist/backend/backend/src/services/orc/reply-destination-resolver.d.ts.map +1 -1
  44. package/dist/backend/backend/src/services/orc/reply-destination-resolver.js +18 -0
  45. package/dist/backend/backend/src/services/orc/reply-destination-resolver.js.map +1 -1
  46. package/dist/backend/backend/src/services/orc/reply-destination.wiring.d.ts +2 -0
  47. package/dist/backend/backend/src/services/orc/reply-destination.wiring.d.ts.map +1 -1
  48. package/dist/backend/backend/src/services/orc/reply-destination.wiring.js +81 -8
  49. package/dist/backend/backend/src/services/orc/reply-destination.wiring.js.map +1 -1
  50. package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts +8 -0
  51. package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts.map +1 -1
  52. package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.js +22 -0
  53. package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.js.map +1 -1
  54. package/dist/backend/backend/src/services/session/session-command-helper.d.ts +17 -0
  55. package/dist/backend/backend/src/services/session/session-command-helper.d.ts.map +1 -1
  56. package/dist/backend/backend/src/services/session/session-command-helper.js +32 -0
  57. package/dist/backend/backend/src/services/session/session-command-helper.js.map +1 -1
  58. package/dist/backend/backend/src/services/slack/orc-owner-dm-target.d.ts +27 -0
  59. package/dist/backend/backend/src/services/slack/orc-owner-dm-target.d.ts.map +1 -0
  60. package/dist/backend/backend/src/services/slack/orc-owner-dm-target.js +48 -0
  61. package/dist/backend/backend/src/services/slack/orc-owner-dm-target.js.map +1 -0
  62. package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js +1 -1
  63. package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
  64. package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
  65. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +13 -1
  66. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  67. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts +3 -2
  68. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
  69. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js +8 -2
  70. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
  71. package/dist/backend/backend/src/services/task-pool/pool-archive-migration.d.ts +18 -0
  72. package/dist/backend/backend/src/services/task-pool/pool-archive-migration.d.ts.map +1 -1
  73. package/dist/backend/backend/src/services/task-pool/pool-archive-migration.js +9 -3
  74. package/dist/backend/backend/src/services/task-pool/pool-archive-migration.js.map +1 -1
  75. package/dist/backend/backend/src/services/task-pool/pool-prune.d.ts +76 -0
  76. package/dist/backend/backend/src/services/task-pool/pool-prune.d.ts.map +1 -0
  77. package/dist/backend/backend/src/services/task-pool/pool-prune.js +129 -0
  78. package/dist/backend/backend/src/services/task-pool/pool-prune.js.map +1 -0
  79. package/dist/backend/backend/src/services/task-pool/pool-storage.d.ts +9 -1
  80. package/dist/backend/backend/src/services/task-pool/pool-storage.d.ts.map +1 -1
  81. package/dist/backend/backend/src/services/task-pool/pool-storage.js +34 -3
  82. package/dist/backend/backend/src/services/task-pool/pool-storage.js.map +1 -1
  83. package/dist/backend/backend/src/utils/screen-excerpt.d.ts +34 -0
  84. package/dist/backend/backend/src/utils/screen-excerpt.d.ts.map +1 -0
  85. package/dist/backend/backend/src/utils/screen-excerpt.js +56 -0
  86. package/dist/backend/backend/src/utils/screen-excerpt.js.map +1 -0
  87. package/dist/backend/build-info.json +2 -2
  88. package/dist/cli/backend/src/constants.d.ts +16 -2
  89. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  90. package/dist/cli/backend/src/constants.js +16 -2
  91. package/dist/cli/backend/src/constants.js.map +1 -1
  92. package/dist/cli/backend/src/services/agent/resource-mode.service.d.ts +1 -0
  93. package/dist/cli/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
  94. package/dist/cli/backend/src/services/agent/resource-mode.service.js +4 -3
  95. package/dist/cli/backend/src/services/agent/resource-mode.service.js.map +1 -1
  96. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +52 -1
  97. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  98. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +101 -29
  99. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  100. package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.d.ts +18 -4
  101. package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.d.ts.map +1 -1
  102. package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.js +36 -8
  103. package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.js.map +1 -1
  104. package/dist/cli/backend/src/services/session/session-command-helper.d.ts +17 -0
  105. package/dist/cli/backend/src/services/session/session-command-helper.d.ts.map +1 -1
  106. package/dist/cli/backend/src/services/session/session-command-helper.js +32 -0
  107. package/dist/cli/backend/src/services/session/session-command-helper.js.map +1 -1
  108. package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js +1 -1
  109. package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
  110. package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
  111. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +13 -1
  112. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  113. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts +3 -2
  114. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
  115. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js +8 -2
  116. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
  117. package/dist/cli/backend/src/services/task-pool/pool-storage.d.ts +9 -1
  118. package/dist/cli/backend/src/services/task-pool/pool-storage.d.ts.map +1 -1
  119. package/dist/cli/backend/src/services/task-pool/pool-storage.js +34 -3
  120. package/dist/cli/backend/src/services/task-pool/pool-storage.js.map +1 -1
  121. package/dist/cli/backend/src/utils/screen-excerpt.d.ts +34 -0
  122. package/dist/cli/backend/src/utils/screen-excerpt.d.ts.map +1 -0
  123. package/dist/cli/backend/src/utils/screen-excerpt.js +56 -0
  124. package/dist/cli/backend/src/utils/screen-excerpt.js.map +1 -0
  125. package/package.json +1 -1
@@ -77,7 +77,7 @@ import { parseSlackThreadKey } from './services/slack/slack-thread-key.js';
77
77
  import { LIVENESS_MONITOR_CONSTANTS, INPUT_CIRCUIT_CONSTANTS, INPUT_BLOCKED_RETRY_CONSTANTS } from './constants.js';
78
78
  import { InputBlockedRetryService } from './services/messaging/input-blocked-retry.service.js';
79
79
  import { driveCapabilities } from './services/drive/drive-agent.service.js';
80
- import { SUB_AGENT_QUEUE_CONSTANTS, CHAT_CONTEXT_CONSTANTS, SAFE_RESTART, AUTO_UPDATE_CONSTANTS, PROCESS_EXIT_CODES, CLAUDE_STARTUP_CONSTANTS, WEB_CONSTANTS, TICKET_CONSTANTS, UNASSIGNED_ROUTE_CONSTANTS, CLOUD_TALK_CONSTANTS, STANDING_ANSWERS_CONSTANTS, TICKET_AUTOPILOT_CONSTANTS, TICKET_HYGIENE_CONSTANTS, EXPERIMENT_CONSTANTS, WORK_ITEM_DESTINATION_CONSTANTS, CODEX_USAGE_SYNC_CONSTANTS, ANTIGRAVITY_USAGE_SYNC_CONSTANTS, OWNER_AUTH_CONSTANTS, CREWLY_APPS_CONSTANTS, SLACK_AGENT_DM_CONSTANTS, BRIEFING_CONSTANTS, DRIVE_CONSTANTS } from './constants.js';
80
+ import { SUB_AGENT_QUEUE_CONSTANTS, CHAT_CONTEXT_CONSTANTS, SAFE_RESTART, AUTO_UPDATE_CONSTANTS, PROCESS_EXIT_CODES, CLAUDE_STARTUP_CONSTANTS, WEB_CONSTANTS, TICKET_CONSTANTS, UNASSIGNED_ROUTE_CONSTANTS, CLOUD_TALK_CONSTANTS, STANDING_ANSWERS_CONSTANTS, TICKET_AUTOPILOT_CONSTANTS, TICKET_HYGIENE_CONSTANTS, EXPERIMENT_CONSTANTS, WORK_ITEM_DESTINATION_CONSTANTS, CODEX_USAGE_SYNC_CONSTANTS, ANTIGRAVITY_USAGE_SYNC_CONSTANTS, OWNER_AUTH_CONSTANTS, CREWLY_APPS_CONSTANTS, SLACK_AGENT_DM_CONSTANTS, BRIEFING_CONSTANTS, DRIVE_CONSTANTS, POOL_PRUNE_CONSTANTS } from './constants.js';
81
81
  import { randomUUID } from 'crypto';
82
82
  import { PtyActivityTrackerService } from './services/agent/pty-activity-tracker.service.js';
83
83
  import { InFlightTurnTracker } from './services/restart/in-flight-turn-tracker.service.js';
@@ -88,6 +88,7 @@ import { initialDecider, nextDecider } from './services/task-pool/untargeted-rou
88
88
  import { activeAcceptance, formatTicketMarker, formatTicketNumber } from './types/v2/ticket.types.js';
89
89
  import { createWorkItem, TERMINAL_WORK_ITEM_STATUSES } from './types/v2/work-item.types.js';
90
90
  import { runPoolArchiveMigration } from './services/task-pool/pool-archive-migration.js';
91
+ import { runPoolPrune } from './services/task-pool/pool-prune.js';
91
92
  import { createPtyTurnProbe } from './services/restart/turn-probe.js';
92
93
  import { RestartDrainService, resolveRestartDrainMs, resolveBackgroundDrainMs, } from './services/restart/restart-drain.service.js';
93
94
  import { interruptedTurnsPath, loadInterruptedTurns, saveInterruptedTurns, writeInterruptedTurns, resumeInterruptedTurns, planCommitmentNotes, } from './services/restart/interrupted-turns.js';
@@ -185,6 +186,7 @@ import { TaskHistorySubscriber } from './services/memory/task-history.subscriber
185
186
  import { TeamHealthWatchdogService, LiveTeamHealthDataProvider, loadTeamHealthConfig, setTeamHealthWatchdogSingleton, getTeamHealthWatchdogSingleton, } from './services/team-health/index.js';
186
187
  import { traceHarness, traceTurnActivity } from './services/trace/trace-recorder.js';
187
188
  import { inputCircuitStats, setInputCircuitOpenListener } from './services/session/input-circuit-breaker.js';
189
+ import { looksLikeShellPrompt } from './utils/screen-excerpt.js';
188
190
  import { harnessPastesSinceOutsideInput, shownMarkers } from './services/session/input-ledger.js';
189
191
  // ESM __dirname equivalent using import.meta.url
190
192
  const __filename = fileURLToPath(import.meta.url);
@@ -764,13 +766,25 @@ export class CrewlyServer {
764
766
  // Ticket loop §4: one-time archive of old WorkItems (marker file makes
765
767
  // it run once). Through the pool's own storage cache, so no later
766
768
  // flush can write the archived items back. Never deletes.
769
+ const poolPruneLogger = LoggerService.getInstance().createComponentLogger('PoolPrune');
770
+ const pruneOnce = () => runPoolPrune(TaskPoolService.getInstance().getStorage(), { logger: poolPruneLogger }).catch((pruneErr) => {
771
+ this.logger.warn('Task pool prune failed (pool left as is; retried next interval)', {
772
+ error: pruneErr instanceof Error ? pruneErr.message : String(pruneErr),
773
+ });
774
+ });
767
775
  void runPoolArchiveMigration(TaskPoolService.getInstance().getStorage(), {
768
776
  logger: LoggerService.getInstance().createComponentLogger('PoolArchive'),
769
- }).catch((archiveErr) => {
777
+ })
778
+ .catch((archiveErr) => {
770
779
  this.logger.warn('Task pool one-time archive failed (pool left as is; retried next boot)', {
771
780
  error: archiveErr instanceof Error ? archiveErr.message : String(archiveErr),
772
781
  });
773
- });
782
+ })
783
+ // Then keep it small: finished items and ended claims move to the
784
+ // archive, once now and every few hours (crewly#1108).
785
+ .then(pruneOnce);
786
+ const poolPruneTimer = setInterval(() => void pruneOnce(), POOL_PRUNE_CONSTANTS.INTERVAL_MS);
787
+ poolPruneTimer.unref?.();
774
788
  // Atlas 2026-05-23 fix: wire the agent-liveness gate so claimFromPool /
775
789
  // claimSpecificItem refuse to put a WI into `running` when the requesting
776
790
  // agent's session is dead. delegate-task's "self-heal fix #1" used to
@@ -2417,7 +2431,20 @@ export class CrewlyServer {
2417
2431
  activateAgent: async (agentSession) => {
2418
2432
  const { activateAgentBySession } = await import('./controllers/team/team.controller.js');
2419
2433
  const res = await activateAgentBySession(this.apiController, agentSession);
2420
- return res.success;
2434
+ // A start waiting for a running-agent slot is deferred, not failed.
2435
+ return res.success ? true : res.deferred ? 'deferred' : false;
2436
+ },
2437
+ // The message waits on the agent's persisted queue for a deferred start.
2438
+ holdForStart: (agentSession, prompt) => {
2439
+ SubAgentMessageQueue.getInstance().enqueue(agentSession, prompt);
2440
+ // Nothing else starts the agent when a slot frees: retry until it does.
2441
+ void import('./services/messaging/deferred-start-retry.js').then(async ({ scheduleDeferredStartRetry }) => {
2442
+ const { activateAgentBySession } = await import('./controllers/team/team.controller.js');
2443
+ await scheduleDeferredStartRetry(agentSession, {
2444
+ activate: (name) => activateAgentBySession(this.apiController, name),
2445
+ hasPending: (name) => SubAgentMessageQueue.getInstance().hasPending(name),
2446
+ });
2447
+ });
2421
2448
  },
2422
2449
  // Every owner message that reached an agent is watched until
2423
2450
  // it is answered (specs/2026-09-30-owner-message-guarantee.md).
@@ -6370,6 +6397,17 @@ export class CrewlyServer {
6370
6397
  };
6371
6398
  // Every delivery refused for a while: automatic redelivery is slowed
6372
6399
  // to a probe now and then, and the owner told once (crewly#1028).
6400
+ // What the unreadable screen shows (redacted rows), so the owner can
6401
+ // tell a dialog from a bare shell without opening the terminal.
6402
+ const screenNote = (sessionName, state) => {
6403
+ if (state !== 'unknown')
6404
+ return '';
6405
+ const excerpt = SessionCommandHelper.unreadableExcerpt(sessionName);
6406
+ if (!excerpt)
6407
+ return '';
6408
+ const hint = looksLikeShellPrompt(excerpt) ? ' It looks like the runtime exited to a shell prompt.' : '';
6409
+ return `${hint}\nScreen (secrets masked):\n${excerpt.split('\n').map((l) => `> ${l}`).join('\n')}`;
6410
+ };
6373
6411
  setInputCircuitOpenListener((info) => {
6374
6412
  traceHarness('guard.block', {
6375
6413
  session: info.sessionName,
@@ -6422,7 +6460,7 @@ export class CrewlyServer {
6422
6460
  ? 'its input box cannot be read (a dialog or an unfamiliar screen)'
6423
6461
  : `its input box holds ${notice.inputLength} characters that Crewly did not write`;
6424
6462
  const maxMin = Math.round(INPUT_CIRCUIT_CONSTANTS.PROBE_MAX_MS / 60000);
6425
- tell(notice.sessionName, `Needs you: ${notice.sessionName} has not received any message for ${minutes} min: ${what}, so Crewly refused to type over it (${notice.refusals} attempts). Crewly has stopped retrying every few seconds and now tries again only every few minutes (at most every ${maxMin} min). To fix it, open ${notice.sessionName}'s terminal and clear the input box (Ctrl+U), or press Enter if that text is yours. Delivery resumes on its own after that.`, notice.message || undefined);
6463
+ tell(notice.sessionName, `Needs you: ${notice.sessionName} has not received any message for ${minutes} min: ${what}, so Crewly refused to type over it (${notice.refusals} attempts). Crewly has stopped retrying every few seconds and now tries again only every few minutes (at most every ${maxMin} min). To fix it, open ${notice.sessionName}'s terminal and clear the input box (Ctrl+U), or press Enter if that text is yours. Delivery resumes on its own after that.${screenNote(notice.sessionName, notice.blockedState)}`, notice.message || undefined);
6426
6464
  return;
6427
6465
  }
6428
6466
  if (notice.state === 'busy') {
@@ -6432,7 +6470,7 @@ export class CrewlyServer {
6432
6470
  const what = notice.state === 'unknown'
6433
6471
  ? 'its input box cannot be read (a dialog or an unfamiliar screen)'
6434
6472
  : `its input box holds ${notice.inputLength} characters of text not written by Crewly`;
6435
- tell(notice.sessionName, `Needs you: messages to ${notice.sessionName} are waiting because ${what}. Crewly will not type over it. Tried ${notice.refusals} times over ${minutes} min; it keeps retrying. Clear the agent's input (or answer its screen) to let them through.`, notice.message);
6473
+ tell(notice.sessionName, `Needs you: messages to ${notice.sessionName} are waiting because ${what}. Crewly will not type over it. Tried ${notice.refusals} times over ${minutes} min; it keeps retrying. Clear the agent's input (or answer its screen) to let them through.${screenNote(notice.sessionName, notice.state)}`, notice.message);
6436
6474
  },
6437
6475
  });
6438
6476
  // A WorkItem brief held by the restart drain gets its hand-over