crewly 1.20.152 → 1.20.153

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 (71) hide show
  1. package/config/roles/orchestrator/prompt.md +7 -0
  2. package/config/roles/team-leader/prompt.md +6 -0
  3. package/config/sops/developer/git-workflow.md +1 -0
  4. package/dist/backend/backend/src/constants.d.ts +92 -0
  5. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  6. package/dist/backend/backend/src/constants.js +92 -0
  7. package/dist/backend/backend/src/constants.js.map +1 -1
  8. package/dist/backend/backend/src/controllers/worktree-janitor/worktree-janitor.routes.d.ts +29 -0
  9. package/dist/backend/backend/src/controllers/worktree-janitor/worktree-janitor.routes.d.ts.map +1 -0
  10. package/dist/backend/backend/src/controllers/worktree-janitor/worktree-janitor.routes.js +63 -0
  11. package/dist/backend/backend/src/controllers/worktree-janitor/worktree-janitor.routes.js.map +1 -0
  12. package/dist/backend/backend/src/index.d.ts +7 -0
  13. package/dist/backend/backend/src/index.d.ts.map +1 -1
  14. package/dist/backend/backend/src/index.js +114 -2
  15. package/dist/backend/backend/src/index.js.map +1 -1
  16. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  17. package/dist/backend/backend/src/routes/api.routes.js +3 -0
  18. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  19. package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts +18 -3
  20. package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts.map +1 -1
  21. package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.js +28 -4
  22. package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.js.map +1 -1
  23. package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
  24. package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
  25. package/dist/backend/backend/src/services/cloud/cloud-sync.types.js +1 -0
  26. package/dist/backend/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
  27. package/dist/backend/backend/src/services/cloud/waiting-actions-inbound.service.d.ts +128 -0
  28. package/dist/backend/backend/src/services/cloud/waiting-actions-inbound.service.d.ts.map +1 -0
  29. package/dist/backend/backend/src/services/cloud/waiting-actions-inbound.service.js +279 -0
  30. package/dist/backend/backend/src/services/cloud/waiting-actions-inbound.service.js.map +1 -0
  31. package/dist/backend/backend/src/services/cloud/waiting-items-sync.service.d.ts +122 -0
  32. package/dist/backend/backend/src/services/cloud/waiting-items-sync.service.d.ts.map +1 -0
  33. package/dist/backend/backend/src/services/cloud/waiting-items-sync.service.js +261 -0
  34. package/dist/backend/backend/src/services/cloud/waiting-items-sync.service.js.map +1 -0
  35. package/dist/backend/backend/src/services/cloud/waiting-items.contract.d.ts +101 -0
  36. package/dist/backend/backend/src/services/cloud/waiting-items.contract.d.ts.map +1 -0
  37. package/dist/backend/backend/src/services/cloud/waiting-items.contract.js +113 -0
  38. package/dist/backend/backend/src/services/cloud/waiting-items.contract.js.map +1 -0
  39. package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
  40. package/dist/backend/backend/src/services/slack/slack-initializer.js +2 -1
  41. package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
  42. package/dist/backend/backend/src/services/v3/request.service.d.ts +19 -0
  43. package/dist/backend/backend/src/services/v3/request.service.d.ts.map +1 -1
  44. package/dist/backend/backend/src/services/v3/request.service.js +36 -0
  45. package/dist/backend/backend/src/services/v3/request.service.js.map +1 -1
  46. package/dist/backend/backend/src/services/worktree/worktree-janitor.git.d.ts +131 -0
  47. package/dist/backend/backend/src/services/worktree/worktree-janitor.git.d.ts.map +1 -0
  48. package/dist/backend/backend/src/services/worktree/worktree-janitor.git.js +238 -0
  49. package/dist/backend/backend/src/services/worktree/worktree-janitor.git.js.map +1 -0
  50. package/dist/backend/backend/src/services/worktree/worktree-janitor.service.d.ts +241 -0
  51. package/dist/backend/backend/src/services/worktree/worktree-janitor.service.d.ts.map +1 -0
  52. package/dist/backend/backend/src/services/worktree/worktree-janitor.service.js +504 -0
  53. package/dist/backend/backend/src/services/worktree/worktree-janitor.service.js.map +1 -0
  54. package/dist/backend/build-info.json +2 -2
  55. package/dist/cli/backend/src/constants.d.ts +92 -0
  56. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  57. package/dist/cli/backend/src/constants.js +92 -0
  58. package/dist/cli/backend/src/constants.js.map +1 -1
  59. package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts +18 -3
  60. package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts.map +1 -1
  61. package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.js +28 -4
  62. package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.js.map +1 -1
  63. package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
  64. package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
  65. package/dist/cli/backend/src/services/cloud/cloud-sync.types.js +1 -0
  66. package/dist/cli/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
  67. package/dist/cli/backend/src/services/v3/request.service.d.ts +19 -0
  68. package/dist/cli/backend/src/services/v3/request.service.d.ts.map +1 -1
  69. package/dist/cli/backend/src/services/v3/request.service.js +36 -0
  70. package/dist/cli/backend/src/services/v3/request.service.js.map +1 -1
  71. package/package.json +1 -1
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Worktree Janitor Routes
3
+ *
4
+ * Debug and manual-trigger endpoints for {@link WorktreeJanitorService},
5
+ * mounted at `/api/worktree-janitor` behind the same API-token middleware as
6
+ * every other `/api` route.
7
+ *
8
+ * - `GET /api/worktree-janitor/worktrees` — dry run: every worktree of every
9
+ * known repo with its keep/remove verdict and reason. Removes nothing.
10
+ * - `POST /api/worktree-janitor/run` — one real pass now. Refused (409) while
11
+ * the `CREWLY_WORKTREE_JANITOR=0` kill switch is on.
12
+ *
13
+ * @module controllers/worktree-janitor/worktree-janitor.routes
14
+ */
15
+ import { Router } from 'express';
16
+ import { WorktreeJanitorService } from '../../services/worktree/worktree-janitor.service.js';
17
+ /**
18
+ * Create the worktree janitor router.
19
+ *
20
+ * @param getService - Service accessor (tests inject their own)
21
+ * @returns Express router for /api/worktree-janitor
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * router.use('/worktree-janitor', createWorktreeJanitorRouter());
26
+ * ```
27
+ */
28
+ export declare function createWorktreeJanitorRouter(getService?: () => WorktreeJanitorService): Router;
29
+ //# sourceMappingURL=worktree-janitor.routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-janitor.routes.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/worktree-janitor/worktree-janitor.routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,MAAM,EAA+B,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,qDAAqD,CAAC;AAG7F;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAC1C,UAAU,GAAE,MAAM,sBAAmE,GACnF,MAAM,CAkCR"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Worktree Janitor Routes
3
+ *
4
+ * Debug and manual-trigger endpoints for {@link WorktreeJanitorService},
5
+ * mounted at `/api/worktree-janitor` behind the same API-token middleware as
6
+ * every other `/api` route.
7
+ *
8
+ * - `GET /api/worktree-janitor/worktrees` — dry run: every worktree of every
9
+ * known repo with its keep/remove verdict and reason. Removes nothing.
10
+ * - `POST /api/worktree-janitor/run` — one real pass now. Refused (409) while
11
+ * the `CREWLY_WORKTREE_JANITOR=0` kill switch is on.
12
+ *
13
+ * @module controllers/worktree-janitor/worktree-janitor.routes
14
+ */
15
+ import { Router } from 'express';
16
+ import { WorktreeJanitorService } from '../../services/worktree/worktree-janitor.service.js';
17
+ import { WORKTREE_JANITOR_CONSTANTS } from '../../constants.js';
18
+ /**
19
+ * Create the worktree janitor router.
20
+ *
21
+ * @param getService - Service accessor (tests inject their own)
22
+ * @returns Express router for /api/worktree-janitor
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * router.use('/worktree-janitor', createWorktreeJanitorRouter());
27
+ * ```
28
+ */
29
+ export function createWorktreeJanitorRouter(getService = () => WorktreeJanitorService.getInstance()) {
30
+ const router = Router();
31
+ router.get('/worktrees', async (_req, res) => {
32
+ try {
33
+ const service = getService();
34
+ const plan = await service.plan();
35
+ res.json({
36
+ success: true,
37
+ data: { ...plan, disabled: service.isDisabled(), lastRun: service.getLastSummary() },
38
+ });
39
+ }
40
+ catch (error) {
41
+ res.status(500).json({ success: false, error: error instanceof Error ? error.message : String(error) });
42
+ }
43
+ });
44
+ router.post('/run', async (_req, res) => {
45
+ try {
46
+ const service = getService();
47
+ if (service.isDisabled()) {
48
+ res.status(409).json({
49
+ success: false,
50
+ error: `Worktree janitor is disabled (${WORKTREE_JANITOR_CONSTANTS.ENV_VAR}=0)`,
51
+ });
52
+ return;
53
+ }
54
+ const summary = await service.run();
55
+ res.json({ success: true, data: summary });
56
+ }
57
+ catch (error) {
58
+ res.status(500).json({ success: false, error: error instanceof Error ? error.message : String(error) });
59
+ }
60
+ });
61
+ return router;
62
+ }
63
+ //# sourceMappingURL=worktree-janitor.routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-janitor.routes.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/worktree-janitor/worktree-janitor.routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,MAAM,EAA+B,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,qDAAqD,CAAC;AAC7F,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAEhE;;;;;;;;;;GAUG;AACH,MAAM,UAAU,2BAA2B,CAC1C,aAA2C,GAAG,EAAE,CAAC,sBAAsB,CAAC,WAAW,EAAE;IAErF,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,EAAE,IAAa,EAAE,GAAa,EAAE,EAAE;QAC/D,IAAI,CAAC;YACJ,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;YAClC,GAAG,CAAC,IAAI,CAAC;gBACR,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,cAAc,EAAE,EAAE;aACpF,CAAC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACzG,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAa,EAAE,GAAa,EAAE,EAAE;QAC1D,IAAI,CAAC;YACJ,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;YAC7B,IAAI,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;gBAC1B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBACpB,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,iCAAiC,0BAA0B,CAAC,OAAO,KAAK;iBAC/E,CAAC,CAAC;gBACH,OAAO;YACR,CAAC;YACD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC;YACpC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACzG,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AACf,CAAC"}
@@ -46,6 +46,7 @@ export declare class CrewlyServer {
46
46
  /** Tells the owner on Slack when this machine loses Crewly Cloud */
47
47
  private cloudDisconnectNotice;
48
48
  private conversationCloudSync;
49
+ private waitingItemsSync;
49
50
  /** Epoch ms of the last shutdown signal acted on (dedups process-group delivery) */
50
51
  private lastShutdownSignalAt;
51
52
  /** Interrupted turns loaded at boot, resumed once their agents are back */
@@ -168,6 +169,12 @@ export declare class CrewlyServer {
168
169
  * first time history reaches Cloud. Never throws.
169
170
  */
170
171
  private startConversationCloudSync;
172
+ /**
173
+ * Start the "waiting on you" uploader: tickets in 待验收 go to Crewly Cloud
174
+ * as text snapshots when they change (and every 5 minutes), so the portal
175
+ * lists what waits on the owner across machines. Never throws.
176
+ */
177
+ private startWaitingItemsSync;
171
178
  /**
172
179
  * Load interrupted turns left by the previous shutdown (fresh ones only).
173
180
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../backend/src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../backend/src/index.ts"],"names":[],"mappings":"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"}
@@ -113,6 +113,7 @@ import { createCloudDisconnectNoticeService, } from './services/cloud/cloud-disc
113
113
  import { isNoticeEnabled } from './services/cloud/cloud-disconnect-notice.utils.js';
114
114
  import { createOwnerDirectDm } from './services/slack/slack-owner-direct-dm.js';
115
115
  import { LogRotationService } from './services/session/log-rotation.service.js';
116
+ import { WorktreeJanitorService } from './services/worktree/worktree-janitor.service.js';
116
117
  import { AuditorSchedulerService } from './services/agent/auditor-scheduler.service.js';
117
118
  import { setAuditorSchedulerService } from './controllers/auditor/auditor.controller.js';
118
119
  import { AddonLoaderService } from './services/addon/addon-loader.service.js';
@@ -218,6 +219,7 @@ export class CrewlyServer {
218
219
  /** Tells the owner on Slack when this machine loses Crewly Cloud */
219
220
  cloudDisconnectNotice = null;
220
221
  conversationCloudSync = null;
222
+ waitingItemsSync = null;
221
223
  /** Epoch ms of the last shutdown signal acted on (dedups process-group delivery) */
222
224
  lastShutdownSignalAt = 0;
223
225
  /** Interrupted turns loaded at boot, resumed once their agents are back */
@@ -1955,6 +1957,38 @@ export class CrewlyServer {
1955
1957
  error: talkErr instanceof Error ? talkErr.message : String(talkErr),
1956
1958
  });
1957
1959
  }
