@evermore.work/server 2026.520.0-canary.0 → 2026.522.0-canary.1
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/dist/app.d.ts +1 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +53 -16
- package/dist/app.js.map +1 -1
- package/dist/http/body-limits.d.ts +4 -0
- package/dist/http/body-limits.d.ts.map +1 -0
- package/dist/http/body-limits.js +4 -0
- package/dist/http/body-limits.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -1
- package/dist/middleware/error-handler.d.ts.map +1 -1
- package/dist/middleware/error-handler.js +10 -1
- package/dist/middleware/error-handler.js.map +1 -1
- package/dist/routes/companies.d.ts.map +1 -1
- package/dist/routes/companies.js +2 -1
- package/dist/routes/companies.js.map +1 -1
- package/dist/routes/company-import-paths.d.ts +3 -0
- package/dist/routes/company-import-paths.d.ts.map +1 -0
- package/dist/routes/company-import-paths.js +3 -0
- package/dist/routes/company-import-paths.js.map +1 -0
- package/dist/routes/issues.d.ts.map +1 -1
- package/dist/routes/issues.js +142 -10
- package/dist/routes/issues.js.map +1 -1
- package/dist/services/issue-thread-interactions.d.ts +5 -0
- package/dist/services/issue-thread-interactions.d.ts.map +1 -1
- package/dist/services/issue-thread-interactions.js +78 -2
- package/dist/services/issue-thread-interactions.js.map +1 -1
- package/dist/services/issues.d.ts +2 -0
- package/dist/services/issues.d.ts.map +1 -1
- package/dist/services/issues.js +27 -2
- package/dist/services/issues.js.map +1 -1
- package/dist/services/plugin-lifecycle.d.ts.map +1 -1
- package/dist/services/plugin-lifecycle.js +30 -5
- package/dist/services/plugin-lifecycle.js.map +1 -1
- package/dist/services/plugin-worker-manager.d.ts.map +1 -1
- package/dist/services/plugin-worker-manager.js +3 -1
- package/dist/services/plugin-worker-manager.js.map +1 -1
- package/package.json +16 -16
- package/ui-dist/assets/{_basePickBy-ur36FGgu.js → _basePickBy-BAfyEDHh.js} +1 -1
- package/ui-dist/assets/{_baseUniq-DOtXUkii.js → _baseUniq-BVtZ4ePq.js} +1 -1
- package/ui-dist/assets/{arc-CgvHLduO.js → arc-NM4T7ncJ.js} +1 -1
- package/ui-dist/assets/{architectureDiagram-VXUJARFQ-C9P1idjU.js → architectureDiagram-VXUJARFQ-CcghPpe4.js} +1 -1
- package/ui-dist/assets/{blockDiagram-VD42YOAC-CAMu_DcH.js → blockDiagram-VD42YOAC-CoPJnEvc.js} +1 -1
- package/ui-dist/assets/{c4Diagram-YG6GDRKO-BbUtuYGo.js → c4Diagram-YG6GDRKO-DC8HKuV5.js} +1 -1
- package/ui-dist/assets/channel-oeICJafe.js +1 -0
- package/ui-dist/assets/{chunk-4BX2VUAB-CTrEBNY1.js → chunk-4BX2VUAB-BFyK9Z-9.js} +1 -1
- package/ui-dist/assets/{chunk-55IACEB6-CIe1wGln.js → chunk-55IACEB6-CUhPuWM1.js} +1 -1
- package/ui-dist/assets/{chunk-B4BG7PRW-B8p6GPTa.js → chunk-B4BG7PRW-D3p8bK_5.js} +1 -1
- package/ui-dist/assets/{chunk-DI55MBZ5-D_q_KdSN.js → chunk-DI55MBZ5-CCD5K6PL.js} +1 -1
- package/ui-dist/assets/{chunk-FMBD7UC4-pn3dIZ5Z.js → chunk-FMBD7UC4-CA4Hn0su.js} +1 -1
- package/ui-dist/assets/{chunk-QN33PNHL-DjVHgBi3.js → chunk-QN33PNHL-6LyF9JFT.js} +1 -1
- package/ui-dist/assets/{chunk-QZHKN3VN-BmX_FU-9.js → chunk-QZHKN3VN-D5iUp0wq.js} +1 -1
- package/ui-dist/assets/{chunk-TZMSLE5B-BsS-f8EW.js → chunk-TZMSLE5B-DwQdEWk6.js} +1 -1
- package/ui-dist/assets/classDiagram-2ON5EDUG-BLDIxz8H.js +1 -0
- package/ui-dist/assets/classDiagram-v2-WZHVMYZB-BLDIxz8H.js +1 -0
- package/ui-dist/assets/clone-CXxoKrQC.js +1 -0
- package/ui-dist/assets/{cose-bilkent-S5V4N54A-Rrh2YWZD.js → cose-bilkent-S5V4N54A-CJXAQtlZ.js} +1 -1
- package/ui-dist/assets/{dagre-6UL2VRFP-BYlLrV1l.js → dagre-6UL2VRFP-DGu0oMQF.js} +1 -1
- package/ui-dist/assets/{diagram-PSM6KHXK-CGmUzDUl.js → diagram-PSM6KHXK-Cdabn9s9.js} +1 -1
- package/ui-dist/assets/{diagram-QEK2KX5R-WaFjpU2E.js → diagram-QEK2KX5R-CVNLM2e3.js} +1 -1
- package/ui-dist/assets/{diagram-S2PKOQOG-CrTMNqtq.js → diagram-S2PKOQOG-17idWIQN.js} +1 -1
- package/ui-dist/assets/{erDiagram-Q2GNP2WA-Dm3faCdS.js → erDiagram-Q2GNP2WA-DWvqhZQi.js} +1 -1
- package/ui-dist/assets/{flowDiagram-NV44I4VS-B4Q5YtnD.js → flowDiagram-NV44I4VS-DvtW8STD.js} +1 -1
- package/ui-dist/assets/{ganttDiagram-JELNMOA3-DwbA62qK.js → ganttDiagram-JELNMOA3-DXicwquE.js} +1 -1
- package/ui-dist/assets/{gitGraphDiagram-V2S2FVAM-D9qrL3NH.js → gitGraphDiagram-V2S2FVAM-C25-WuW6.js} +1 -1
- package/ui-dist/assets/{graph-DFXafxQf.js → graph-CFYRqodg.js} +1 -1
- package/ui-dist/assets/{index-SDl3zIIz.js → index-BHGC2J3x.js} +1 -1
- package/ui-dist/assets/{index-DKDHGw8g.js → index-BVHQhywh.js} +1 -1
- package/ui-dist/assets/{index-Dh6pW3kR.js → index-BXkIyLU3.js} +1 -1
- package/ui-dist/assets/{index-DbI_ounN.js → index-Bat3FSRG.js} +1 -1
- package/ui-dist/assets/{index-DqUoy5Xt.js → index-BjTEWd_N.js} +1 -1
- package/ui-dist/assets/{index-BLMvao6K.js → index-BwH24qCy.js} +1 -1
- package/ui-dist/assets/{index-2l4kaSnK.js → index-CAF13J8j.js} +1 -1
- package/ui-dist/assets/{index-B9TjE7C1.js → index-CCXEIc5t.js} +1 -1
- package/ui-dist/assets/{index-Wd0d_e7x.js → index-CQCOD315.js} +1 -1
- package/ui-dist/assets/{index-Bu_Yw-rq.js → index-CT8XPEg8.js} +1 -1
- package/ui-dist/assets/{index-DrFHxroW.js → index-CUNx0bRn.js} +126 -126
- package/ui-dist/assets/{index-CGQCTx4q.js → index-Ca3xBUXp.js} +1 -1
- package/ui-dist/assets/{index-Bv-NIGkH.js → index-Cw3iF_k6.js} +1 -1
- package/ui-dist/assets/{index-D0AW6Ex4.js → index-CxZQpQTP.js} +1 -1
- package/ui-dist/assets/{index-KfGo4tR4.js → index-D6uEP1N1.js} +1 -1
- package/ui-dist/assets/{index-DONP_c_6.js → index-D85jUak7.js} +1 -1
- package/ui-dist/assets/{index-C6epqsMd.js → index-DMnKD2AG.js} +1 -1
- package/ui-dist/assets/{index-D_YO6Ibe.js → index-Ds2tRcF9.js} +1 -1
- package/ui-dist/assets/{index-CoHgnjUU.js → index-IDPqK6dk.js} +1 -1
- package/ui-dist/assets/{index-AdFQqp3g.js → index-NsXec_rb.js} +1 -1
- package/ui-dist/assets/{index-B7P1n35S.js → index-SHt_ZvlJ.js} +1 -1
- package/ui-dist/assets/{index-36xStgzi.js → index-VNR5mBPK.js} +1 -1
- package/ui-dist/assets/{index-BTcY-hP2.js → index-ZglV-fz_.js} +1 -1
- package/ui-dist/assets/{infoDiagram-HS3SLOUP-BpSoPdCX.js → infoDiagram-HS3SLOUP-DK9j0BGY.js} +1 -1
- package/ui-dist/assets/{journeyDiagram-XKPGCS4Q-CteiGqXX.js → journeyDiagram-XKPGCS4Q-BQ1wv45a.js} +1 -1
- package/ui-dist/assets/{kanban-definition-3W4ZIXB7-bxXoEdtx.js → kanban-definition-3W4ZIXB7-CWNvcmce.js} +1 -1
- package/ui-dist/assets/{layout-C73CcCuC.js → layout-yOBskK5Z.js} +1 -1
- package/ui-dist/assets/{linear-CxlfBvt7.js → linear-CJ5iTPUv.js} +1 -1
- package/ui-dist/assets/{mermaid.core-Fg3ZO6QO.js → mermaid.core-DlHhoBx2.js} +4 -4
- package/ui-dist/assets/{mindmap-definition-VGOIOE7T-nu_pvWep.js → mindmap-definition-VGOIOE7T-BJ2DXzjK.js} +1 -1
- package/ui-dist/assets/{pieDiagram-ADFJNKIX-BOA6WgQP.js → pieDiagram-ADFJNKIX-CDCDTKT8.js} +1 -1
- package/ui-dist/assets/{quadrantDiagram-AYHSOK5B-Dxy0YFqG.js → quadrantDiagram-AYHSOK5B-VQAT-8Am.js} +1 -1
- package/ui-dist/assets/{requirementDiagram-UZGBJVZJ-Di4nW5Aa.js → requirementDiagram-UZGBJVZJ-D0thUX7y.js} +1 -1
- package/ui-dist/assets/{sankeyDiagram-TZEHDZUN-DZQ4EGbS.js → sankeyDiagram-TZEHDZUN-DxPP5JxP.js} +1 -1
- package/ui-dist/assets/{sequenceDiagram-WL72ISMW-Bi6X93SR.js → sequenceDiagram-WL72ISMW-DrjVPEcr.js} +1 -1
- package/ui-dist/assets/{stateDiagram-FKZM4ZOC-7FE9LR7S.js → stateDiagram-FKZM4ZOC-BFvVUDkq.js} +1 -1
- package/ui-dist/assets/stateDiagram-v2-4FDKWEC3-pah5kxfq.js +1 -0
- package/ui-dist/assets/{timeline-definition-IT6M3QCI-BHt5ey38.js → timeline-definition-IT6M3QCI-DqFsh20q.js} +1 -1
- package/ui-dist/assets/{treemap-GDKQZRPO-BgLxlWZU.js → treemap-GDKQZRPO-BdHExSsY.js} +1 -1
- package/ui-dist/assets/{xychartDiagram-PRI3JC2R-yLw6fryP.js → xychartDiagram-PRI3JC2R-BuufhaB_.js} +1 -1
- package/ui-dist/index.html +1 -1
- package/ui-dist/assets/channel-DKyh0X3p.js +0 -1
- package/ui-dist/assets/classDiagram-2ON5EDUG-Dn8GiEC1.js +0 -1
- package/ui-dist/assets/classDiagram-v2-WZHVMYZB-Dn8GiEC1.js +0 -1
- package/ui-dist/assets/clone-CgBtIqNi.js +0 -1
- package/ui-dist/assets/stateDiagram-v2-4FDKWEC3-DNlLaaUR.js +0 -1
package/dist/routes/issues.js
CHANGED
|
@@ -375,6 +375,15 @@ function shouldImplicitlyMoveCommentedIssueToTodo(input) {
|
|
|
375
375
|
return false;
|
|
376
376
|
return true;
|
|
377
377
|
}
|
|
378
|
+
function shouldHumanCommentResumeInProgressScheduledRetry(input) {
|
|
379
|
+
if (!input.hasComment)
|
|
380
|
+
return false;
|
|
381
|
+
if (input.actorType !== "user")
|
|
382
|
+
return false;
|
|
383
|
+
if (input.issueStatus !== "in_progress")
|
|
384
|
+
return false;
|
|
385
|
+
return typeof input.assigneeAgentId === "string" && input.assigneeAgentId.length > 0;
|
|
386
|
+
}
|
|
378
387
|
function isExplicitResumeCapableStatus(status) {
|
|
379
388
|
return status === "done" || status === "blocked" || status === "todo" || status === "in_progress";
|
|
380
389
|
}
|
|
@@ -561,6 +570,34 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
561
570
|
};
|
|
562
571
|
const feedbackExportService = opts?.feedbackExportService;
|
|
563
572
|
const environmentsSvc = environmentService(db);
|
|
573
|
+
async function cancelScheduledRetrySupersededByComment(input) {
|
|
574
|
+
const scheduledRetryRunId = readNonEmptyString(input.scheduledRetryRunId);
|
|
575
|
+
if (!scheduledRetryRunId)
|
|
576
|
+
return null;
|
|
577
|
+
try {
|
|
578
|
+
const cancelled = await heartbeat.cancelRun(scheduledRetryRunId);
|
|
579
|
+
const cancelledRunId = cancelled?.id ?? scheduledRetryRunId;
|
|
580
|
+
await logActivity(db, {
|
|
581
|
+
companyId: input.issue.companyId,
|
|
582
|
+
actorType: input.actor.actorType,
|
|
583
|
+
actorId: input.actor.actorId,
|
|
584
|
+
agentId: input.actor.agentId,
|
|
585
|
+
runId: input.actor.runId,
|
|
586
|
+
action: "heartbeat.cancelled",
|
|
587
|
+
entityType: "heartbeat_run",
|
|
588
|
+
entityId: cancelledRunId,
|
|
589
|
+
details: {
|
|
590
|
+
source: "issue_comment_scheduled_retry_superseded",
|
|
591
|
+
issueId: input.issue.id,
|
|
592
|
+
},
|
|
593
|
+
});
|
|
594
|
+
return cancelledRunId;
|
|
595
|
+
}
|
|
596
|
+
catch (err) {
|
|
597
|
+
logger.error({ err, issueId: input.issue.id, runId: scheduledRetryRunId }, "failed to cancel scheduled retry superseded by issue comment");
|
|
598
|
+
throw err;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
564
601
|
async function classifySourceRecoveryRevalidation(input) {
|
|
565
602
|
const { issue } = input;
|
|
566
603
|
if (issue.status === "done" || issue.status === "cancelled") {
|
|
@@ -1298,6 +1335,8 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
1298
1335
|
? Number.parseInt(rawOffset, 10)
|
|
1299
1336
|
: null;
|
|
1300
1337
|
const attention = req.query.attention;
|
|
1338
|
+
const sortField = req.query.sortField;
|
|
1339
|
+
const sortDir = req.query.sortDir;
|
|
1301
1340
|
if (assigneeUserFilterRaw === "me" && (!assigneeUserId || req.actor.type !== "board")) {
|
|
1302
1341
|
res.status(403).json({ error: "assigneeUserId=me requires board authentication" });
|
|
1303
1342
|
return;
|
|
@@ -1326,6 +1365,14 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
1326
1365
|
res.status(400).json({ error: "offset must be a non-negative integer" });
|
|
1327
1366
|
return;
|
|
1328
1367
|
}
|
|
1368
|
+
if (sortField !== undefined && sortField !== "updated") {
|
|
1369
|
+
res.status(400).json({ error: "sortField must be 'updated' when provided" });
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
if (sortDir !== undefined && sortDir !== "asc" && sortDir !== "desc") {
|
|
1373
|
+
res.status(400).json({ error: "sortDir must be 'asc' or 'desc' when provided" });
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1329
1376
|
const offset = parsedOffset ?? 0;
|
|
1330
1377
|
const result = await svc.list(companyId, {
|
|
1331
1378
|
attention: attention === "blocked" ? "blocked" : undefined,
|
|
@@ -1353,6 +1400,8 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
1353
1400
|
q: req.query.q,
|
|
1354
1401
|
limit,
|
|
1355
1402
|
offset,
|
|
1403
|
+
sortField: sortField === "updated" ? "updated" : undefined,
|
|
1404
|
+
sortDir: sortDir === "asc" || sortDir === "desc" ? sortDir : undefined,
|
|
1356
1405
|
});
|
|
1357
1406
|
const issueIds = result.map((issue) => issue.id);
|
|
1358
1407
|
const [handoffStates, recoveryActionByIssue] = await Promise.all([
|
|
@@ -2736,6 +2785,16 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
2736
2785
|
!(await assertRecoveryActionAuthority(req, res, existing, activeRecoveryActionBeforeUpdate, { source: "issue_update" }))) {
|
|
2737
2786
|
return;
|
|
2738
2787
|
}
|
|
2788
|
+
const scheduledRetryForHumanComment = shouldHumanCommentResumeInProgressScheduledRetry({
|
|
2789
|
+
hasComment: !!commentBody,
|
|
2790
|
+
issueStatus: existing.status,
|
|
2791
|
+
assigneeAgentId: requestedAssigneeAgentId,
|
|
2792
|
+
actorType: actor.actorType,
|
|
2793
|
+
})
|
|
2794
|
+
? await svc.getCurrentScheduledRetry(existing.id)
|
|
2795
|
+
: null;
|
|
2796
|
+
const shouldResumeInProgressScheduledRetry = !!scheduledRetryForHumanComment &&
|
|
2797
|
+
scheduledRetryForHumanComment.agentId === requestedAssigneeAgentId;
|
|
2739
2798
|
const effectiveMoveToTodoRequested = explicitMoveToTodoRequested ||
|
|
2740
2799
|
(!!commentBody &&
|
|
2741
2800
|
shouldImplicitlyMoveCommentedIssueToTodo({
|
|
@@ -2743,7 +2802,8 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
2743
2802
|
assigneeAgentId: requestedAssigneeAgentId,
|
|
2744
2803
|
actorType: actor.actorType,
|
|
2745
2804
|
actorId: actor.actorId,
|
|
2746
|
-
}))
|
|
2805
|
+
})) ||
|
|
2806
|
+
shouldResumeInProgressScheduledRetry;
|
|
2747
2807
|
const updateReferenceSummaryBefore = titleOrDescriptionChanged
|
|
2748
2808
|
? await issueReferencesSvc.listIssueReferenceSummary(existing.id)
|
|
2749
2809
|
: null;
|
|
@@ -2797,10 +2857,20 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
2797
2857
|
}
|
|
2798
2858
|
if (commentBody &&
|
|
2799
2859
|
effectiveMoveToTodoRequested &&
|
|
2800
|
-
(isClosed || (isBlocked && !hasUnresolvedFirstClassBlockers)) &&
|
|
2860
|
+
(isClosed || (isBlocked && !hasUnresolvedFirstClassBlockers) || shouldResumeInProgressScheduledRetry) &&
|
|
2801
2861
|
updateFields.status === undefined) {
|
|
2802
2862
|
updateFields.status = "todo";
|
|
2803
2863
|
}
|
|
2864
|
+
let cancelledScheduledRetryRunId = null;
|
|
2865
|
+
if (commentBody &&
|
|
2866
|
+
shouldResumeInProgressScheduledRetry &&
|
|
2867
|
+
updateFields.status === "todo") {
|
|
2868
|
+
cancelledScheduledRetryRunId = await cancelScheduledRetrySupersededByComment({
|
|
2869
|
+
scheduledRetryRunId: scheduledRetryForHumanComment?.runId,
|
|
2870
|
+
issue: existing,
|
|
2871
|
+
actor,
|
|
2872
|
+
});
|
|
2873
|
+
}
|
|
2804
2874
|
if (req.body.executionPolicy !== undefined) {
|
|
2805
2875
|
updateFields.executionPolicy = applyActorMonitorScheduledBy(normalizeIssueExecutionPolicy(req.body.executionPolicy), actor.actorType);
|
|
2806
2876
|
}
|
|
@@ -3023,6 +3093,10 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
3023
3093
|
previous.status !== undefined &&
|
|
3024
3094
|
issue.status === "todo";
|
|
3025
3095
|
const reopenFromStatus = reopened ? existing.status : null;
|
|
3096
|
+
const scheduledRetrySupersededByComment = shouldResumeInProgressScheduledRetry &&
|
|
3097
|
+
previous.status !== undefined &&
|
|
3098
|
+
existing.status === "in_progress" &&
|
|
3099
|
+
issue.status === "todo";
|
|
3026
3100
|
const statusChangedFromBlockedToTodo = existing.status === "blocked" &&
|
|
3027
3101
|
issue.status === "todo" &&
|
|
3028
3102
|
(req.body.status !== undefined || reopened);
|
|
@@ -3062,6 +3136,13 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
3062
3136
|
...(commentBody ? { source: "comment" } : {}),
|
|
3063
3137
|
...(resumeRequested === true ? { resumeIntent: true, followUpRequested: true } : {}),
|
|
3064
3138
|
...(reopened ? { reopened: true, reopenedFrom: reopenFromStatus } : {}),
|
|
3139
|
+
...(scheduledRetrySupersededByComment
|
|
3140
|
+
? {
|
|
3141
|
+
scheduledRetrySupersededByComment: true,
|
|
3142
|
+
scheduledRetryRunId: scheduledRetryForHumanComment?.runId ?? null,
|
|
3143
|
+
...(cancelledScheduledRetryRunId ? { cancelledScheduledRetryRunId } : {}),
|
|
3144
|
+
}
|
|
3145
|
+
: {}),
|
|
3065
3146
|
...(interruptedRunId ? { interruptedRunId } : {}),
|
|
3066
3147
|
...(cancelledStatusRunId ? { cancelledStatusRunId } : {}),
|
|
3067
3148
|
...(workspaceChange ? { workspaceChange } : {}),
|
|
@@ -3266,6 +3347,13 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
3266
3347
|
issueTitle: issue.title,
|
|
3267
3348
|
...(resumeRequested === true ? { resumeIntent: true, followUpRequested: true } : {}),
|
|
3268
3349
|
...(reopened ? { reopened: true, reopenedFrom: reopenFromStatus, source: "comment" } : {}),
|
|
3350
|
+
...(scheduledRetrySupersededByComment
|
|
3351
|
+
? {
|
|
3352
|
+
scheduledRetrySupersededByComment: true,
|
|
3353
|
+
scheduledRetryRunId: scheduledRetryForHumanComment?.runId ?? null,
|
|
3354
|
+
...(cancelledScheduledRetryRunId ? { cancelledScheduledRetryRunId } : {}),
|
|
3355
|
+
}
|
|
3356
|
+
: {}),
|
|
3269
3357
|
...(interruptedRunId ? { interruptedRunId } : {}),
|
|
3270
3358
|
...(hasFieldChanges ? { updated: true } : {}),
|
|
3271
3359
|
...summarizeIssueReferenceActivityDetails({
|
|
@@ -3709,7 +3797,16 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
3709
3797
|
return;
|
|
3710
3798
|
}
|
|
3711
3799
|
assertCompanyAccess(req, issue.companyId);
|
|
3712
|
-
const
|
|
3800
|
+
const actor = getActorInfo(req);
|
|
3801
|
+
const interactionSvc = issueThreadInteractionService(db);
|
|
3802
|
+
const expiredInteractions = await interactionSvc.expireRequestConfirmationsSupersededByHistoricalComments(issue);
|
|
3803
|
+
await logExpiredRequestConfirmations({
|
|
3804
|
+
issue,
|
|
3805
|
+
interactions: expiredInteractions,
|
|
3806
|
+
actor,
|
|
3807
|
+
source: "issue.interactions.catchup_superseded_by_comment",
|
|
3808
|
+
});
|
|
3809
|
+
const interactions = await interactionSvc.listForIssue(id);
|
|
3713
3810
|
res.json(interactions);
|
|
3714
3811
|
});
|
|
3715
3812
|
router.post("/issues/:id/interactions", validate(createIssueThreadInteractionSchema), async (req, res) => {
|
|
@@ -4155,13 +4252,24 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
4155
4252
|
const isClosed = isClosedIssueStatus(issue.status);
|
|
4156
4253
|
const isBlocked = issue.status === "blocked";
|
|
4157
4254
|
const explicitMoveToTodoRequested = reopenRequested || resumeRequested === true;
|
|
4255
|
+
const scheduledRetryForHumanComment = shouldHumanCommentResumeInProgressScheduledRetry({
|
|
4256
|
+
hasComment: true,
|
|
4257
|
+
issueStatus: issue.status,
|
|
4258
|
+
assigneeAgentId: issue.assigneeAgentId,
|
|
4259
|
+
actorType: actor.actorType,
|
|
4260
|
+
})
|
|
4261
|
+
? await svc.getCurrentScheduledRetry(issue.id)
|
|
4262
|
+
: null;
|
|
4263
|
+
const shouldResumeInProgressScheduledRetry = !!scheduledRetryForHumanComment &&
|
|
4264
|
+
scheduledRetryForHumanComment.agentId === issue.assigneeAgentId;
|
|
4158
4265
|
const effectiveMoveToTodoRequested = explicitMoveToTodoRequested ||
|
|
4159
4266
|
shouldImplicitlyMoveCommentedIssueToTodo({
|
|
4160
4267
|
issueStatus: issue.status,
|
|
4161
4268
|
assigneeAgentId: issue.assigneeAgentId,
|
|
4162
4269
|
actorType: actor.actorType,
|
|
4163
4270
|
actorId: actor.actorId,
|
|
4164
|
-
})
|
|
4271
|
+
}) ||
|
|
4272
|
+
shouldResumeInProgressScheduledRetry;
|
|
4165
4273
|
const hasUnresolvedFirstClassBlockers = isBlocked && effectiveMoveToTodoRequested
|
|
4166
4274
|
? (await svc.getDependencyReadiness(issue.id)).unresolvedBlockerCount > 0
|
|
4167
4275
|
: false;
|
|
@@ -4174,14 +4282,25 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
4174
4282
|
let interruptedRunId = null;
|
|
4175
4283
|
let currentIssue = issue;
|
|
4176
4284
|
const commentReferenceSummaryBefore = await issueReferencesSvc.listIssueReferenceSummary(issue.id);
|
|
4177
|
-
|
|
4285
|
+
let scheduledRetrySupersededByComment = false;
|
|
4286
|
+
let cancelledScheduledRetryRunId = null;
|
|
4287
|
+
if (effectiveMoveToTodoRequested &&
|
|
4288
|
+
(isClosed || (isBlocked && !hasUnresolvedFirstClassBlockers) || shouldResumeInProgressScheduledRetry)) {
|
|
4289
|
+
scheduledRetrySupersededByComment = shouldResumeInProgressScheduledRetry && issue.status === "in_progress";
|
|
4290
|
+
cancelledScheduledRetryRunId = scheduledRetrySupersededByComment
|
|
4291
|
+
? await cancelScheduledRetrySupersededByComment({
|
|
4292
|
+
scheduledRetryRunId: scheduledRetryForHumanComment?.runId,
|
|
4293
|
+
issue,
|
|
4294
|
+
actor,
|
|
4295
|
+
})
|
|
4296
|
+
: null;
|
|
4178
4297
|
const reopenedIssue = await svc.update(id, { status: "todo" });
|
|
4179
4298
|
if (!reopenedIssue) {
|
|
4180
4299
|
res.status(404).json({ error: "Issue not found" });
|
|
4181
4300
|
return;
|
|
4182
4301
|
}
|
|
4183
|
-
reopened =
|
|
4184
|
-
reopenFromStatus = issue.status;
|
|
4302
|
+
reopened = isClosed || (isBlocked && !hasUnresolvedFirstClassBlockers);
|
|
4303
|
+
reopenFromStatus = reopened ? issue.status : null;
|
|
4185
4304
|
currentIssue = reopenedIssue;
|
|
4186
4305
|
await logActivity(db, {
|
|
4187
4306
|
companyId: currentIssue.companyId,
|
|
@@ -4194,8 +4313,14 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
4194
4313
|
entityId: currentIssue.id,
|
|
4195
4314
|
details: {
|
|
4196
4315
|
status: "todo",
|
|
4197
|
-
reopened: true,
|
|
4198
|
-
|
|
4316
|
+
...(reopened ? { reopened: true, reopenedFrom: reopenFromStatus } : {}),
|
|
4317
|
+
...(scheduledRetrySupersededByComment
|
|
4318
|
+
? {
|
|
4319
|
+
scheduledRetrySupersededByComment: true,
|
|
4320
|
+
scheduledRetryRunId: scheduledRetryForHumanComment?.runId ?? null,
|
|
4321
|
+
...(cancelledScheduledRetryRunId ? { cancelledScheduledRetryRunId } : {}),
|
|
4322
|
+
}
|
|
4323
|
+
: {}),
|
|
4199
4324
|
source: "comment",
|
|
4200
4325
|
...(resumeRequested === true ? { resumeIntent: true, followUpRequested: true } : {}),
|
|
4201
4326
|
identifier: currentIssue.identifier,
|
|
@@ -4257,6 +4382,13 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
4257
4382
|
issueTitle: currentIssue.title,
|
|
4258
4383
|
...(resumeRequested === true ? { resumeIntent: true, followUpRequested: true } : {}),
|
|
4259
4384
|
...(reopened ? { reopened: true, reopenedFrom: reopenFromStatus, source: "comment" } : {}),
|
|
4385
|
+
...(scheduledRetrySupersededByComment
|
|
4386
|
+
? {
|
|
4387
|
+
scheduledRetrySupersededByComment: true,
|
|
4388
|
+
scheduledRetryRunId: scheduledRetryForHumanComment?.runId ?? null,
|
|
4389
|
+
...(cancelledScheduledRetryRunId ? { cancelledScheduledRetryRunId } : {}),
|
|
4390
|
+
}
|
|
4391
|
+
: {}),
|
|
4260
4392
|
...(interruptedRunId ? { interruptedRunId } : {}),
|
|
4261
4393
|
...summarizeIssueReferenceActivityDetails({
|
|
4262
4394
|
addedReferencedIssues: commentReferenceDiff.addedReferencedIssues.map(summarizeIssueRelationForActivity),
|
|
@@ -4279,7 +4411,7 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
4279
4411
|
issue: currentIssue,
|
|
4280
4412
|
trigger: "comment",
|
|
4281
4413
|
actor,
|
|
4282
|
-
statusChanged: reopened,
|
|
4414
|
+
statusChanged: reopened || scheduledRetrySupersededByComment,
|
|
4283
4415
|
resumeRequested: resumeRequested === true,
|
|
4284
4416
|
reopened,
|
|
4285
4417
|
blockedToTodoRecovery: reopened && reopenFromStatus === "blocked" && currentIssue.status === "todo",
|