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.
- package/config/roles/orchestrator/prompt.md +7 -0
- package/config/roles/team-leader/prompt.md +6 -0
- package/config/sops/developer/git-workflow.md +1 -0
- package/dist/backend/backend/src/constants.d.ts +92 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +92 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/worktree-janitor/worktree-janitor.routes.d.ts +29 -0
- package/dist/backend/backend/src/controllers/worktree-janitor/worktree-janitor.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/worktree-janitor/worktree-janitor.routes.js +63 -0
- package/dist/backend/backend/src/controllers/worktree-janitor/worktree-janitor.routes.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts +7 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +114 -2
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +3 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts +18 -3
- package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.js +28 -4
- package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.js +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/waiting-actions-inbound.service.d.ts +128 -0
- package/dist/backend/backend/src/services/cloud/waiting-actions-inbound.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/waiting-actions-inbound.service.js +279 -0
- package/dist/backend/backend/src/services/cloud/waiting-actions-inbound.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/waiting-items-sync.service.d.ts +122 -0
- package/dist/backend/backend/src/services/cloud/waiting-items-sync.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/waiting-items-sync.service.js +261 -0
- package/dist/backend/backend/src/services/cloud/waiting-items-sync.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/waiting-items.contract.d.ts +101 -0
- package/dist/backend/backend/src/services/cloud/waiting-items.contract.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/waiting-items.contract.js +113 -0
- package/dist/backend/backend/src/services/cloud/waiting-items.contract.js.map +1 -0
- package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.js +2 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request.service.d.ts +19 -0
- package/dist/backend/backend/src/services/v3/request.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/request.service.js +36 -0
- package/dist/backend/backend/src/services/v3/request.service.js.map +1 -1
- package/dist/backend/backend/src/services/worktree/worktree-janitor.git.d.ts +131 -0
- package/dist/backend/backend/src/services/worktree/worktree-janitor.git.d.ts.map +1 -0
- package/dist/backend/backend/src/services/worktree/worktree-janitor.git.js +238 -0
- package/dist/backend/backend/src/services/worktree/worktree-janitor.git.js.map +1 -0
- package/dist/backend/backend/src/services/worktree/worktree-janitor.service.d.ts +241 -0
- package/dist/backend/backend/src/services/worktree/worktree-janitor.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/worktree/worktree-janitor.service.js +504 -0
- package/dist/backend/backend/src/services/worktree/worktree-janitor.service.js.map +1 -0
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +92 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +92 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts +18 -3
- package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.js +28 -4
- package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.js.map +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.js +1 -0
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
- package/dist/cli/backend/src/services/v3/request.service.d.ts +19 -0
- package/dist/cli/backend/src/services/v3/request.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/v3/request.service.js +36 -0
- package/dist/cli/backend/src/services/v3/request.service.js.map +1 -1
- 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
|
package/dist/backend/backend/src/controllers/worktree-janitor/worktree-janitor.routes.d.ts.map
ADDED
|
@@ -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":";AA2CA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
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
|