1960
+ // "Waiting on you" (specs/unified-conversations-cloud-store.md §F):
1961
+ // the owner's accept / send-back from the portal arrives as a
1962
+ // `waiting_action` push; the handler fetches it with this
1963
+ // machine's token and runs it through the ticket review.
1964
+ // Starting it is what advertises `waiting_actions` to Cloud.
1965
+ try {
1966
+ const [{ WaitingActionsInboundService }, { CloudClientService }, { getWaitingItemsSyncService },] = await Promise.all([
1967
+ import('./services/cloud/waiting-actions-inbound.service.js'),
1968
+ import('./services/cloud/cloud-client.service.js'),
1969
+ import('./services/cloud/waiting-items-sync.service.js'),
1970
+ ]);
1971
+ const cloudClient = CloudClientService.getInstance();
1972
+ new WaitingActionsInboundService({
1973
+ source: sync,
1974
+ cloud: {
1975
+ getToken: () => cloudClient.getToken(),
1976
+ getCloudUrl: () => cloudClient.getCloudUrl(),
1977
+ tryRefreshToken: () => cloudClient.tryRefreshToken(),
1978
+ },
1979
+ review: () => getTicketReviewService(),
1980
+ identity: async () => {
1981
+ const id = await DeviceIdentityService.getInstance().getOrCreateIdentity();
1982
+ return { instanceId: id.deviceId, deviceName: id.deviceName };
1983
+ },
1984
+ requestResync: () => getWaitingItemsSyncService()?.requestSync(),
1985
+ }).start();
1986
+ }
1987
+ catch (waitingErr) {
1988
+ this.logger.warn('"Waiting on you" action handler wiring skipped', {
1989
+ error: waitingErr instanceof Error ? waitingErr.message : String(waitingErr),
1990
+ });
1991
+ }
1958
1992
  // Mobile app: generic allowlisted REST passthrough over the same
