atris 3.74.26 → 3.74.27
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/commands/task.js +16 -0
- package/commands/worktree.js +16 -1
- package/lib/fleet.js +28 -1
- package/lib/gm-season.js +1 -1
- package/lib/task-db.js +25 -1
- package/package.json +1 -1
package/commands/task.js
CHANGED
|
@@ -575,6 +575,20 @@ function landingFlags(args) {
|
|
|
575
575
|
};
|
|
576
576
|
}
|
|
577
577
|
|
|
578
|
+
// The pull request and commit a flight merged on its own, so the job record
|
|
579
|
+
// names what landed. Only a merge commit makes it count.
|
|
580
|
+
function readyMergeFlags(args) {
|
|
581
|
+
const commit = textFlag(args, ['--merge-commit']);
|
|
582
|
+
if (!commit) return null;
|
|
583
|
+
return {
|
|
584
|
+
merge_commit: commit,
|
|
585
|
+
number: textFlag(args, ['--pr-number']),
|
|
586
|
+
url: textFlag(args, ['--pr-url']),
|
|
587
|
+
merged_at: textFlag(args, ['--merged-at']),
|
|
588
|
+
self_landed: hasFlag(args, '--self-landed'),
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
|
|
578
592
|
function normalizedLandingSentence(value) {
|
|
579
593
|
return String(value || '').replace(/\s+/g, ' ').trim();
|
|
580
594
|
}
|
|
@@ -9650,6 +9664,7 @@ function cmdReady(args) {
|
|
|
9650
9664
|
const lesson = flag(args, '--lesson') || '';
|
|
9651
9665
|
const nextTaskInput = normalizeReviewNextTaskInput(typeof flag(args, '--next') === 'string' ? flag(args, '--next') : '');
|
|
9652
9666
|
const landing = landingFlags(args);
|
|
9667
|
+
const merge = readyMergeFlags(args);
|
|
9653
9668
|
guardExplicitActor('atris task ready', flag(args, '--as'));
|
|
9654
9669
|
const actor = String(flag(args, '--as') || DEFAULT_OWNER);
|
|
9655
9670
|
const resultFields = {
|
|
@@ -9697,6 +9712,7 @@ function cmdReady(args) {
|
|
|
9697
9712
|
nextTask: nextTaskInput.nextTask,
|
|
9698
9713
|
resultTrace: resultTrace && resultTrace.trace,
|
|
9699
9714
|
landing,
|
|
9715
|
+
merge,
|
|
9700
9716
|
result: resultSentence,
|
|
9701
9717
|
});
|
|
9702
9718
|
if (!result.ready) {
|
package/commands/worktree.js
CHANGED
|
@@ -1125,7 +1125,7 @@ function shipWorktree(args) {
|
|
|
1125
1125
|
}
|
|
1126
1126
|
// A merge queue accepts the request before merging. Deleting its head
|
|
1127
1127
|
// here closes the PR and cancels that request, so confirm the outcome.
|
|
1128
|
-
const confirmation = spawnSync('gh', ['pr', 'view', mergeRef, '--json', 'state,mergedAt'], { cwd: root, encoding: 'utf8' });
|
|
1128
|
+
const confirmation = spawnSync('gh', ['pr', 'view', mergeRef, '--json', 'state,mergedAt,number,url,mergeCommit'], { cwd: root, encoding: 'utf8' });
|
|
1129
1129
|
if (confirmation.status !== 0) {
|
|
1130
1130
|
throw new Error('could not confirm the merge; the source branch was kept');
|
|
1131
1131
|
}
|
|
@@ -1141,6 +1141,10 @@ function shipWorktree(args) {
|
|
|
1141
1141
|
throw new Error('the change was not merged; the source branch was kept');
|
|
1142
1142
|
}
|
|
1143
1143
|
console.log('merge: merged');
|
|
1144
|
+
// One machine-readable line, so a caller can save which pull request
|
|
1145
|
+
// and commit landed. The rating only counts a landing it can point at.
|
|
1146
|
+
const record = shipMergeRecord(state);
|
|
1147
|
+
if (record) console.log(`merge: record ${JSON.stringify(record)}`);
|
|
1144
1148
|
const deleted = runGit(['push', 'origin', '--delete', branch], { cwd: root, check: false });
|
|
1145
1149
|
if (deleted.status === 0) {
|
|
1146
1150
|
console.log(`merge: remote branch deleted ${branch}`);
|
|
@@ -1165,6 +1169,17 @@ function shipWorktree(args) {
|
|
|
1165
1169
|
return 0;
|
|
1166
1170
|
}
|
|
1167
1171
|
|
|
1172
|
+
// The landed pull request from `gh pr view --json`, or null without a merge commit.
|
|
1173
|
+
function shipMergeRecord(state) {
|
|
1174
|
+
const commit = state && state.mergeCommit && typeof state.mergeCommit === 'object' ? state.mergeCommit.oid : null;
|
|
1175
|
+
if (typeof commit !== 'string' || !/^[0-9a-f]{7,64}$/i.test(commit)) return null;
|
|
1176
|
+
const record = { merge_commit: commit };
|
|
1177
|
+
if (Number.isInteger(state.number) && state.number > 0) record.number = state.number;
|
|
1178
|
+
if (typeof state.url === 'string' && state.url) record.url = state.url;
|
|
1179
|
+
if (typeof state.mergedAt === 'string' && state.mergedAt) record.merged_at = state.mergedAt;
|
|
1180
|
+
return record;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1168
1183
|
function guard(args) {
|
|
1169
1184
|
const root = repoRoot();
|
|
1170
1185
|
const worktrees = listWorktrees(root);
|
package/lib/fleet.js
CHANGED
|
@@ -1483,6 +1483,28 @@ function shipFailureDetail(shipped, { head = 400, tail = 500 } = {}) {
|
|
|
1483
1483
|
return `${cause}${headTail(combined.trim(), head, tail)}`;
|
|
1484
1484
|
}
|
|
1485
1485
|
|
|
1486
|
+
// The `merge: record {...}` line worktree ship prints after a confirmed merge.
|
|
1487
|
+
function shipMergeRecord(stdout) {
|
|
1488
|
+
const line = String(stdout || '').match(/^merge: record (\{.*\})\s*$/m);
|
|
1489
|
+
if (!line) return null;
|
|
1490
|
+
try {
|
|
1491
|
+
const record = JSON.parse(line[1]);
|
|
1492
|
+
return record && typeof record === 'object' && typeof record.merge_commit === 'string' ? record : null;
|
|
1493
|
+
} catch {
|
|
1494
|
+
return null;
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
// task ready flags that name the pull request a flight merged by itself.
|
|
1499
|
+
function landedMergeFlags(merge) {
|
|
1500
|
+
if (!merge || !merge.merge_commit) return [];
|
|
1501
|
+
const flags = ['--merge-commit', merge.merge_commit, '--self-landed'];
|
|
1502
|
+
if (merge.number) flags.push('--pr-number', String(merge.number));
|
|
1503
|
+
if (merge.url) flags.push('--pr-url', merge.url);
|
|
1504
|
+
if (merge.merged_at) flags.push('--merged-at', merge.merged_at);
|
|
1505
|
+
return flags;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1486
1508
|
function fleetShipArgs(entry, check, targetRef = resolveDispatchLandTarget(entry.worktreePath || process.cwd())) {
|
|
1487
1509
|
return [
|
|
1488
1510
|
'worktree', 'ship',
|
|
@@ -1629,6 +1651,8 @@ module.exports = {
|
|
|
1629
1651
|
runInReapedProcessGroup,
|
|
1630
1652
|
shipWithRetry,
|
|
1631
1653
|
shipFailureDetail,
|
|
1654
|
+
shipMergeRecord,
|
|
1655
|
+
landedMergeFlags,
|
|
1632
1656
|
get FLEET_CAPABLE() { return FLEET_CAPABLE; },
|
|
1633
1657
|
get DISPATCH_CAPABLE() { return DISPATCH_CAPABLE; },
|
|
1634
1658
|
get runFleetFlight() { return runFleetFlight; },
|
|
@@ -3272,7 +3296,7 @@ async function runFleetFlight({
|
|
|
3272
3296
|
if (shipped.status !== 0 || !/done: worktree shipped/.test(shipped.stdout)) {
|
|
3273
3297
|
return { ok: false, stage: 'ship', detail: shipFailureDetail(shipped) };
|
|
3274
3298
|
}
|
|
3275
|
-
return { ok: true, stage: 'shipped' };
|
|
3299
|
+
return { ok: true, stage: 'shipped', merge: shipMergeRecord(shipped.stdout) };
|
|
3276
3300
|
});
|
|
3277
3301
|
|
|
3278
3302
|
for (const { entry, result } of results) {
|
|
@@ -3309,6 +3333,7 @@ async function runFleetFlight({
|
|
|
3309
3333
|
'task', 'ready', String(entry.task.display_id),
|
|
3310
3334
|
'--proof', `Built by ${activeEngine} engine in fleet flight.${restaffProof} Landed via worktree ship gate (rebase-before-ship, verify re-run). Receipt saved at ${path.relative(root, receiptPath)}. Report tail: ${headTail(String(result.report || '').replace(/\n/g, ' '))}`,
|
|
3311
3335
|
'--result', 'Operators can now review fleet-shipped work faster because the worktree was verified before landing.',
|
|
3336
|
+
...landedMergeFlags(landed.merge),
|
|
3312
3337
|
'--as', `fleet-${activeEngine}`,
|
|
3313
3338
|
], { flight, landedRow, worktree: entry.worktreePath, save: () => atomicWriteFlightReceipt(flight, receiptPath) });
|
|
3314
3339
|
if (!reviewRecorded) {
|
|
@@ -3795,6 +3820,7 @@ async function runDispatchFlight({
|
|
|
3795
3820
|
return {
|
|
3796
3821
|
ok: true,
|
|
3797
3822
|
stage: 'shipped',
|
|
3823
|
+
merge: shipMergeRecord(shipped.stdout),
|
|
3798
3824
|
check,
|
|
3799
3825
|
verifyOutput: `${verified.stdout}${verified.stderr}`,
|
|
3800
3826
|
verifier_result: verifierResult,
|
|
@@ -4195,6 +4221,7 @@ async function runDispatchFlight({
|
|
|
4195
4221
|
'--result', 'Operators can now review engine-built work faster because dispatch reran the verifier before landing.',
|
|
4196
4222
|
'--checked', `${landed.check} passed before landing`,
|
|
4197
4223
|
'--tested', 'The requested behavior passed its declared verifier.',
|
|
4224
|
+
...landedMergeFlags(landed.merge),
|
|
4198
4225
|
'--as', readyActor,
|
|
4199
4226
|
], { flight, landedRow, worktree: entry.worktreePath, save: () => writeDispatchReceipt(flight, receiptPath, { ids, reviewOnly: proofOnly, enforceRemoteBoundary }) });
|
|
4200
4227
|
if (!reviewRecorded) {
|
package/lib/gm-season.js
CHANGED
|
@@ -301,7 +301,7 @@ function parseJson(text) {
|
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
function landedBy(row, payload) {
|
|
304
|
-
if (payload && payload.auto_accepted === true) return 'autoland';
|
|
304
|
+
if (payload && (payload.auto_accepted === true || payload.self_landed === true)) return 'autoland';
|
|
305
305
|
return /auto/i.test(String(row.actor || '')) ? 'autoland' : 'you';
|
|
306
306
|
}
|
|
307
307
|
|
package/lib/task-db.js
CHANGED
|
@@ -1044,7 +1044,23 @@ function recordReviewPassActor(metadata, claimedBy, rawActor) {
|
|
|
1044
1044
|
return { builder: builder || null, independent };
|
|
1045
1045
|
}
|
|
1046
1046
|
|
|
1047
|
-
|
|
1047
|
+
// A merge the caller confirmed. The commit id is required; the other fields
|
|
1048
|
+
// are kept only when they look right.
|
|
1049
|
+
function cleanMergeRecord(merge) {
|
|
1050
|
+
if (!merge || typeof merge !== 'object') return null;
|
|
1051
|
+
const commit = String(merge.merge_commit || '').trim();
|
|
1052
|
+
if (!/^[0-9a-f]{7,64}$/i.test(commit)) return null;
|
|
1053
|
+
const record = { merge_commit: commit.toLowerCase() };
|
|
1054
|
+
const number = Number(merge.number);
|
|
1055
|
+
if (Number.isInteger(number) && number > 0) record.number = number;
|
|
1056
|
+
const url = String(merge.url || '').trim();
|
|
1057
|
+
if (/^https?:\/\//i.test(url)) record.url = url;
|
|
1058
|
+
const mergedAt = String(merge.merged_at || '').trim();
|
|
1059
|
+
if (mergedAt && Number.isFinite(Date.parse(mergedAt))) record.merged_at = mergedAt;
|
|
1060
|
+
return record;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
function readyTask(db, { id, actor, proof, lesson, nextTask, landing = {}, merge = null, resultTrace, result: resultSentence, reason, workRoot }) {
|
|
1048
1064
|
if (!id) throw new Error('id required');
|
|
1049
1065
|
const text = String(proof || '').trim();
|
|
1050
1066
|
if (!text) throw new Error('proof required');
|
|
@@ -1073,6 +1089,8 @@ function readyTask(db, { id, actor, proof, lesson, nextTask, landing = {}, resul
|
|
|
1073
1089
|
const cleaned = cleanLandingText(landingInput[key]);
|
|
1074
1090
|
if (cleaned) metadata[`landing_${key}`] = cleaned;
|
|
1075
1091
|
}
|
|
1092
|
+
const mergeRecord = cleanMergeRecord(merge);
|
|
1093
|
+
if (mergeRecord) metadata.merge_commit = mergeRecord.merge_commit;
|
|
1076
1094
|
// Only the builder's own ready names the work's commit. A reviewer or the
|
|
1077
1095
|
// autoland verifier re-runs the check from its own checkout; stamping that
|
|
1078
1096
|
// checkout's HEAD would name a commit the builder never made. No actor, or
|
|
@@ -1121,6 +1139,12 @@ function readyTask(db, { id, actor, proof, lesson, nextTask, landing = {}, resul
|
|
|
1121
1139
|
tested: metadata.landing_tested || null,
|
|
1122
1140
|
decision: metadata.landing_decision || null,
|
|
1123
1141
|
};
|
|
1142
|
+
if (mergeRecord) {
|
|
1143
|
+
payload.landing.merge_commit = mergeRecord.merge_commit;
|
|
1144
|
+
payload.pull_request = { state: 'merged', ...mergeRecord };
|
|
1145
|
+
// Landed by the flight with no person in the loop.
|
|
1146
|
+
if (merge.self_landed === true) payload.self_landed = true;
|
|
1147
|
+
}
|
|
1124
1148
|
const event = appendTaskEvent(db, {
|
|
1125
1149
|
taskId: id,
|
|
1126
1150
|
workspaceRoot: updated.workspace_root,
|
package/package.json
CHANGED