crewly 1.20.108 → 1.20.110
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/skills/agent/core/complete-task/SKILL.md +11 -0
- package/config/skills/agent/core/complete-task/execute.sh +16 -1
- package/config/skills/agent/core/complete-task/execute.test.sh +19 -0
- package/config/skills/agent/core/ticket-check/SKILL.md +62 -0
- package/config/skills/agent/core/ticket-check/execute.sh +71 -0
- package/config/skills/agent/core/ticket-check/execute.test.sh +69 -0
- package/dist/backend/backend/src/constants.d.ts +36 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +36 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/tickets/tickets.controller.d.ts +42 -0
- package/dist/backend/backend/src/controllers/tickets/tickets.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/tickets/tickets.controller.js +185 -0
- package/dist/backend/backend/src/controllers/tickets/tickets.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/tickets/tickets.routes.d.ts +7 -0
- package/dist/backend/backend/src/controllers/tickets/tickets.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/tickets/tickets.routes.js +16 -1
- package/dist/backend/backend/src/controllers/tickets/tickets.routes.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +84 -3
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/cache/redis-cache.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cache/redis-cache.service.js +8 -1
- package/dist/backend/backend/src/services/cache/redis-cache.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js +1 -1
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts +24 -0
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +83 -3
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js +6 -0
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js +2 -2
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +2 -2
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/backend/backend/src/services/system/version-check.service.d.ts +7 -1
- package/dist/backend/backend/src/services/system/version-check.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/system/version-check.service.js +10 -3
- package/dist/backend/backend/src/services/system/version-check.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +35 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js +88 -6
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/ticket-claim-policy.d.ts +92 -0
- package/dist/backend/backend/src/services/task-pool/ticket-claim-policy.d.ts.map +1 -0
- package/dist/backend/backend/src/services/task-pool/ticket-claim-policy.js +168 -0
- package/dist/backend/backend/src/services/task-pool/ticket-claim-policy.js.map +1 -0
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.js +24 -12
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request-decompose.subscriber.d.ts +8 -0
- package/dist/backend/backend/src/services/v3/request-decompose.subscriber.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/request-decompose.subscriber.js +40 -0
- package/dist/backend/backend/src/services/v3/request-decompose.subscriber.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.js +9 -0
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request.service.d.ts +10 -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 +51 -0
- package/dist/backend/backend/src/services/v3/request.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/ticket-channel-hooks.d.ts +17 -0
- package/dist/backend/backend/src/services/v3/ticket-channel-hooks.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/ticket-channel-hooks.js +52 -5
- package/dist/backend/backend/src/services/v3/ticket-channel-hooks.js.map +1 -1
- package/dist/backend/backend/src/services/v3/ticket-intake.service.d.ts +63 -1
- package/dist/backend/backend/src/services/v3/ticket-intake.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/ticket-intake.service.js +67 -1
- package/dist/backend/backend/src/services/v3/ticket-intake.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/ticket-review.service.d.ts +242 -0
- package/dist/backend/backend/src/services/v3/ticket-review.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/ticket-review.service.js +456 -0
- package/dist/backend/backend/src/services/v3/ticket-review.service.js.map +1 -0
- package/dist/backend/backend/src/types/v2/index.d.ts +1 -1
- package/dist/backend/backend/src/types/v2/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/index.js.map +1 -1
- package/dist/backend/backend/src/types/v2/request.types.d.ts +21 -1
- package/dist/backend/backend/src/types/v2/request.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/request.types.js +3 -2
- package/dist/backend/backend/src/types/v2/request.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/ticket.types.d.ts +71 -1
- package/dist/backend/backend/src/types/v2/ticket.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/ticket.types.js +40 -0
- package/dist/backend/backend/src/types/v2/ticket.types.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +36 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +36 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js +2 -2
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +2 -2
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +35 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js +88 -6
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/ticket-claim-policy.d.ts +92 -0
- package/dist/cli/backend/src/services/task-pool/ticket-claim-policy.d.ts.map +1 -0
- package/dist/cli/backend/src/services/task-pool/ticket-claim-policy.js +168 -0
- package/dist/cli/backend/src/services/task-pool/ticket-claim-policy.js.map +1 -0
- package/dist/cli/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -1
- package/dist/cli/backend/src/services/v3/request-sla.subscriber.js +9 -0
- package/dist/cli/backend/src/services/v3/request-sla.subscriber.js.map +1 -1
- package/dist/cli/backend/src/services/v3/request.service.d.ts +10 -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 +51 -0
- package/dist/cli/backend/src/services/v3/request.service.js.map +1 -1
- package/dist/cli/backend/src/services/v3/ticket-channel-hooks.d.ts +17 -0
- package/dist/cli/backend/src/services/v3/ticket-channel-hooks.d.ts.map +1 -1
- package/dist/cli/backend/src/services/v3/ticket-channel-hooks.js +52 -5
- package/dist/cli/backend/src/services/v3/ticket-channel-hooks.js.map +1 -1
- package/dist/cli/backend/src/services/v3/ticket-intake.service.d.ts +63 -1
- package/dist/cli/backend/src/services/v3/ticket-intake.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/v3/ticket-intake.service.js +67 -1
- package/dist/cli/backend/src/services/v3/ticket-intake.service.js.map +1 -1
- package/dist/cli/backend/src/services/v3/ticket-review.service.d.ts +242 -0
- package/dist/cli/backend/src/services/v3/ticket-review.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/v3/ticket-review.service.js +456 -0
- package/dist/cli/backend/src/services/v3/ticket-review.service.js.map +1 -0
- package/dist/cli/backend/src/types/v2/index.d.ts +1 -1
- package/dist/cli/backend/src/types/v2/index.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/index.js.map +1 -1
- package/dist/cli/backend/src/types/v2/request.types.d.ts +21 -1
- package/dist/cli/backend/src/types/v2/request.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/request.types.js +3 -2
- package/dist/cli/backend/src/types/v2/request.types.js.map +1 -1
- package/dist/cli/backend/src/types/v2/ticket.types.d.ts +71 -1
- package/dist/cli/backend/src/types/v2/ticket.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/ticket.types.js +40 -0
- package/dist/cli/backend/src/types/v2/ticket.types.js.map +1 -1
- package/frontend/dist/assets/{index-f7b99e81.js → index-07e338a9.js} +284 -284
- package/frontend/dist/assets/index-8327e63e.css +42 -0
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/frontend/dist/assets/index-413c5813.css +0 -42
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
* - GET /api/tickets?column=&q=&kind=&includeLegacy= — board-shaped list
|
|
6
6
|
* - GET /api/tickets/:tkt — one ticket by `TKT-123`, `123` or id
|
|
7
7
|
* - POST /api/tickets/:id/dismiss — the "不用记" action
|
|
8
|
+
* - POST /api/tickets/:id/verify — 验过了 (Phase 2)
|
|
9
|
+
* - POST /api/tickets/:id/reject { reason } — 打回 (Phase 2)
|
|
10
|
+
* - PUT /api/tickets/:id/acceptance { items } — replace acceptance list (Phase 2)
|
|
11
|
+
* - POST /api/tickets/:id/self-check { index, result, evidence } — agent self-check (Phase 2)
|
|
12
|
+
* - PATCH /api/tickets/:id { title, priority, kind, assignee } — board edits (Phase 2)
|
|
8
13
|
*
|
|
9
14
|
* @module controllers/tickets/tickets.controller
|
|
10
15
|
*/
|
|
@@ -38,4 +43,41 @@ export declare function getTicket(req: ExpressRequest, res: Response): Promise<v
|
|
|
38
43
|
* @param res - `{ success, data: ticket, alreadyDismissed }`, 404, 403 or 409
|
|
39
44
|
*/
|
|
40
45
|
export declare function dismissTicket(req: ExpressRequest, res: Response): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* POST /api/tickets/:id/verify — 验过了. Owner only.
|
|
48
|
+
*
|
|
49
|
+
* @param req - Express request with `id` param
|
|
50
|
+
* @param res - `{ success, data: ticket }`, 403, 404 or 409
|
|
51
|
+
*/
|
|
52
|
+
export declare function verifyTicket(req: ExpressRequest, res: Response): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* POST /api/tickets/:id/reject — 打回 with a required reason. Owner only.
|
|
55
|
+
* The reason becomes an acceptance criterion and a rework WorkItem is queued.
|
|
56
|
+
*
|
|
57
|
+
* @param req - Express request with `id` param and body `{ reason }`
|
|
58
|
+
* @param res - `{ success, data: ticket }`, 400, 403, 404 or 409
|
|
59
|
+
*/
|
|
60
|
+
export declare function rejectTicket(req: ExpressRequest, res: Response): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* PUT /api/tickets/:id/acceptance — replace the live acceptance list. Owner only.
|
|
63
|
+
*
|
|
64
|
+
* @param req - Express request with body `{ items: [{ text, check? }] }`
|
|
65
|
+
* @param res - `{ success, data: ticket }`, 400, 403 or 404
|
|
66
|
+
*/
|
|
67
|
+
export declare function setTicketAcceptance(req: ExpressRequest, res: Response): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* POST /api/tickets/:id/self-check — an agent records its check of one
|
|
70
|
+
* criterion. Agents may call this.
|
|
71
|
+
*
|
|
72
|
+
* @param req - Express request with body `{ index, result: 'pass'|'fail', evidence? }`
|
|
73
|
+
* @param res - `{ success, data: ticket }`, 400 or 404
|
|
74
|
+
*/
|
|
75
|
+
export declare function selfCheckTicket(req: ExpressRequest, res: Response): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* PATCH /api/tickets/:id — board edits (title, priority, kind, assignee). Owner only.
|
|
78
|
+
*
|
|
79
|
+
* @param req - Express request with a partial body
|
|
80
|
+
* @param res - `{ success, data: ticket }`, 400, 403 or 404
|
|
81
|
+
*/
|
|
82
|
+
export declare function patchTicket(req: ExpressRequest, res: Response): Promise<void>;
|
|
41
83
|
//# sourceMappingURL=tickets.controller.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tickets.controller.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/tickets/tickets.controller.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tickets.controller.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/tickets/tickets.controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,OAAO,IAAI,cAAc,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAyCnE;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBnF;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAajF;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBrF;AAyFD;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpF;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAQpF;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB3F;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CASvF;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAanF"}
|
|
@@ -5,12 +5,18 @@
|
|
|
5
5
|
* - GET /api/tickets?column=&q=&kind=&includeLegacy= — board-shaped list
|
|
6
6
|
* - GET /api/tickets/:tkt — one ticket by `TKT-123`, `123` or id
|
|
7
7
|
* - POST /api/tickets/:id/dismiss — the "不用记" action
|
|
8
|
+
* - POST /api/tickets/:id/verify — 验过了 (Phase 2)
|
|
9
|
+
* - POST /api/tickets/:id/reject { reason } — 打回 (Phase 2)
|
|
10
|
+
* - PUT /api/tickets/:id/acceptance { items } — replace acceptance list (Phase 2)
|
|
11
|
+
* - POST /api/tickets/:id/self-check { index, result, evidence } — agent self-check (Phase 2)
|
|
12
|
+
* - PATCH /api/tickets/:id { title, priority, kind, assignee } — board edits (Phase 2)
|
|
8
13
|
*
|
|
9
14
|
* @module controllers/tickets/tickets.controller
|
|
10
15
|
*/
|
|
11
16
|
import { getTicketIntakeService, } from '../../services/v3/ticket-intake.service.js';
|
|
12
17
|
import { isTicketBoardColumn, isTicketKind } from '../../types/v2/ticket.types.js';
|
|
13
18
|
import { readAgentSessionHeader } from '../../utils/agent-caller.utils.js';
|
|
19
|
+
import { getTicketReviewService, } from '../../services/v3/ticket-review.service.js';
|
|
14
20
|
/**
|
|
15
21
|
* The wired intake service, or a 503 when boot has not wired it.
|
|
16
22
|
*
|
|
@@ -132,4 +138,183 @@ export async function dismissTicket(req, res) {
|
|
|
132
138
|
res.status(500).json({ success: false, error: error.message });
|
|
133
139
|
}
|
|
134
140
|
}
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
// Phase 2 — review
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
/** HTTP status for each refusal. */
|
|
145
|
+
const REVIEW_REFUSAL_STATUS = {
|
|
146
|
+
not_found: 404,
|
|
147
|
+
invalid: 400,
|
|
148
|
+
not_in_review: 409,
|
|
149
|
+
already_done: 409,
|
|
150
|
+
cancelled: 409,
|
|
151
|
+
open_work: 409,
|
|
152
|
+
};
|
|
153
|
+
/** Human text for each refusal. */
|
|
154
|
+
const REVIEW_REFUSAL_TEXT = {
|
|
155
|
+
not_found: 'Ticket not found',
|
|
156
|
+
invalid: 'Invalid input',
|
|
157
|
+
not_in_review: 'Ticket is not waiting for review',
|
|
158
|
+
already_done: 'Ticket is already done',
|
|
159
|
+
cancelled: 'Ticket was cancelled',
|
|
160
|
+
open_work: 'Ticket still has open work items',
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* The wired review service, or a 503.
|
|
164
|
+
*
|
|
165
|
+
* @param res - Response to write the 503 to
|
|
166
|
+
* @returns The service, or null after responding
|
|
167
|
+
*/
|
|
168
|
+
function reviewOr503(res) {
|
|
169
|
+
const svc = getTicketReviewService();
|
|
170
|
+
if (!svc) {
|
|
171
|
+
res.status(503).json({ success: false, error: 'Ticket review is not ready' });
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
return svc;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Refuse a call made by an agent (owner-only actions).
|
|
178
|
+
*
|
|
179
|
+
* @param req - Express request
|
|
180
|
+
* @param res - Response
|
|
181
|
+
* @param what - What is owner-only (for the message)
|
|
182
|
+
* @returns True when refused
|
|
183
|
+
*/
|
|
184
|
+
function refuseAgent(req, res, what) {
|
|
185
|
+
if (!readAgentSessionHeader(req))
|
|
186
|
+
return false;
|
|
187
|
+
res.status(403).json({ success: false, error: `Only the owner can ${what}` });
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Write a review action's result.
|
|
192
|
+
*
|
|
193
|
+
* @param res - Response
|
|
194
|
+
* @param result - The result
|
|
195
|
+
*/
|
|
196
|
+
function sendReviewResult(res, result) {
|
|
197
|
+
if (result.ok) {
|
|
198
|
+
res.json({ success: true, data: result.ticket });
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
res.status(REVIEW_REFUSAL_STATUS[result.reason]).json({
|
|
202
|
+
success: false,
|
|
203
|
+
error: REVIEW_REFUSAL_TEXT[result.reason],
|
|
204
|
+
code: result.reason,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Run a review handler with the shared 503 / 500 handling.
|
|
209
|
+
*
|
|
210
|
+
* @param res - Response
|
|
211
|
+
* @param fn - The action
|
|
212
|
+
*/
|
|
213
|
+
async function runReview(res, fn) {
|
|
214
|
+
const svc = reviewOr503(res);
|
|
215
|
+
if (!svc)
|
|
216
|
+
return;
|
|
217
|
+
try {
|
|
218
|
+
sendReviewResult(res, await fn(svc));
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
res.status(500).json({ success: false, error: error.message });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* POST /api/tickets/:id/verify — 验过了. Owner only.
|
|
226
|
+
*
|
|
227
|
+
* @param req - Express request with `id` param
|
|
228
|
+
* @param res - `{ success, data: ticket }`, 403, 404 or 409
|
|
229
|
+
*/
|
|
230
|
+
export async function verifyTicket(req, res) {
|
|
231
|
+
if (refuseAgent(req, res, 'accept a ticket'))
|
|
232
|
+
return;
|
|
233
|
+
await runReview(res, (svc) => svc.verify(req.params.id ?? ''));
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* POST /api/tickets/:id/reject — 打回 with a required reason. Owner only.
|
|
237
|
+
* The reason becomes an acceptance criterion and a rework WorkItem is queued.
|
|
238
|
+
*
|
|
239
|
+
* @param req - Express request with `id` param and body `{ reason }`
|
|
240
|
+
* @param res - `{ success, data: ticket }`, 400, 403, 404 or 409
|
|
241
|
+
*/
|
|
242
|
+
export async function rejectTicket(req, res) {
|
|
243
|
+
if (refuseAgent(req, res, 'send a ticket back'))
|
|
244
|
+
return;
|
|
245
|
+
const reason = typeof req.body?.reason === 'string' ? req.body.reason.trim() : '';
|
|
246
|
+
if (!reason) {
|
|
247
|
+
res.status(400).json({ success: false, error: 'A reason is required', code: 'invalid' });
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
await runReview(res, (svc) => svc.reject(req.params.id ?? '', reason, 'board'));
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* PUT /api/tickets/:id/acceptance — replace the live acceptance list. Owner only.
|
|
254
|
+
*
|
|
255
|
+
* @param req - Express request with body `{ items: [{ text, check? }] }`
|
|
256
|
+
* @param res - `{ success, data: ticket }`, 400, 403 or 404
|
|
257
|
+
*/
|
|
258
|
+
export async function setTicketAcceptance(req, res) {
|
|
259
|
+
if (refuseAgent(req, res, 'edit acceptance criteria'))
|
|
260
|
+
return;
|
|
261
|
+
const raw = req.body?.items;
|
|
262
|
+
if (!Array.isArray(raw)) {
|
|
263
|
+
res.status(400).json({ success: false, error: '`items` must be an array', code: 'invalid' });
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
const items = [];
|
|
267
|
+
for (const entry of raw) {
|
|
268
|
+
const text = typeof entry === 'string' ? entry : entry?.text;
|
|
269
|
+
const check = typeof entry === 'object' && entry ? entry.check : undefined;
|
|
270
|
+
if (typeof text !== 'string') {
|
|
271
|
+
res.status(400).json({ success: false, error: 'Each item needs a `text`', code: 'invalid' });
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
items.push({ text, ...(check === 'auto' || check === 'judgment' ? { check } : {}) });
|
|
275
|
+
}
|
|
276
|
+
await runReview(res, (svc) => svc.setAcceptance(req.params.id ?? '', items));
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* POST /api/tickets/:id/self-check — an agent records its check of one
|
|
280
|
+
* criterion. Agents may call this.
|
|
281
|
+
*
|
|
282
|
+
* @param req - Express request with body `{ index, result: 'pass'|'fail', evidence? }`
|
|
283
|
+
* @param res - `{ success, data: ticket }`, 400 or 404
|
|
284
|
+
*/
|
|
285
|
+
export async function selfCheckTicket(req, res) {
|
|
286
|
+
const index = Number(req.body?.index);
|
|
287
|
+
const result = req.body?.result;
|
|
288
|
+
const evidence = typeof req.body?.evidence === 'string' ? req.body.evidence : undefined;
|
|
289
|
+
if (!Number.isInteger(index) || index < 0 || (result !== 'pass' && result !== 'fail')) {
|
|
290
|
+
res.status(400).json({ success: false, error: '`index` (>= 0) and `result` (pass|fail) are required', code: 'invalid' });
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
await runReview(res, (svc) => svc.selfCheck(req.params.id ?? '', index, result, evidence));
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* PATCH /api/tickets/:id — board edits (title, priority, kind, assignee). Owner only.
|
|
297
|
+
*
|
|
298
|
+
* @param req - Express request with a partial body
|
|
299
|
+
* @param res - `{ success, data: ticket }`, 400, 403 or 404
|
|
300
|
+
*/
|
|
301
|
+
export async function patchTicket(req, res) {
|
|
302
|
+
if (refuseAgent(req, res, 'edit a ticket'))
|
|
303
|
+
return;
|
|
304
|
+
const body = (req.body ?? {});
|
|
305
|
+
const patch = {};
|
|
306
|
+
if (typeof body.title === 'string')
|
|
307
|
+
patch.title = body.title;
|
|
308
|
+
if (typeof body.priority === 'string')
|
|
309
|
+
patch.priority = body.priority;
|
|
310
|
+
if (typeof body.kind === 'string')
|
|
311
|
+
patch.kind = body.kind;
|
|
312
|
+
if (typeof body.assignee === 'string' || body.assignee === null)
|
|
313
|
+
patch.assignee = body.assignee;
|
|
314
|
+
if (Object.keys(patch).length === 0) {
|
|
315
|
+
res.status(400).json({ success: false, error: 'Nothing to change', code: 'invalid' });
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
await runReview(res, (svc) => svc.patch(req.params.id ?? '', patch));
|
|
319
|
+
}
|
|
135
320
|
//# sourceMappingURL=tickets.controller.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tickets.controller.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/tickets/tickets.controller.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tickets.controller.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/tickets/tickets.controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,13 @@ import { Router } from 'express';
|
|
|
11
11
|
* - GET / — board-shaped list
|
|
12
12
|
* - GET /:tkt — one ticket
|
|
13
13
|
* - POST /:id/dismiss — "不用记"
|
|
14
|
+
* - POST /:id/verify — 验过了
|
|
15
|
+
* - POST /:id/reject — 打回 { reason }
|
|
16
|
+
* - PUT /:id/acceptance — replace acceptance list
|
|
17
|
+
* - POST /:id/self-check — agent self-check of one criterion
|
|
18
|
+
* - PATCH /:id — title / priority / kind / assignee
|
|
19
|
+
* - POST /:id/acceptance, POST /:id/update — the same two, for the relay
|
|
20
|
+
* (portal / phone), which only carries GET and POST
|
|
14
21
|
*
|
|
15
22
|
* @returns Express router for /api/tickets
|
|
16
23
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tickets.routes.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/tickets/tickets.routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"tickets.routes.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/tickets/tickets.routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAYjC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAc5C"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @module controllers/tickets/tickets.routes
|
|
5
5
|
*/
|
|
6
6
|
import { Router } from 'express';
|
|
7
|
-
import { listTickets, getTicket, dismissTicket } from './tickets.controller.js';
|
|
7
|
+
import { listTickets, getTicket, dismissTicket, verifyTicket, rejectTicket, setTicketAcceptance, selfCheckTicket, patchTicket, } from './tickets.controller.js';
|
|
8
8
|
/**
|
|
9
9
|
* Create the tickets router.
|
|
10
10
|
*
|
|
@@ -12,6 +12,13 @@ import { listTickets, getTicket, dismissTicket } from './tickets.controller.js';
|
|
|
12
12
|
* - GET / — board-shaped list
|
|
13
13
|
* - GET /:tkt — one ticket
|
|
14
14
|
* - POST /:id/dismiss — "不用记"
|
|
15
|
+
* - POST /:id/verify — 验过了
|
|
16
|
+
* - POST /:id/reject — 打回 { reason }
|
|
17
|
+
* - PUT /:id/acceptance — replace acceptance list
|
|
18
|
+
* - POST /:id/self-check — agent self-check of one criterion
|
|
19
|
+
* - PATCH /:id — title / priority / kind / assignee
|
|
20
|
+
* - POST /:id/acceptance, POST /:id/update — the same two, for the relay
|
|
21
|
+
* (portal / phone), which only carries GET and POST
|
|
15
22
|
*
|
|
16
23
|
* @returns Express router for /api/tickets
|
|
17
24
|
*/
|
|
@@ -20,6 +27,14 @@ export function createTicketsRouter() {
|
|
|
20
27
|
router.get('/', listTickets);
|
|
21
28
|
router.get('/:tkt', getTicket);
|
|
22
29
|
router.post('/:id/dismiss', dismissTicket);
|
|
30
|
+
router.post('/:id/verify', verifyTicket);
|
|
31
|
+
router.post('/:id/reject', rejectTicket);
|
|
32
|
+
router.put('/:id/acceptance', setTicketAcceptance);
|
|
33
|
+
router.post('/:id/self-check', selfCheckTicket);
|
|
34
|
+
router.patch('/:id', patchTicket);
|
|
35
|
+
// POST twins: the relay (portal / phone) only carries GET and POST.
|
|
36
|
+
router.post('/:id/acceptance', setTicketAcceptance);
|
|
37
|
+
router.post('/:id/update', patchTicket);
|
|
23
38
|
return router;
|
|
24
39
|
}
|
|
25
40
|
//# sourceMappingURL=tickets.routes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tickets.routes.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/tickets/tickets.routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,
|
|
1
|
+
{"version":3,"file":"tickets.routes.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/tickets/tickets.routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EACL,WAAW,EACX,SAAS,EACT,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,WAAW,GACZ,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC7B,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC/B,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC;IAC3C,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IACzC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IACzC,MAAM,CAAC,GAAG,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAC;IACnD,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC;IAChD,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAClC,oEAAoE;IACpE,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAC;IACpD,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IACxC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -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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"}
|
|
@@ -58,11 +58,14 @@ import { setRequestServiceEventBus, RequestService } from './services/v3/request
|
|
|
58
58
|
import { getSlackService } from './services/slack/slack.service.js';
|
|
59
59
|
import { sendBootAnnouncement, isFirstBoot, markBooted } from './services/boot/boot-announce.service.js';
|
|
60
60
|
import { SubAgentMessageQueue } from './services/messaging/sub-agent-message-queue.service.js';
|
|
61
|
-
import { SUB_AGENT_QUEUE_CONSTANTS, CHAT_CONTEXT_CONSTANTS, SAFE_RESTART, PROCESS_EXIT_CODES, CLAUDE_STARTUP_CONSTANTS, WEB_CONSTANTS } from './constants.js';
|
|
61
|
+
import { SUB_AGENT_QUEUE_CONSTANTS, CHAT_CONTEXT_CONSTANTS, SAFE_RESTART, PROCESS_EXIT_CODES, CLAUDE_STARTUP_CONSTANTS, WEB_CONSTANTS, TICKET_CONSTANTS } from './constants.js';
|
|
62
62
|
import { PtyActivityTrackerService } from './services/agent/pty-activity-tracker.service.js';
|
|
63
63
|
import { InFlightTurnTracker } from './services/restart/in-flight-turn-tracker.service.js';
|
|
64
64
|
import { TicketIntakeService, setTicketIntakeService, resolveTicketIdForSession, } from './services/v3/ticket-intake.service.js';
|
|
65
65
|
import { createChatV2ReceiptSink } from './services/v3/ticket-channel-hooks.js';
|
|
66
|
+
import { TicketReviewService, setTicketReviewService, getTicketReviewService } from './services/v3/ticket-review.service.js';
|
|
67
|
+
import { activeAcceptance, formatTicketMarker, formatTicketNumber } from './types/v2/ticket.types.js';
|
|
68
|
+
import { createWorkItem, TERMINAL_WORK_ITEM_STATUSES } from './types/v2/work-item.types.js';
|
|
66
69
|
import { runPoolArchiveMigration } from './services/task-pool/pool-archive-migration.js';
|
|
67
70
|
import { createPtyTurnProbe } from './services/restart/turn-probe.js';
|
|
68
71
|
import { RestartDrainService, resolveRestartDrainMs } from './services/restart/restart-drain.service.js';
|
|
@@ -415,6 +418,64 @@ export class CrewlyServer {
|
|
|
415
418
|
}));
|
|
416
419
|
setTicketIntakeService(ticketIntake);
|
|
417
420
|
TaskPoolService.getInstance().setTicketResolver((sessionName) => resolveTicketIdForSession(InFlightTurnTracker.getInstance(), sessionName));
|
|
421
|
+
// Phase 2: answered → 待验收 → 验过了 / 打回 / silence accepts.
|
|
422
|
+
const ticketReview = new TicketReviewService({
|
|
423
|
+
requests: RequestService.getInstance(),
|
|
424
|
+
fallbackAgent: ORCHESTRATOR_SESSION_NAME,
|
|
425
|
+
openWorkItemCount: async (requestId) => (await TaskPoolService.getInstance().getAllItems()).filter((wi) => wi.requestId === requestId && !TERMINAL_WORK_ITEM_STATUSES.has(wi.status)).length,
|
|
426
|
+
createRework: async ({ ticket, reason, target }) => {
|
|
427
|
+
const tkt = formatTicketNumber(ticket.ticketNumber ?? 0);
|
|
428
|
+
const criteria = activeAcceptance(ticket.acceptance).map((a) => `- ${a.text}`).join('\n');
|
|
429
|
+
const wi = createWorkItem({
|
|
430
|
+
type: 'delegate',
|
|
431
|
+
owner: 'system',
|
|
432
|
+
target,
|
|
433
|
+
requestId: ticket.id,
|
|
434
|
+
title: TICKET_CONSTANTS.REVIEW.REWORK_TITLE(tkt),
|
|
435
|
+
description: `${formatTicketMarker(ticket)} The owner sent ${tkt} back: ${reason}\n\n` +
|
|
436
|
+
`Original ask: ${ticket.description}\n` +
|
|
437
|
+
(ticket.reply ? `Your last answer: ${ticket.reply.excerpt}\n` : '') +
|
|
438
|
+
(criteria ? `\nAcceptance criteria:\n${criteria}\n` : '') +
|
|
439
|
+
`\nFix it and answer in the ticket's conversation.`,
|
|
440
|
+
metadata: { ticketRework: true },
|
|
441
|
+
});
|
|
442
|
+
await TaskPoolService.getInstance().addToPool(wi);
|
|
443
|
+
return wi.id;
|
|
444
|
+
},
|
|
445
|
+
markReceiptDone: (ticket) => ticketIntake.markReceiptDone(ticket),
|
|
446
|
+
});
|
|
447
|
+
setTicketReviewService(ticketReview);
|
|
448
|
+
ticketIntake.setReviewHandler(ticketReview);
|
|
449
|
+
// Phase 3: claim order (own rejected → own unblocked → queue
|
|
450
|
+
// rejected → P0..P3) and one ticket per agent, for every claim path.
|
|
451
|
+
TaskPoolService.getInstance().setTicketClaimPolicy({
|
|
452
|
+
snapshot: async () => {
|
|
453
|
+
const out = new Map();
|
|
454
|
+
for (const r of await RequestService.getInstance().listAll()) {
|
|
455
|
+
if (typeof r.ticketNumber !== 'number' || r.status === 'done' || r.status === 'cancelled')
|
|
456
|
+
continue;
|
|
457
|
+
out.set(r.id, { id: r.id, priority: r.priority, ...(r.assignee ? { assignee: r.assignee } : {}) });
|
|
458
|
+
}
|
|
459
|
+
return out;
|
|
460
|
+
},
|
|
461
|
+
onSelfClaimed: async (requestId, agentId) => {
|
|
462
|
+
const r = await RequestService.getInstance().getById(requestId);
|
|
463
|
+
if (r && typeof r.ticketNumber === 'number' && !r.assignee) {
|
|
464
|
+
await RequestService.getInstance().update(requestId, { assignee: agentId });
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
});
|
|
468
|
+
getChatV2Service().on('chat_message', (dto) => {
|
|
469
|
+
void ticketReview.onChatMessage(dto).catch(() => undefined);
|
|
470
|
+
});
|
|
471
|
+
const reviewSweep = setInterval(() => {
|
|
472
|
+
void ticketReview.sweep().catch((sweepErr) => {
|
|
473
|
+
this.logger.warn('Ticket review sweep failed', {
|
|
474
|
+
error: sweepErr instanceof Error ? sweepErr.message : String(sweepErr),
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
}, TICKET_CONSTANTS.REVIEW.SWEEP_INTERVAL_MS);
|
|
478
|
+
reviewSweep.unref?.();
|
|
418
479
|
}
|
|
419
480
|
catch (ticketBootErr) {
|
|
420
481
|
this.logger.error('Ticket intake boot failed — messages are still delivered, no tickets filed', {
|
|
@@ -913,6 +974,11 @@ export class CrewlyServer {
|
|
|
913
974
|
// was mid-answer and never got a reply; the message was still
|
|
914
975
|
// in the queue an hour later (2026-09-21, Ella).
|
|
915
976
|
setImmediate(() => void this.flushQueuedAgentMessages(event.sessionName));
|
|
977
|
+
// Ticket loop Phase 2: an agent that finished its turn has answered
|
|
978
|
+
// the tickets it replied in — submit them (待验收 or done).
|
|
979
|
+
void getTicketReviewService()
|
|
980
|
+
?.onAgentIdle(event.sessionName)
|
|
981
|
+
.catch(() => undefined);
|
|
916
982
|
// V3: Auto-close open Requests when the orchestrator goes idle
|
|
917
983
|
// Handles direct responses (no WorkItem delegation)
|
|
918
984
|
if (event.sessionName === ORCHESTRATOR_SESSION_NAME) {
|
|
@@ -3489,19 +3555,30 @@ export class CrewlyServer {
|
|
|
3489
3555
|
const svc = RequestService.getInstance();
|
|
3490
3556
|
const all = await svc.listAll();
|
|
3491
3557
|
let purgedRequests = 0;
|
|
3558
|
+
const ticketCutoff = Date.now() - TICKET_CONSTANTS.ARCHIVE.AFTER_MS;
|
|
3559
|
+
let archivedTickets = 0;
|
|
3492
3560
|
for (const req of all) {
|
|
3493
3561
|
if (req.status !== 'done' && req.status !== 'cancelled')
|
|
3494
3562
|
continue;
|
|
3495
3563
|
const completedAt = req.completedAt ? new Date(req.completedAt).getTime() : 0;
|
|
3496
3564
|
const createdAt = new Date(req.createdAt).getTime();
|
|
3497
3565
|
const age = completedAt || createdAt;
|
|
3566
|
+
// Tickets are the owner's record of what they asked for: they
|
|
3567
|
+
// stay on the board for 30 days, then move to requests/archive/
|
|
3568
|
+
// — never deleted (ticket loop Phase 3). Before this, every
|
|
3569
|
+
// accepted ticket was deleted a day after it closed.
|
|
3570
|
+
if (typeof req.ticketNumber === 'number') {
|
|
3571
|
+
if (age < ticketCutoff && (await svc.archive(req.id)))
|
|
3572
|
+
archivedTickets++;
|
|
3573
|
+
continue;
|
|
3574
|
+
}
|
|
3498
3575
|
if (age < cutoff) {
|
|
3499
3576
|
await svc.delete(req.id);
|
|
3500
3577
|
purgedRequests++;
|
|
3501
3578
|
}
|
|
3502
3579
|
}
|
|
3503
|
-
if (purgedRequests > 0) {
|
|
3504
|
-
this.logger.info('Purged old completed Requests', { count: purgedRequests });
|
|
3580
|
+
if (purgedRequests > 0 || archivedTickets > 0) {
|
|
3581
|
+
this.logger.info('Purged old completed Requests', { count: purgedRequests, archivedTickets });
|
|
3505
3582
|
}
|
|
3506
3583
|
}
|
|
3507
3584
|
catch (err) {
|
|
@@ -3589,6 +3666,10 @@ export class CrewlyServer {
|
|
|
3589
3666
|
for (const req of all) {
|
|
3590
3667
|
if (req.status !== 'open')
|
|
3591
3668
|
continue;
|
|
3669
|
+
// Tickets matched to their chat turn close when their answer
|
|
3670
|
+
// settles (TicketReviewService), not on a timer.
|
|
3671
|
+
if (req.chatRef)
|
|
3672
|
+
continue;
|
|
3592
3673
|
const reqAge = Date.now() - new Date(req.createdAt).getTime();
|
|
3593
3674
|
if (reqAge > 10 * 60 * 1000)
|
|
3594
3675
|
continue; // older than 10 min — skip
|