1959
1993
  // relay (api_request → local HTTP → api_response). Non-fatal.
1960
1994
  try {
@@ -2625,6 +2659,9 @@ export class CrewlyServer {
2625
2659
  // specs/unified-conversations-cloud-store.md §B). On by default for a
2626
2660
  // signed-in machine; CREWLY_CONVERSATION_SYNC=0 turns it off.
2627
2661
  void this.startConversationCloudSync();
2662
+ // "Waiting on you" (§F): tickets in 待验收 go to Crewly Cloud as text
2663
+ // snapshots, so the portal lists them for every machine.
2664
+ void this.startWaitingItemsSync();
2628
2665
  // V3-only as of spec 2026-05-06-task-management-v1-deprecation.md.
2629
2666
  // The legacy `TaskTrackingService.startAutoSync()` is gone — V3
2630
2667
  // task-pool reconciler owns lifecycle cleanup now.
@@ -2829,6 +2866,22 @@ export class CrewlyServer {
2829
2866
  error: error instanceof Error ? error.message : String(error),
2830
2867
  });
2831
2868
  }
2869
+ // Worktree janitor (non-critical): removes finished agent worktrees
2870
+ // (merged + clean + idle >2h + nobody inside). Kill switch:
2871
+ // CREWLY_WORKTREE_JANITOR=0.
2872
+ try {
2873
+ if (WorktreeJanitorService.getInstance().start()) {
2874
+ this.logger.info('WorktreeJanitorService scheduled');
2875
+ }
2876
+ else {
2877
+ this.logger.info('WorktreeJanitorService disabled (CREWLY_WORKTREE_JANITOR)');
2878
+ }
2879
+ }
2880
+ catch (error) {
2881
+ this.logger.warn('Failed to start WorktreeJanitorService (non-critical)', {
2882
+ error: error instanceof Error ? error.message : String(error),
2883
+ });
2884
+ }
2832
2885
  // Start AuditorSchedulerService (non-critical — audit scheduling)
