specrails-desktop 2.49.2 → 2.50.0
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/client/dist/assets/{ActivityFeedPage-CyOxof-U.js → ActivityFeedPage-tWhhCACX.js} +1 -1
- package/client/dist/assets/{AgentBrowserCapture-DBGaKW4u.js → AgentBrowserCapture-CZeFRg-Y.js} +1 -1
- package/client/dist/assets/{AgentModeAnalyticsPane-WZpPaNMa.js → AgentModeAnalyticsPane-u4ux0xLJ.js} +2 -2
- package/client/dist/assets/{AgentModeCodePane-nHYnJUdP.js → AgentModeCodePane-wn1RDZ4y.js} +2 -2
- package/client/dist/assets/{AgentModeJobsPane-DkhcBtoZ.js → AgentModeJobsPane-CXLikWKG.js} +1 -1
- package/client/dist/assets/{AgentsPage-CX90q-nY.js → AgentsPage-zjVv7i9S.js} +1 -1
- package/client/dist/assets/{AnalyticsPage-DisrtBr7.js → AnalyticsPage-Bf2kyeeR.js} +1 -1
- package/client/dist/assets/{CodePage-ixqxftCT.js → CodePage-Db7jdyKI.js} +1 -1
- package/client/dist/assets/{DesktopAnalyticsPage-BFB-Pn-D.js → DesktopAnalyticsPage-CnF_SL4h.js} +1 -1
- package/client/dist/assets/{DocsDialog-BwiFrwEJ.js → DocsDialog-DJ0ATgNN.js} +1 -1
- package/client/dist/assets/{DocsPage-ByS0ZCco.js → DocsPage-I5217wRs.js} +1 -1
- package/client/dist/assets/{ExportDropdown-IPutNYvD.js → ExportDropdown-D1JqZXMo.js} +1 -1
- package/client/dist/assets/{InteractiveJobComposer-BEok7ntM.js → InteractiveJobComposer-Ccyfbaj1.js} +1 -1
- package/client/dist/assets/{JobDetailModal-BnO_V8KR.js → JobDetailModal-BV0oXeR1.js} +1 -1
- package/client/dist/assets/{JobDetailPage-BnS8aHKD.js → JobDetailPage-B6muzK7f.js} +1 -1
- package/client/dist/assets/{JobsPage-BC0mq-MF.js → JobsPage-z7YjsSNs.js} +1 -1
- package/client/dist/assets/{LoopBuilderPage-WmqNpDw2.js → LoopBuilderPage-cu6qiv41.js} +1 -1
- package/client/dist/assets/{LoopPreviewModal-BY5dDezY.js → LoopPreviewModal-Cz9CT647.js} +1 -1
- package/client/dist/assets/{LoopsPage-BcegqJyY.js → LoopsPage-C1PYYWno.js} +1 -1
- package/client/dist/assets/{MinimizedChatsContext-CX1i2kQ8.js → MinimizedChatsContext-D-wIfWD7.js} +1 -1
- package/client/dist/assets/{PluginsPage-BhG3qPda.js → PluginsPage-Bib-5fVd.js} +1 -1
- package/client/dist/assets/{ProjectSettingsDialog-JQdLwCy2.js → ProjectSettingsDialog-K5_ufJmm.js} +1 -1
- package/client/dist/assets/{RepositoryDeliveries-DqmlG0Zs.js → RepositoryDeliveries-BVROW9bi.js} +1 -1
- package/client/dist/assets/{RepositoryScopeSelector-DG8KKPrm.js → RepositoryScopeSelector-Qq2dUoCl.js} +1 -1
- package/client/dist/assets/ReviewPacketPage-tvI4dFpw.js +4 -0
- package/client/dist/assets/{TemplatePreviewModal-1AVv-hu4.js → TemplatePreviewModal-CV3fxeb1.js} +1 -1
- package/client/dist/assets/{TicketDetailModalContext-D2MEhRwJ.js → TicketDetailModalContext-BSpIHNsJ.js} +1 -1
- package/client/dist/assets/{Trans-BLljsfHR.js → Trans-BZWwRo1V.js} +1 -1
- package/client/dist/assets/{agent-D3jkMipn.js → agent-1Sh10wFp.js} +1 -1
- package/client/dist/assets/{agent-BII69Nc0.js → agent-BScqU3oM.js} +1 -1
- package/client/dist/assets/{agent-B76BhAyE.js → agent-Crfgp_yl.js} +1 -1
- package/client/dist/assets/{agent-CYFBDwFD.js → agent-CvaTFLGI.js} +1 -1
- package/client/dist/assets/{agent-CVeMLIu4.js → agent-DH5vUrkg.js} +1 -1
- package/client/dist/assets/{agent-BIO4q6b0.js → agent-DUuWo07e.js} +1 -1
- package/client/dist/assets/{agent-DSrflYFL.js → agent-MlnQFv-P.js} +1 -1
- package/client/dist/assets/{agent-ButS6kwl.js → agent-uG7w5crQ.js} +1 -1
- package/client/dist/assets/{formatDistanceToNow-CbQZkD8M.js → formatDistanceToNow-BHeWIeTB.js} +1 -1
- package/client/dist/assets/{getTimezoneOffsetInMilliseconds-pBVK3rJC.js → getTimezoneOffsetInMilliseconds-DTT9YgCB.js} +1 -1
- package/client/dist/assets/index-D7f-4Igx.css +2 -0
- package/client/dist/assets/{index-DEqG4WdV.js → index-DnVIArMT.js} +34 -34
- package/client/dist/assets/{jira-api-f-sYCIuX.js → jira-api-CbYLdWCi.js} +1 -1
- package/client/dist/assets/packet-B8gXENJV.js +1 -0
- package/client/dist/assets/{packet-DF-iwqqY.js → packet-BTfIuMol.js} +1 -1
- package/client/dist/assets/{packet-BsRimSfZ.js → packet-CFjk65pR.js} +1 -1
- package/client/dist/assets/{packet-C8qzvgrZ.js → packet-CYoLyZf9.js} +1 -1
- package/client/dist/assets/{packet-r7J14m89.js → packet-D-v2OxI7.js} +1 -1
- package/client/dist/assets/{packet-DQ_GnT2b.js → packet-Dg7Ij21z.js} +1 -1
- package/client/dist/assets/{packet-C0pcMd6x.js → packet-tLvSufRp.js} +1 -1
- package/client/dist/assets/{packet-Nb8BLI5h.js → packet-zdb1UItU.js} +1 -1
- package/client/dist/assets/{project-repositories-DAjJbFhm.js → project-repositories-DC4nyJi7.js} +1 -1
- package/client/dist/assets/{spending-DJBbdJyD.js → spending-BT4ahFx2.js} +1 -1
- package/client/dist/assets/{useDesktop-BJ8IRBRt.js → useDesktop-DvDdw7oq.js} +1 -1
- package/client/dist/assets/{useRuntimeRuns-Ch1KUc7k.js → useRuntimeRuns-C6qGuPG6.js} +1 -1
- package/client/dist/assets/{useSharedWebSocket-BN3Lmehi.js → useSharedWebSocket-DkwOZsMN.js} +2 -2
- package/client/dist/index.html +17 -17
- package/docs/internals/safe-pr-review-flow.md +72 -0
- package/package.json +1 -1
- package/server/dist/agent-operator-prompt.js +16 -0
- package/server/dist/db.js +11 -0
- package/server/dist/loop-run-manager.js +4 -1
- package/server/dist/mcp/tools/rails.js +24 -0
- package/server/dist/multi-repo-delivery.js +4 -0
- package/server/dist/pr-follow-up-scope.js +224 -0
- package/server/dist/pr-follow-up.js +75 -0
- package/server/dist/rail-isolated-launch.js +3 -0
- package/server/dist/rail-launch-parser.js +12 -0
- package/server/dist/rail-pr-decision.js +20 -3
- package/server/dist/rail-pr-store.js +24 -3
- package/server/dist/rails-router.js +30 -2
- package/server/dist/review-packet.js +41 -0
- package/client/dist/assets/ReviewPacketPage-DSSi3x16.js +0 -4
- package/client/dist/assets/index-UDzndadF.css +0 -2
- package/client/dist/assets/packet-BTRySHoQ.js +0 -1
|
@@ -162,7 +162,13 @@ async function executePrDecision(deps, input) {
|
|
|
162
162
|
return { status: 404, body: { error: 'Unknown prDeliveryId' } };
|
|
163
163
|
if (row.parent_delivery_id && deps.repositoryChildOf !== row.parent_delivery_id)
|
|
164
164
|
return { status: 409, body: { error: 'repository_delivery_requires_parent', parentDeliveryId: row.parent_delivery_id } };
|
|
165
|
-
|
|
165
|
+
// A manifest alone does not make a repository GROUP: a launch that failed
|
|
166
|
+
// before allocating a single repository delivery persists the parent with
|
|
167
|
+
// its manifest and zero children (observed: `git worktree add` refused
|
|
168
|
+
// because the PR branch was checked out in the main clone). Routing that
|
|
169
|
+
// parent into the group path 404'd on "no repositories" — which the UI read
|
|
170
|
+
// as "already resolved" — and left the rail pinned at pending_decision.
|
|
171
|
+
if (!row.parent_delivery_id && row.execution_manifest && (0, rail_pr_store_1.hasRepositoryDeliveries)(deps.db, row.id)) {
|
|
166
172
|
const { executeRepositoryGroupDecision } = await Promise.resolve().then(() => __importStar(require('./multi-repo-delivery')));
|
|
167
173
|
return executeRepositoryGroupDecision(deps, input);
|
|
168
174
|
}
|
|
@@ -1525,6 +1531,16 @@ async function runDiscard(deps, row, opts = { removeNeedsReview: true }) {
|
|
|
1525
1531
|
// borrows the PR/ticket lifecycle. Per-unit ownership below independently
|
|
1526
1532
|
// prevents deletion of borrowed/pre-existing head refs for fresh replacements.
|
|
1527
1533
|
const preserveExternalReview = row.is_continuation === 1;
|
|
1534
|
+
// A preparation failure never ran: no worktree, no branch, no commit, no PR.
|
|
1535
|
+
// Discarding it only closes the attempt and frees the rail — the spec keeps
|
|
1536
|
+
// the status it had (typically on_review from a still-open earlier PR), the
|
|
1537
|
+
// backlog/Jira are not told about a delivery that never existed, and no
|
|
1538
|
+
// resource cleanup can be owed. Distinct from implementation_failed, which
|
|
1539
|
+
// did run and did move the ticket.
|
|
1540
|
+
const preparationFailure = row.decision === 'pr_failed' &&
|
|
1541
|
+
row.implementation_outcome === 'failed' &&
|
|
1542
|
+
!row.pr_url && !row.delivery_sha && !preserveExternalReview &&
|
|
1543
|
+
snap.branches.length === 0 && snap.worktreeIds.length === 0;
|
|
1528
1544
|
const cleanupWarnings = [];
|
|
1529
1545
|
// A continuation borrows an existing PR/head. Discarding its local iteration
|
|
1530
1546
|
// may remove Specrails' worktree, but never closes or deletes borrowed review
|
|
@@ -1620,7 +1636,7 @@ async function runDiscard(deps, row, opts = { removeNeedsReview: true }) {
|
|
|
1620
1636
|
statusCode: cleanupWarnings.length > 0 ? 'cleanup_incomplete' : 'discarded',
|
|
1621
1637
|
cleanupWarnings,
|
|
1622
1638
|
};
|
|
1623
|
-
const conflict = preserveExternalReview
|
|
1639
|
+
const conflict = preserveExternalReview || preparationFailure
|
|
1624
1640
|
? casTransition(deps, row, 'discarded', terminalPatch)
|
|
1625
1641
|
: casTransitionWithTicketEffect(deps, row, 'discarded', terminalPatch, {
|
|
1626
1642
|
deliveryId: row.id,
|
|
@@ -1634,7 +1650,7 @@ async function runDiscard(deps, row, opts = { removeNeedsReview: true }) {
|
|
|
1634
1650
|
if (conflict)
|
|
1635
1651
|
return conflict;
|
|
1636
1652
|
pauseChainsOnDiscard(deps, row);
|
|
1637
|
-
if (!preserveExternalReview)
|
|
1653
|
+
if (!preserveExternalReview && !preparationFailure)
|
|
1638
1654
|
applyTerminalTicketEffect(deps, row, 'discarded', cleanupWarnings);
|
|
1639
1655
|
finalizeTransition(deps, row.id);
|
|
1640
1656
|
return {
|
|
@@ -1643,6 +1659,7 @@ async function runDiscard(deps, row, opts = { removeNeedsReview: true }) {
|
|
|
1643
1659
|
ok: true,
|
|
1644
1660
|
decision: 'discarded',
|
|
1645
1661
|
...(cleanupWarnings.length > 0 ? { cleanupWarnings } : {}),
|
|
1662
|
+
...(preparationFailure ? { preparationFailure: true } : {}),
|
|
1646
1663
|
...(preserveExternalReview ? { preservedBorrowedReview: true, preservedExternalReview: true } : {}),
|
|
1647
1664
|
},
|
|
1648
1665
|
};
|
|
@@ -10,6 +10,7 @@ exports.createPrDeliveryGeneration = createPrDeliveryGeneration;
|
|
|
10
10
|
exports.failPrDeliveryAndRestoreSuperseded = failPrDeliveryAndRestoreSuperseded;
|
|
11
11
|
exports.getPrDelivery = getPrDelivery;
|
|
12
12
|
exports.getActivePrDeliveryByRail = getActivePrDeliveryByRail;
|
|
13
|
+
exports.hasRepositoryDeliveries = hasRepositoryDeliveries;
|
|
13
14
|
exports.listActivePrDeliveries = listActivePrDeliveries;
|
|
14
15
|
exports.listTerminalPrDeliveries = listTerminalPrDeliveries;
|
|
15
16
|
exports.getLatestTerminalPrDeliveryTouchingTicketSet = getLatestTerminalPrDeliveryTouchingTicketSet;
|
|
@@ -30,6 +31,16 @@ exports.toPrDeliverySnapshot = toPrDeliverySnapshot;
|
|
|
30
31
|
exports.toRailPrStateMessage = toRailPrStateMessage;
|
|
31
32
|
exports.toPrDecisionCardEnvelope = toPrDecisionCardEnvelope;
|
|
32
33
|
exports.missionPhaseForDecision = missionPhaseForDecision;
|
|
34
|
+
/**
|
|
35
|
+
* CRUD for the `rail_pr_deliveries` ledger (migration 36) — one row per isolated
|
|
36
|
+
* rail LAUNCH tracking the ask-first PR decision lifecycle. This is the single
|
|
37
|
+
* authoritative server-side state both decision surfaces (the rail row on the
|
|
38
|
+
* dashboard and the launching agent-chat conversation) read and write, so the
|
|
39
|
+
* two surfaces never desync and a refresh/restart never loses a pending
|
|
40
|
+
* decision. Pure data access; the PR plumbing lives in rail-pr-delivery /
|
|
41
|
+
* pr-publisher and the launch wiring in rail-isolated-launch.
|
|
42
|
+
*/
|
|
43
|
+
const pr_follow_up_1 = require("./pr-follow-up");
|
|
33
44
|
const ids_1 = require("./ids");
|
|
34
45
|
const multi_repo_execution_store_1 = require("./multi-repo-execution-store");
|
|
35
46
|
/** Defensive per-ticket cap; contract-layer specs run long but bounded. */
|
|
@@ -88,11 +99,11 @@ function createPrDelivery(db, input) {
|
|
|
88
99
|
loop_name, origin_surface, origin_conversation_id,
|
|
89
100
|
implementation_outcome, delivery_outcome, status_code,
|
|
90
101
|
is_continuation, supersedes_delivery_id, spec_snapshot,
|
|
91
|
-
revision_note, revision_of, parent_delivery_id, repository_id, repository_path
|
|
102
|
+
revision_note, revision_of, parent_delivery_id, repository_id, repository_path, follow_up
|
|
92
103
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'running', 'pending',
|
|
93
|
-
'implementation_running', ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.railIndex, input.loopId ?? null, input.railKey, JSON.stringify(input.ticketIds), input.baseBranch, input.loopName, input.originSurface, input.originConversationId ?? null, input.isContinuation ? 1 : 0, input.supersedesDeliveryId ?? null, input.specSnapshot && input.specSnapshot.length > 0
|
|
104
|
+
'implementation_running', ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.railIndex, input.loopId ?? null, input.railKey, JSON.stringify(input.ticketIds), input.baseBranch, input.loopName, input.originSurface, input.originConversationId ?? null, input.isContinuation ? 1 : 0, input.supersedesDeliveryId ?? null, input.specSnapshot && input.specSnapshot.length > 0
|
|
94
105
|
? JSON.stringify(boundSpecSnapshot(input.specSnapshot))
|
|
95
|
-
: null, input.revisionNote ? boundRevisionNote(input.revisionNote) : null, input.revisionOf ?? null, input.parentDeliveryId ?? null, input.repositoryId ?? null, input.repositoryPath ?? null);
|
|
106
|
+
: null, input.revisionNote ? boundRevisionNote(input.revisionNote) : null, input.revisionOf ?? null, input.parentDeliveryId ?? null, input.repositoryId ?? null, input.repositoryPath ?? null, input.followUp ? JSON.stringify(input.followUp) : null);
|
|
96
107
|
return getPrDelivery(db, id);
|
|
97
108
|
}
|
|
98
109
|
class PrDeliveryGenerationConflict extends Error {
|
|
@@ -203,6 +214,15 @@ function getActivePrDeliveryByRail(db, railIndex) {
|
|
|
203
214
|
.get(railIndex);
|
|
204
215
|
}
|
|
205
216
|
/** Every non-terminal delivery — hydrates the GET /rails prDeliveries snapshot. */
|
|
217
|
+
/** True when a delivery group has at least one per-repository child row. A
|
|
218
|
+
* parent that carries an execution manifest but no children is a launch that
|
|
219
|
+
* failed BEFORE any repository delivery was allocated (worktree add refused,
|
|
220
|
+
* DB setup error…) — it must be decided as an ordinary single row, not routed
|
|
221
|
+
* to the per-repository group machinery, which has nothing to act on. */
|
|
222
|
+
function hasRepositoryDeliveries(db, parentId) {
|
|
223
|
+
const row = db.prepare('SELECT 1 AS present FROM rail_pr_deliveries WHERE parent_delivery_id = ? LIMIT 1').get(parentId);
|
|
224
|
+
return Boolean(row);
|
|
225
|
+
}
|
|
206
226
|
function listActivePrDeliveries(db) {
|
|
207
227
|
return db
|
|
208
228
|
.prepare(`SELECT * FROM rail_pr_deliveries
|
|
@@ -597,6 +617,7 @@ function toPrDeliverySnapshot(row) {
|
|
|
597
617
|
runIds: parseJsonArray(row.run_ids ?? '[]'),
|
|
598
618
|
originSurface: row.origin_surface,
|
|
599
619
|
originConversationId: row.origin_conversation_id,
|
|
620
|
+
followUp: (0, pr_follow_up_1.readFollowUp)(row.follow_up),
|
|
600
621
|
createdAt: row.created_at,
|
|
601
622
|
updatedAt: row.updated_at,
|
|
602
623
|
};
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.prDeliveryRevisionAllowed = prDeliveryRevisionAllowed;
|
|
7
7
|
exports.createRailsRouter = createRailsRouter;
|
|
8
|
+
const pr_follow_up_1 = require("./pr-follow-up");
|
|
8
9
|
const agent_runtime_settings_1 = require("./agent-runtime-settings");
|
|
9
10
|
const path_1 = __importDefault(require("path"));
|
|
10
11
|
const express_1 = require("express");
|
|
@@ -477,7 +478,29 @@ function createRailsRouter() {
|
|
|
477
478
|
return;
|
|
478
479
|
}
|
|
479
480
|
let { mode = 'implement' } = req.body ?? {};
|
|
480
|
-
const { repositoryIds: rawRepositoryIds, baseDeliveryIds, profileName, aiEngine, model, loopId: rawLoopId, reasoning_effort, originConversationId, originSurface, targetPrNumber, revisionOfDeliveryId, revisionNote, baseBranch: rawBaseBranch } = req.body ?? {};
|
|
481
|
+
const { repositoryIds: rawRepositoryIds, baseDeliveryIds, profileName, aiEngine, model, loopId: rawLoopId, reasoning_effort, originConversationId, originSurface, targetPrNumber, revisionOfDeliveryId, revisionNote, baseBranch: rawBaseBranch, followUp: rawFollowUp } = req.body ?? {};
|
|
482
|
+
// PR review follow-up (pr-follow-up-fixes): a typed, bounded, FROZEN scope
|
|
483
|
+
// for "resolve these review comments". It rides the delivery row and every
|
|
484
|
+
// ai-step prompt — never the spec, whose description Jira-linked projects
|
|
485
|
+
// sync. It needs something to follow up ON: an explicit target PR or the
|
|
486
|
+
// delivery being revised.
|
|
487
|
+
let followUp;
|
|
488
|
+
if (rawFollowUp !== undefined && rawFollowUp !== null) {
|
|
489
|
+
try {
|
|
490
|
+
followUp = (0, pr_follow_up_1.freezeFollowUp)((0, pr_follow_up_1.parseFollowUpInput)(rawFollowUp));
|
|
491
|
+
}
|
|
492
|
+
catch (err) {
|
|
493
|
+
if (err instanceof pr_follow_up_1.FollowUpValidationError) {
|
|
494
|
+
res.status(400).json({ error: 'invalid_follow_up', code: err.code, detail: err.message });
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
throw err;
|
|
498
|
+
}
|
|
499
|
+
if (typeof targetPrNumber !== 'number' && !revisionOfDeliveryId) {
|
|
500
|
+
res.status(400).json({ error: 'follow_up_requires_target', detail: 'followUp needs the pull request to follow up on: pass targetPrNumber (an open PR) or revisionOfDeliveryId (an undecided delivery)' });
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
481
504
|
// Revision launch (nontech-review-experience Wave 3): the user asked for a
|
|
482
505
|
// change to a delivery that is already awaiting their decision. Shape is
|
|
483
506
|
// validated here; the narrow guard exemption is enforced below.
|
|
@@ -587,6 +610,10 @@ function createRailsRouter() {
|
|
|
587
610
|
res.status(400).json({ error: 'target_pr_requires_pr_mode', detail: 'targetPrNumber requires loops and PR delivery to be enabled' });
|
|
588
611
|
return;
|
|
589
612
|
}
|
|
613
|
+
if (followUp && (!(0, feature_flags_1.isLoopsEnabled)() || !(0, rail_isolation_1.isRailPrDeliveryEnabled)())) {
|
|
614
|
+
res.status(400).json({ error: 'follow_up_requires_pr_mode', detail: 'a PR review follow-up runs on the isolated PR-delivery path; loops and PR delivery must be enabled' });
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
590
617
|
// Interactive in-job chat is ON by default for providers that expose the
|
|
591
618
|
// spawn-time gate in QueueManager (kill-switch + persistent-stdin
|
|
592
619
|
// capability) decides, so the launch no longer passes an explicit flag. A
|
|
@@ -1039,8 +1066,9 @@ function createRailsRouter() {
|
|
|
1039
1066
|
// Revision of an undecided delivery: the guard above proved the
|
|
1040
1067
|
// exemption, so pass the contract through for supersession.
|
|
1041
1068
|
...(revisionRequest ? { revision: revisionRequest } : {}),
|
|
1069
|
+
...(followUp ? { followUp } : {}),
|
|
1042
1070
|
});
|
|
1043
|
-
res.status(202).json({ loopRunIds: ids, railIndex, mode, isolated: true });
|
|
1071
|
+
res.status(202).json({ loopRunIds: ids, railIndex, mode, isolated: true, ...(followUp ? { followUp: { id: followUp.id, version: followUp.version, hash: followUp.hash } } : {}) });
|
|
1044
1072
|
return;
|
|
1045
1073
|
}
|
|
1046
1074
|
catch (err) {
|
|
@@ -5,6 +5,36 @@ exports.selectVariant = selectVariant;
|
|
|
5
5
|
exports.computeDriftNudges = computeDriftNudges;
|
|
6
6
|
exports.composeReviewPacket = composeReviewPacket;
|
|
7
7
|
exports.packetHasUnsourcedNumericClaim = packetHasUnsourcedNumericClaim;
|
|
8
|
+
/**
|
|
9
|
+
* Review-packet composer (nontech-review-experience Wave 2).
|
|
10
|
+
*
|
|
11
|
+
* Turns a settled delivery generation into a structured document a
|
|
12
|
+
* non-technical person can judge — with ZERO model calls and zero live-store
|
|
13
|
+
* reads. Everything comes from durable rows: the launch-time spec snapshot, the
|
|
14
|
+
* settle-time evidence harvest, per-unit outcomes, provenance line stats, and
|
|
15
|
+
* the invocation cost sum. Composing is therefore free, idempotent, and
|
|
16
|
+
* reproducible after a restart.
|
|
17
|
+
*
|
|
18
|
+
* THE HONESTY CONTRACT (the reason this module is shaped like this):
|
|
19
|
+
*
|
|
20
|
+
* Verification claims are split into three tiers by their SOURCE, and the tier
|
|
21
|
+
* travels with the claim so the UI can label it:
|
|
22
|
+
*
|
|
23
|
+
* app-verified — Specrails measured it (diff stats, changed test files,
|
|
24
|
+
* the decider's routed verdict). Trustworthy.
|
|
25
|
+
* ai-reported — the agent said so (the VERIFICATION sentinel, its verify
|
|
26
|
+
* output). Rendered with an explicit "we did not run this"
|
|
27
|
+
* caveat, never as fact.
|
|
28
|
+
* reviewer-score— sr-reviewer's own confidence-score.json. Labelled as the
|
|
29
|
+
* AI grading itself, surfacing the documented
|
|
30
|
+
* human-review band.
|
|
31
|
+
*
|
|
32
|
+
* A numeric verification claim (e.g. "68 tests passed") is NEVER emitted: no
|
|
33
|
+
* structured source for it exists today, so scraping it out of prose would
|
|
34
|
+
* launder a self-report into a measurement. `testEvidence` states which test
|
|
35
|
+
* FILES changed, which is all the diff can actually prove.
|
|
36
|
+
*/
|
|
37
|
+
const pr_follow_up_1 = require("./pr-follow-up");
|
|
8
38
|
const delivery_evidence_1 = require("./delivery-evidence");
|
|
9
39
|
const rail_pr_store_1 = require("./rail-pr-store");
|
|
10
40
|
const pr_body_1 = require("./pr-body");
|
|
@@ -244,6 +274,14 @@ function computeDriftNudges(input) {
|
|
|
244
274
|
}
|
|
245
275
|
return nudges;
|
|
246
276
|
}
|
|
277
|
+
/** Where a follow-up run's `FOLLOW-UP REPORT` can be found after settle: the
|
|
278
|
+
* harvested verify tails (the final reply of record). Nothing else is guessed. */
|
|
279
|
+
function followUpReportSource(evidence) {
|
|
280
|
+
if (!evidence)
|
|
281
|
+
return null;
|
|
282
|
+
const parts = evidence.units.flatMap((unit) => [unit.verifyTail, unit.sentinelDetail]).filter((v) => typeof v === 'string' && v.length > 0);
|
|
283
|
+
return parts.length > 0 ? parts.join('\n') : null;
|
|
284
|
+
}
|
|
247
285
|
function composeReviewPacket({ db, row, repositoryId = row.repository_id ?? undefined, includeLegacyProvenance = false }) {
|
|
248
286
|
const repository = repositoryId ? { repositoryId, includeLegacy: includeLegacyProvenance } : undefined;
|
|
249
287
|
const ticketIds = safeParse(row.ticket_ids, []);
|
|
@@ -251,6 +289,7 @@ function composeReviewPacket({ db, row, repositoryId = row.repository_id ?? unde
|
|
|
251
289
|
const runIds = safeParse(row.run_ids, []);
|
|
252
290
|
const snapshot = (0, rail_pr_store_1.readSpecSnapshot)(row.spec_snapshot);
|
|
253
291
|
const evidence = (0, delivery_evidence_1.readSettleEvidence)(row.settle_evidence);
|
|
292
|
+
const followUp = (0, pr_follow_up_1.readFollowUp)(row.follow_up);
|
|
254
293
|
const churn = churnForRuns(db, runIds, repository);
|
|
255
294
|
const variant = selectVariant(row, units);
|
|
256
295
|
const confidence = (evidence?.units ?? [])
|
|
@@ -346,6 +385,8 @@ function composeReviewPacket({ db, row, repositoryId = row.repository_id ?? unde
|
|
|
346
385
|
runIds,
|
|
347
386
|
supersedesDeliveryId: row.supersedes_delivery_id,
|
|
348
387
|
revisionNote: row.revision_note,
|
|
388
|
+
followUp,
|
|
389
|
+
followUpReport: followUp ? (0, pr_follow_up_1.parseFollowUpReport)(followUpReportSource(evidence), followUp) : null,
|
|
349
390
|
versions,
|
|
350
391
|
chainCostUsd: chainCosts.length > 0 ? chainCosts.reduce((sum, value) => sum + value, 0) : null,
|
|
351
392
|
chainCostEstimated: versions.some((version) => version.costEstimated),
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./jsx-runtime-zu2_FqZY.js";import{d as r,f as i,u as a}from"./chunk-KS7C4IRE-DEKu087k.js";import{B as ee,U as te,n as ne}from"./TicketDetailModalContext-D2MEhRwJ.js";import{n as re,t as o}from"./createLucideIcon-Bjbbp_KS.js";import{a as s,r as ie}from"./useDesktop-BJ8IRBRt.js";import{C as ae,E as oe,b as se,r as ce,t as le,w as ue}from"./RepositoryDeliveries-DqmlG0Zs.js";import{n as de}from"./save-B6wGWwBR.js";import{u as fe}from"./MinimizedChatsContext-CX1i2kQ8.js";import{t as c}from"./loader-circle-DcygOQpC.js";import{t as l}from"./sparkles-DrY8hb0X.js";import{t as u}from"./triangle-alert-H9T4jAmh.js";import{t as d}from"./utils-BC4DHlz2.js";import{n as f,t as p}from"./lib-CGdyxIWg.js";import{Dt as pe,Gt as me,Rt as m,d as he,dt as h,zt as g}from"./index-DEqG4WdV.js";var ge=o(`circle-dollar-sign`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8`,key:`1h4pet`}],[`path`,{d:`M12 18V6`,key:`zqpxq5`}]]),_=o(`file-diff`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M9 10h6`,key:`9gxzsh`}],[`path`,{d:`M12 13V7`,key:`h0r20n`}],[`path`,{d:`M9 17h6`,key:`r8uit2`}]]),v=e(t(),1),y=n();function b(e){return e.split(/\n{2,}/).map(e=>{if(e.includes(`
|
|
2
|
-
`))return e;let t=e.match(/(?:^|\s)(\d{1,2})\.\s+(?=\S)/g);return!t||t.length<3?e:e.replace(/\s+(\d{1,2})\.\s+(?=\S)/g,(e,t,n)=>n===0?e:`\n${t}. `)}).join(`
|
|
3
|
-
|
|
4
|
-
`)}function _e({children:e,muted:t=!1,className:n}){let r=(0,v.useMemo)(()=>({a:({href:e,children:t})=>(0,y.jsx)(`a`,{href:e,target:`_blank`,rel:`noreferrer`,className:`text-accent-primary underline decoration-accent-primary/40 underline-offset-2 hover:decoration-accent-primary`,children:t}),img:()=>null,code:({className:e,children:t})=>e?(0,y.jsx)(`code`,{className:e,children:t}):(0,y.jsx)(`code`,{className:`rounded-md border border-border/50 bg-background-deep/60 px-1.5 py-px font-mono text-[0.85em] text-accent-info`,children:t})}),[]);return(0,y.jsx)(`div`,{"data-testid":`packet-markdown`,className:d(`prose prose-invert prose-sm max-w-none leading-relaxed`,`prose-p:my-1.5 prose-headings:mt-3 prose-headings:mb-1 prose-headings:text-sm prose-headings:font-semibold`,`prose-strong:text-foreground prose-ul:my-1.5 prose-ol:my-1.5 prose-li:my-0.5 prose-li:marker:text-accent-primary/70`,`prose-pre:my-2 prose-pre:rounded-lg prose-pre:border prose-pre:border-border/50 prose-pre:bg-background-deep/60 prose-pre:text-xs`,`prose-blockquote:border-accent-primary/40 prose-blockquote:text-muted-foreground prose-hr:border-border/50`,t?`text-muted-foreground`:`text-foreground/85`,n),children:(0,y.jsx)(f,{remarkPlugins:[p],skipHtml:!0,components:r,children:b(e)})})}var x=(e={})=>({verbs:[],acceptMeaning:null,fineControlOnly:!1,inFlight:!1,terminal:!1,requiresIrreversibleConfirm:!1,...e});function ve(e){let{decision:t,presentation:n,prUrl:r,canCreatePr:i}=e;if(t===`building`)return x({inFlight:!0});if(t===`merged`||t===`discarded`||n.superseded)return x({terminal:!0});if(n.manualRecovery||n.recoveryUnavailable||n.recoveryRecheck||n.retryablePush||n.retryablePrCreation||n.closed||n.deliveryBlocked&&!n.implementationFailed)return x({fineControlOnly:!0});if(n.noChanges)return x({verbs:[`accept`,`request-changes`],acceptMeaning:`mark-done`});if(n.implementationFailed)return x({verbs:n.succeededCount>0?[`request-changes`,`discard`]:[`discard`]});if(t===`pr_draft`)return x(r?{verbs:[`accept`,`request-changes`,`discard`],acceptMeaning:`publish`}:{fineControlOnly:!0});if(t===`pr_ready`)return x({verbs:[`request-changes`,`discard`]});if(t===`on_review`){let e=i?`create-pr`:`merge-local`;return x({verbs:[`accept`,`request-changes`,`discard`],acceptMeaning:e,requiresIrreversibleConfirm:e===`merge-local`})}return x({fineControlOnly:!0})}function ye(e,t){if(e===`discard`)return`discard`;if(e===`request-changes`)return null;switch(t.acceptMeaning){case`create-pr`:return`create-pr`;case`publish`:return`publish`;case`merge-local`:return`merge-local`;case`mark-done`:return`acknowledge-no-changes`;default:return null}}var be=[`app-verified`,`ai-reported`,`reviewer-score`],xe={"app-verified":h,"ai-reported":l,"reviewer-score":_},Se={"app-verified":`text-accent-success border-accent-success/30 bg-accent-success/5`,"ai-reported":`text-accent-highlight border-accent-highlight/30 bg-accent-highlight/5`,"reviewer-score":`text-accent-info border-accent-info/30 bg-accent-info/5`};function S({item:e}){let{t}=re(`packet`);return(0,y.jsxs)(`li`,{className:`flex flex-col gap-1 py-1.5`,children:[(0,y.jsx)(`span`,{className:`text-sm text-foreground`,children:t(e.code,{...e.values??{},defaultValue:e.code})}),e.rawExcerpt?(0,y.jsx)(`pre`,{className:`max-h-32 overflow-auto rounded border border-border/60 bg-background-deep/60 p-2 text-[11px] leading-relaxed text-muted-foreground whitespace-pre-wrap`,children:e.rawExcerpt}):null]})}function Ce(e){return e.implementationOutcome===`failed`?`failed`:e.deliveryOutcome===`no_changes`||e.implementationOutcome===`succeeded`&&e.changed===!1?`noChanges`:e.deliveryOutcome===`not_started`?`notStarted`:e.implementationOutcome===`succeeded`?`succeeded`:`unknown`}var we={succeeded:`border-accent-success/40 bg-accent-success/10 text-accent-success`,noChanges:`border-accent-info/40 bg-accent-info/10 text-accent-info`,failed:`border-destructive/40 bg-destructive/10 text-destructive`,notStarted:`border-border bg-background-deep/50 text-muted-foreground`,unknown:`border-border bg-background-deep/50 text-muted-foreground`};function C({title:e,children:t,defaultOpen:n=!1,badge:r}){let[i,a]=(0,v.useState)(n);return(0,y.jsxs)(`div`,{className:`rounded-lg border border-border/60 bg-surface/40`,children:[(0,y.jsxs)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`flex w-full items-center gap-2 px-4 py-3 text-left`,"aria-expanded":i,children:[i?(0,y.jsx)(g,{className:`size-4 shrink-0 text-muted-foreground`,"aria-hidden":!0}):(0,y.jsx)(m,{className:`size-4 shrink-0 text-muted-foreground`,"aria-hidden":!0}),(0,y.jsx)(`span`,{className:`flex-1 text-sm font-medium text-foreground`,children:e}),r]}),i?(0,y.jsx)(`div`,{className:`border-t border-border/60 px-4 py-3`,children:t}):null]})}function w(e={}){let t=r(),n=e.prDeliveryId??t.prDeliveryId,{t:o}=re([`packet`,`common`]),l=a(),[d,f]=i(),p=d.get(`repositoryId`),m=(0,v.useRef)(0),h=e.onClose??(()=>l(`/`)),{activeProjectId:g}=ie(),_=ce(g),b=n?_.has(n):!1,{act:x,checkout:w}=he(),{openTicketDetail:Te}=ne(),T=JSON.stringify([g,n,p]),E=(0,v.useRef)({key:T,epoch:0});E.current.key!==T&&(E.current={key:T,epoch:E.current.epoch+1});let D=E.current.epoch,O=(0,v.useRef)(!0);(0,v.useEffect)(()=>(O.current=!0,()=>{O.current=!1}),[]);let k=(0,v.useCallback)(()=>O.current&&E.current.key===T&&E.current.epoch===D,[T,D]),[A,j]=(0,v.useState)(null),M=A?.key===T&&A.epoch===D?A:null,N=M?.data??null,P=M?.loading??!0,F=M?.error??null,[I,L]=(0,v.useState)(null),[Ee,R]=(0,v.useState)(!1),[z,B]=(0,v.useState)(null),[V,H]=(0,v.useState)(``),[U,W]=(0,v.useState)(!1),[De,G]=(0,v.useState)(null),[Oe,K]=(0,v.useState)(!1),q=(0,v.useCallback)(async()=>{if(!n||!g||!k())return;let e=++m.current,t=()=>k()&&m.current===e;j(e=>({key:T,epoch:D,data:e?.key===T&&e.epoch===D?e.data:null,loading:!0,error:null}));try{let e=p?`?repositoryId=${encodeURIComponent(p)}`:``,r=await fetch(`${s()}/rails/pr-deliveries/${n}/packet${e}`);if(!t())return;if(!r.ok){j({key:T,epoch:D,data:null,loading:!1,error:r.status===404?`notFound`:`loadFailed`});return}let i=await r.json();if(!t())return;j({key:T,epoch:D,data:i,loading:!1,error:null})}catch{if(!t())return;j({key:T,epoch:D,data:null,loading:!1,error:`loadFailed`})}},[n,g,p,T,D,k]);(0,v.useEffect)(()=>(q(),R(!1),K(!1),L(null),B(null),G(null),W(!1),H(``),()=>{m.current++}),[q]);let J=(0,v.useMemo)(()=>ue(N?.snapshot),[N?.snapshot]),Y=N?.packet??null,X=P||I!==null||U||!!J?.operation,Z=N?.acceptCapability??null,Q=(0,v.useMemo)(()=>{if(!Y)return null;let e=oe({decision:Y.decision,ticketIds:Y.ticketIds,prState:Y.prUrl?`pr-created`:`none`,statusCode:Y.statusCode,prUrl:Y.prUrl,runIds:Y.runIds});return ve({decision:Y.decision,presentation:e,prUrl:Y.prUrl,canCreatePr:Z?.target===`create-pr`})},[Y,Z]),$=(0,v.useCallback)(async e=>{if(!Y||!Q||X||!k())return;let t=ye(e,Q);if(t){B(null),L(e);try{let e=await(p&&J?x(J.railIndex,t,J.decision,J.prDeliveryId,p):x(Y.railIndex,t,Y.decision,Y.prDeliveryId));if(!k())return;e.ok?g&&se(g):B(e.status===409&&e.error===`stale_decision`?`alreadyResolved`:`actionFailed`),await q()}finally{k()&&(L(null),R(!1))}}},[x,g,q,Y,Q,J,p,X,k]),ke=(0,v.useCallback)(async()=>{if(!(!Y||!V.trim()||!g||X||!k())){G(null),W(!0);try{let e=await fetch(`${s()}/rails/${Y.railIndex}/launch`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({revisionOfDeliveryId:J?.prDeliveryId??Y.prDeliveryId,revisionNote:V.trim(),...J?.executionManifest?{repositoryIds:J.executionManifest.selectedRepositoryIds}:{}})});if(!k())return;if(!e.ok){let t=await e.json().catch(()=>null);if(!k())return;G(t?.error===`invalid_revision_target`?`revisionStale`:`revisionFailed`);return}H(``),K(!1),await q()}catch{k()&&G(`revisionFailed`)}finally{k()&&W(!1)}}},[g,q,Y,V,J,X,k]);if(P&&!Y)return(0,y.jsxs)(`div`,{className:`flex h-full items-center justify-center text-muted-foreground`,children:[(0,y.jsx)(c,{className:`mr-2 size-4 animate-spin`,"aria-hidden":!0}),o(`common:states.loading`)]});if(F||!Y||!Q)return(0,y.jsxs)(`div`,{className:`mx-auto flex max-w-2xl flex-col items-center gap-4 p-10 text-center`,children:[(0,y.jsx)(u,{className:`size-6 text-accent-warning`,"aria-hidden":!0}),(0,y.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:o(F===`notFound`?`error.notFound`:`error.loadFailed`)}),(0,y.jsx)(`button`,{type:`button`,onClick:h,className:`rounded-md border border-border px-3 py-1.5 text-sm text-foreground hover:bg-surface`,children:o(`backToBoard`)})]});let Ae=be.map(e=>({tier:e,items:Y.proof.filter(t=>t.tier===e)})).filter(e=>e.items.length>0),je=Y.cost.totalUsd===null?`—`:`${Y.cost.estimated?`~`:``}$${Y.cost.totalUsd.toFixed(2)}`;return(0,y.jsxs)(`div`,{className:`mx-auto flex w-full max-w-3xl flex-col gap-4 p-6`,children:[(0,y.jsxs)(`button`,{type:`button`,onClick:h,className:`flex w-fit items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground`,children:[(0,y.jsx)(de,{className:`size-3.5`,"aria-hidden":!0}),o(`backToBoard`)]}),J?.repositoryDeliveries?.length?(0,y.jsxs)(y.Fragment,{children:[(0,y.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[o(`common:repositories.select`),(0,y.jsxs)(`select`,{value:p??``,onChange:e=>{let t=new URLSearchParams(d);e.target.value?t.set(`repositoryId`,e.target.value):t.delete(`repositoryId`),f(t,{replace:!0})},className:`rounded border border-border bg-background px-2 py-1`,children:[(0,y.jsx)(`option`,{value:``,children:o(`common:repositories.all`)}),J.repositoryDeliveries.map(e=>(0,y.jsx)(`option`,{value:e.repositoryId,children:e.name},e.repositoryId))]})]}),(0,y.jsx)(le,{deliveryId:J.prDeliveryId,repositories:J.repositoryDeliveries,busy:X,onAct:async(e,t)=>{if(!(X||!k())){L(`accept`);try{let n=await x(J.railIndex,e,J.decision,J.prDeliveryId,t);if(!k())return;n.ok||B(`actionFailed`),await q()}finally{k()&&L(null)}}},onCheckout:async e=>{if(!(X||!k())){L(`accept`);try{let t=await w(J.railIndex,J.prDeliveryId,e);if(!k())return;t.ok||B(`actionFailed`),await q()}finally{k()&&L(null)}}}})]}):null,(0,y.jsxs)(`div`,{className:`rounded-xl border border-border/70 bg-surface/60 p-5 shadow-sm`,children:[(0,y.jsx)(`h1`,{className:`text-lg font-semibold text-foreground`,children:o(Y.headlineCode,{count:Y.totalCount,succeeded:Y.succeededCount,total:Y.totalCount,defaultValue:Y.headlineCode})}),(0,y.jsxs)(`div`,{className:`mt-2 flex flex-wrap items-center gap-2 text-xs`,children:[Y.confidence?.overall!==null&&Y.confidence?.overall!==void 0?(0,y.jsx)(`span`,{className:`inline-flex items-center gap-1 rounded-full border border-accent-info/30 bg-accent-info/10 px-2 py-0.5 text-accent-info`,title:o(`confidence.tooltip`),children:o(`confidence.pill`,{overall:Y.confidence.overall})}):(0,y.jsx)(`span`,{className:`inline-flex items-center gap-1 rounded-full border border-border bg-background-deep/50 px-2 py-0.5 text-muted-foreground`,children:o(`confidence.unavailable`)}),(0,y.jsxs)(`span`,{className:`inline-flex items-center gap-1 text-muted-foreground`,children:[(0,y.jsx)(ge,{className:`size-3.5`,"aria-hidden":!0}),o(`cost.thisBuild`,{amount:je})]}),Y.prUrl?(0,y.jsxs)(`a`,{href:Y.prUrl,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1 text-accent-info hover:underline`,children:[(0,y.jsx)(te,{className:`size-3.5`,"aria-hidden":!0}),o(`openPr`,{number:Y.prNumber??``})]}):null]}),Q.fineControlOnly?(0,y.jsx)(`p`,{className:`mt-4 rounded-md border border-accent-warning/30 bg-accent-warning/5 px-3 py-2 text-xs text-accent-warning`,children:o(`fineControlOnly`)}):Q.inFlight?(0,y.jsxs)(`p`,{className:`mt-4 flex items-center gap-2 text-sm text-muted-foreground`,children:[(0,y.jsx)(c,{className:`size-4 animate-spin`,"aria-hidden":!0}),o(`stillWorking`)]}):Q.terminal?(0,y.jsx)(`p`,{className:`mt-4 text-sm text-muted-foreground`,children:o(`alreadyResolved`)}):(0,y.jsxs)(`div`,{className:`mt-4 flex flex-wrap items-center gap-2`,children:[Q.verbs.includes(`accept`)&&(!J?.repositoryDeliveries?.length||p)?Ee?(0,y.jsxs)(`div`,{className:`flex w-full flex-col gap-2 rounded-md border border-destructive/40 bg-destructive/5 p-3`,children:[(0,y.jsx)(`p`,{className:`text-xs text-foreground`,children:o(`accept.irreversibleWarning`)}),(0,y.jsxs)(`div`,{className:`flex gap-2`,children:[(0,y.jsx)(`button`,{type:`button`,onClick:()=>void $(`accept`),disabled:X,className:`rounded-md bg-destructive px-3 py-1.5 text-sm font-medium text-white disabled:opacity-50`,"data-testid":`packet-accept-confirm`,children:o(`accept.irreversibleConfirm`)}),(0,y.jsx)(`button`,{type:`button`,onClick:()=>R(!1),className:`rounded-md border border-border px-3 py-1.5 text-sm text-foreground`,children:o(`common:actions.cancel`)})]})]}):(0,y.jsxs)(`button`,{type:`button`,onClick:()=>{Q.requiresIrreversibleConfirm?R(!0):$(`accept`)},disabled:X,className:`inline-flex items-center gap-1.5 rounded-md bg-accent-success px-3 py-1.5 text-sm font-medium text-white disabled:opacity-50`,"data-testid":`packet-accept`,children:[I===`accept`?(0,y.jsx)(c,{className:`size-4 animate-spin`,"aria-hidden":!0}):(0,y.jsx)(fe,{className:`size-4`,"aria-hidden":!0}),o(`accept.${Q.acceptMeaning??`generic`}`)]}):null,Q.verbs.includes(`request-changes`)?(0,y.jsxs)(`button`,{type:`button`,onClick:()=>K(e=>!e),disabled:X||U,"aria-expanded":Oe,className:`inline-flex items-center gap-1.5 rounded-md border border-border px-3 py-1.5 text-sm text-foreground hover:bg-surface disabled:opacity-50`,"data-testid":`packet-request-changes`,children:[(0,y.jsx)(ee,{className:`size-4`,"aria-hidden":!0}),o(`requestChanges.label`)]}):null,Q.verbs.includes(`discard`)?(0,y.jsxs)(`button`,{type:`button`,onClick:()=>void $(`discard`),disabled:X,className:`inline-flex items-center gap-1.5 rounded-md border border-border px-3 py-1.5 text-sm text-foreground hover:bg-surface disabled:opacity-50`,"data-testid":`packet-discard`,children:[I===`discard`?(0,y.jsx)(c,{className:`size-4 animate-spin`,"aria-hidden":!0}):(0,y.jsx)(me,{className:`size-4`,"aria-hidden":!0}),o(`discard.label`)]}):null]}),b&&Q.verbs.includes(`discard`)?(0,y.jsx)(`p`,{className:`mt-3 rounded-md border border-accent-warning/40 bg-accent-warning/10 px-3 py-2 text-xs text-accent-warning`,"data-testid":`packet-discard-stacked-note`,children:o(`discard.stackedNote`)}):null,z?(0,y.jsx)(`p`,{className:`mt-3 text-xs text-accent-warning`,children:o(`error.${z}`)}):null,Oe?(0,y.jsxs)(`div`,{className:`mt-4 flex flex-col gap-2 rounded-md border border-border/70 bg-background-deep/40 p-3`,children:[(0,y.jsx)(`label`,{htmlFor:`packet-revision-note`,className:`text-xs font-medium text-foreground`,children:o(`requestChanges.prompt`)}),(0,y.jsx)(`textarea`,{id:`packet-revision-note`,value:V,onChange:e=>H(e.target.value),rows:2,placeholder:o(`requestChanges.placeholder`),className:`resize-y rounded-md border border-border bg-surface px-2 py-1.5 text-sm text-foreground placeholder:text-muted-foreground`,"data-testid":`packet-revision-input`}),(0,y.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,y.jsxs)(`button`,{type:`button`,onClick:()=>void ke(),disabled:X||V.trim().length===0,className:`inline-flex items-center gap-1.5 rounded-md bg-accent-primary px-3 py-1.5 text-sm font-medium text-white disabled:opacity-50`,"data-testid":`packet-revision-submit`,children:[U?(0,y.jsx)(c,{className:`size-4 animate-spin`,"aria-hidden":!0}):(0,y.jsx)(ae,{className:`size-4`,"aria-hidden":!0}),o(`requestChanges.submit`)]}),(0,y.jsx)(`span`,{className:`text-[11px] text-muted-foreground`,children:o(`requestChanges.hint`)})]}),De?(0,y.jsx)(`p`,{className:`text-xs text-accent-warning`,children:o(`error.${De}`)}):null]}):null]}),Y.driftNudges.length>0?(0,y.jsxs)(`div`,{className:`rounded-lg border border-accent-highlight/30 bg-accent-highlight/5 p-4`,"data-testid":`packet-drift-nudges`,children:[(0,y.jsx)(`h2`,{className:`mb-1 text-sm font-medium text-accent-highlight`,children:o(`drift.title`)}),(0,y.jsx)(`ul`,{className:`space-y-1 text-xs text-foreground`,children:Y.driftNudges.map(e=>(0,y.jsx)(`li`,{children:o(e.code,{...e.values,defaultValue:e.code})},e.code))}),(0,y.jsx)(`p`,{className:`mt-2 text-[11px] text-muted-foreground`,children:o(`drift.advisory`)})]}):null,Y.versions.length>1?(0,y.jsxs)(C,{title:o(`versions.title`,{count:Y.versions.length}),badge:(0,y.jsx)(pe,{className:`size-3.5 text-muted-foreground`,"aria-hidden":!0}),children:[(0,y.jsx)(`ol`,{className:`space-y-2`,"data-testid":`packet-versions`,children:Y.versions.map(e=>(0,y.jsxs)(`li`,{className:`flex flex-col gap-0.5 text-sm`,children:[(0,y.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,y.jsx)(`span`,{className:e.current?`font-medium text-foreground`:`text-muted-foreground`,children:o(`versions.label`,{version:e.version})}),e.current?(0,y.jsx)(`span`,{className:`rounded-full border border-accent-primary/40 bg-accent-primary/10 px-1.5 text-[10px] text-accent-primary`,children:o(`versions.current`)}):null,(0,y.jsx)(`span`,{className:`text-[11px] text-muted-foreground`,children:e.costUsd===null?`—`:`${e.costEstimated?`~`:``}$${e.costUsd.toFixed(2)}`})]}),(0,y.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:e.revisionNote??o(`versions.originalBuild`)})]},e.prDeliveryId))}),(0,y.jsx)(`p`,{className:`mt-3 text-xs text-muted-foreground`,children:o(`cost.allVersions`,{amount:Y.chainCostUsd===null?`—`:`${Y.chainCostEstimated?`~`:``}$${Y.chainCostUsd.toFixed(2)}`})})]}):null,Y.watchOut.length>0?(0,y.jsxs)(`div`,{className:`rounded-lg border border-accent-warning/30 bg-accent-warning/5 p-4`,children:[(0,y.jsxs)(`h2`,{className:`mb-2 flex items-center gap-1.5 text-sm font-medium text-accent-warning`,children:[(0,y.jsx)(u,{className:`size-4`,"aria-hidden":!0}),o(`watchOut.title`)]}),(0,y.jsx)(`ul`,{className:`space-y-1`,children:Y.watchOut.map((e,t)=>(0,y.jsx)(S,{item:e},`${e.code}-${t}`))})]}):null,(0,y.jsx)(C,{title:o(`sections.whatYouAsked`),defaultOpen:!0,children:(0,y.jsx)(`ul`,{className:`space-y-3`,children:Y.sections.map(e=>(0,y.jsxs)(`li`,{className:`text-sm`,children:[(0,y.jsxs)(`button`,{type:`button`,onClick:()=>Te(e.ticketId),className:`text-accent-primary hover:underline`,children:[`#`,e.ticketId,` `,e.title??``]}),e.problem?(0,y.jsx)(_e,{muted:!0,className:`mt-1`,children:e.problem}):null]},e.ticketId))})}),(0,y.jsx)(C,{title:o(`sections.whatIDid`),children:(0,y.jsx)(`ul`,{className:`space-y-3`,children:Y.sections.map(e=>(0,y.jsxs)(`li`,{className:`text-sm`,"data-testid":`packet-done-${e.ticketId}`,children:[(0,y.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,y.jsxs)(`span`,{className:`font-medium text-foreground`,children:[`#`,e.ticketId]}),e.title?(0,y.jsx)(`span`,{className:`text-foreground/80`,children:e.title}):null,(()=>{let t=Ce(e);return(0,y.jsx)(`span`,{className:`rounded-full border px-2 py-0.5 text-[10px] font-medium ${we[t]}`,"data-testid":`packet-outcome-pill`,children:o(`outcome.${t}`)})})()]}),e.churn?(0,y.jsxs)(`p`,{className:`mt-1 text-xs text-muted-foreground`,children:[o(`churn.line`,{files:e.churn.filesTouched,added:e.churn.addedLines,removed:e.churn.removedLines}),` · `,e.churn.testFilesTouched.length>0?o(`churn.testFiles`,{count:e.churn.testFilesTouched.length}):o(`churn.noTestFiles`)]}):(0,y.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground`,children:o(`churn.batchNotSplittable`)}),e.solution?(0,y.jsxs)(`details`,{className:`group mt-2 rounded-md border border-border/50 bg-background-deep/30 px-3 py-2`,children:[(0,y.jsx)(`summary`,{className:`cursor-pointer select-none text-xs font-medium text-muted-foreground group-open:text-foreground/80`,children:o(`planned.title`)}),(0,y.jsx)(`p`,{className:`mt-1 text-[11px] italic text-muted-foreground/80`,children:o(`planned.caveat`)}),(0,y.jsx)(_e,{className:`mt-2`,children:e.solutionOverflow??e.solution})]}):(0,y.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground`,children:o(`noSolutionRecorded`)})]},e.ticketId))})}),(0,y.jsx)(C,{title:o(`sections.howItWasChecked`),badge:Y.evidenceUnavailable?(0,y.jsx)(`span`,{className:`rounded-full border border-border bg-background-deep/50 px-2 py-0.5 text-[10px] text-muted-foreground`,children:o(`proof.evidenceUnavailable`)}):void 0,children:(0,y.jsx)(`div`,{className:`space-y-4`,children:Ae.map(({tier:e,items:t})=>{let n=xe[e];return(0,y.jsxs)(`div`,{className:`rounded-md border px-3 py-2 ${Se[e]}`,children:[(0,y.jsxs)(`h3`,{className:`mb-1 flex items-center gap-1.5 text-xs font-medium`,children:[(0,y.jsx)(n,{className:`size-3.5`,"aria-hidden":!0}),o(`tier.${e}.title`)]}),(0,y.jsx)(`p`,{className:`mb-2 text-[11px] opacity-80`,children:o(`tier.${e}.caveat`)}),(0,y.jsx)(`ul`,{className:`space-y-1`,children:t.map((e,t)=>(0,y.jsx)(S,{item:e},`${e.code}-${t}`))})]},e)})})})]})}export{w as default};
|