2833
2886
  // Priority: env var > settings.json > ENABLED_BY_DEFAULT constant
2834
2887
  const envValue = process.env[AUDITOR_CONSTANTS.ENV_VAR]?.toLowerCase();
@@ -3766,12 +3819,13 @@ export class CrewlyServer {
3766
3819
  */
3767
3820
  async startConversationCloudSync() {
3768
3821
  try {
3769
- const [{ ConversationCloudSyncService, setConversationCloudSyncService }, { CloudClientService }, { VersionCheckService }, { buildAgentRoster }, { cloudTalkCapabilities },] = await Promise.all([
3822
+ const [{ ConversationCloudSyncService, setConversationCloudSyncService }, { CloudClientService }, { VersionCheckService }, { buildAgentRoster }, { cloudTalkCapabilities }, { waitingActionCapabilities },] = await Promise.all([
3770
3823
  import('./services/cloud/conversation-cloud-sync.service.js'),
3771
3824
  import('./services/cloud/cloud-client.service.js'),
3772
3825
  import('./services/system/version-check.service.js'),
3773
3826
  import('./services/cloud/agent-roster.utils.js'),
3774
3827
  import('./services/cloud/cloud-talk-inbound.service.js'),
3828
+ import('./services/cloud/waiting-actions-inbound.service.js'),
3775
3829
  ]);
3776
3830
  const chat = getChatV2Service();
3777
3831
  const cloud = CloudClientService.getInstance();
@@ -3792,7 +3846,7 @@ export class CrewlyServer {
3792
3846
  // whether this machine takes `talk_message` — also for machines
3793
3847
  // without Slack, which never send the registry heartbeat.
3794
3848
  roster: async () => buildAgentRoster(await this.storageService.getTeams()),
3795
- capabilities: () => cloudTalkCapabilities(),
3849
+ capabilities: () => [...cloudTalkCapabilities(), ...waitingActionCapabilities()],
3796
3850
  onNewMessage: (listener) => {
3797
3851
  chat.on('chat_message', listener);
3798
3852
  return () => chat.off('chat_message', listener);
@@ -3821,6 +3875,61 @@ export class CrewlyServer {
3821
3875
  });
3822
3876
  }
3823
3877
  }
3878
+ /**
3879
+ * Start the "waiting on you" uploader: tickets in 待验收 go to Crewly Cloud
3880
+ * as text snapshots when they change (and every 5 minutes), so the portal
3881
+ * lists what waits on the owner across machines. Never throws.
3882
+ */
3883
+ async startWaitingItemsSync() {
3884
+ try {
3885
+ const [{ WaitingItemsSyncService, setWaitingItemsSyncService }, { CloudClientService }, { VersionCheckService }, { buildAgentRoster }, { cloudTalkCapabilities }, { waitingActionCapabilities }, { getTicketIntakeService },] = await Promise.all([
3886
+ import('./services/cloud/waiting-items-sync.service.js'),
3887
+ import('./services/cloud/cloud-client.service.js'),
3888
+ import('./services/system/version-check.service.js'),
3889
+ import('./services/cloud/agent-roster.utils.js'),
3890
+ import('./services/cloud/cloud-talk-inbound.service.js'),
3891
+ import('./services/cloud/waiting-actions-inbound.service.js'),
3892
+ import('./services/v3/ticket-intake.service.js'),
3893
+ ]);
3894
+ const cloud = CloudClientService.getInstance();
3895
+ const service = new WaitingItemsSyncService({
3896
+ listWaiting: async () => {
3897
+ const intake = getTicketIntakeService();
3898
+ // Never upload an empty set just because tickets are not wired yet.
3899
+ if (!intake)
3900
+ throw new Error('ticket service is not ready');
3901
+ // Only tickets that can be in 待验收 need their WorkItems looked up
3902
+ // (this runs every 30 s; done / cancelled / no-review tickets never are).
3903
+ const candidates = (await RequestService.getInstance().listAll()).filter((r) => typeof r.ticketNumber === 'number' && r.requiresConfirmation && r.status !== 'done' && r.status !== 'cancelled');
3904
+ const rows = await Promise.all(candidates.map((r) => intake.toListItem(r)));
3905
+ return rows.filter((row) => row.column === 'to_review');
3906
+ },
3907
+ cloud: {
3908
+ getToken: () => cloud.getToken(),
3909
+ getCloudUrl: () => cloud.getCloudUrl(),
3910
+ tryRefreshToken: () => cloud.tryRefreshToken(),
3911
+ },
3912
+ identity: async () => {
3913
+ const id = await DeviceIdentityService.getInstance().getOrCreateIdentity();
3914
+ return { instanceId: id.deviceId, deviceName: id.deviceName };
3915
+ },
3916
+ crewlyVersion: async () => VersionCheckService.getInstance().getLocalVersion(),
3917
+ agentNames: async () => new Map(buildAgentRoster(await this.storageService.getTeams())
3918
+ .filter((a) => a.displayName)
3919
+ .map((a) => [a.agentSession, a.displayName])),
3920
+ capabilities: () => [...cloudTalkCapabilities(), ...waitingActionCapabilities()],
3921
+ onTicketChange: (listener) => RequestService.getInstance().onChange(() => listener()),
3922
+ });
3923
+ setWaitingItemsSyncService(service);
3924
+ service.start();
3925
+ this.waitingItemsSync = service;
3926
+ }
3927
+ catch (error) {
3928
+ this.logger.warn('"Waiting on you" sync not started (non-fatal)', {
3929
+ error: error instanceof Error ? error.message : String(error),
3930
+ });
3931
+ }
3932
+ }
3824
3933
  /**
3825
3934
  * Load interrupted turns left by the previous shutdown (fresh ones only).
3826
3935
  */
@@ -4248,6 +4357,7 @@ export class CrewlyServer {
4248
4357
  AutoUpdateService.getInstance()?.stop();
4249
4358
  this.cloudDisconnectNotice?.stop();
4250
4359
  this.conversationCloudSync?.stop();
4360
+ this.waitingItemsSync?.stop();
4251
4361
  // Safe restart: stop delivering, wait for agents mid-turn, persist the rest.
4252
4362
  // Runs before the force-exit timer below, which only bounds the teardown.
4253
4363
  await this.drainInFlightTurns(options.reason ?? 'shutdown', options.drain !== false);
@@ -4482,6 +4592,8 @@ export class CrewlyServer {
4482
4592
  this.teamsJsonWatcherService.stop();
4483
4593
  // Stop log rotation service
4484
4594
  LogRotationService.getInstance().stop();
4595
+ // Stop worktree janitor timers
4596
+ WorktreeJanitorService.getInstance().stop();
4485
4597
  // Stop auditor scheduler
4486
4598
  AuditorSchedulerService.getInstance().stop();
4487
4599
  // Persist the token ledger: it flushes every 5 minutes, so a restart