atris 3.74.27 → 3.74.28
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/rating.js +7 -2
- package/commands/task.js +105 -15
- package/commands/worktree.js +510 -18
- package/lib/auto-accept-certified.js +56 -0
- package/lib/campaign-keep.js +5 -1
- package/lib/fleet.js +329 -48
- package/lib/gm-season.js +44 -8
- package/lib/release-kind.js +27 -0
- package/lib/review-integrity.js +7 -0
- package/lib/roster-runs.js +11 -5
- package/lib/roster-suggest.js +3 -2
- package/lib/roster-swap.js +3 -1
- package/lib/router-brain.js +7 -6
- package/lib/task-db.js +88 -2
- package/lib/voice-gate.js +1 -0
- package/lib/worktree-space.js +357 -0
- package/package.json +1 -1
|
@@ -318,6 +318,56 @@ function unmergedPullRequestBoundaryResult(ref, proof) {
|
|
|
318
318
|
};
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
+
// The pull request the task names, as task ready recorded it: the row keeps the
|
|
322
|
+
// newest word on it, and a row written before that falls back to the newest proof
|
|
323
|
+
// event that named one. Only this attempt's events count: reopening a job clears
|
|
324
|
+
// the row's pull request and starts it over, so whatever the history said before
|
|
325
|
+
// the latest reopen is about an attempt that is over. A send-back for changes is
|
|
326
|
+
// not a reopen; its pull request is still open. Null when the task names none.
|
|
327
|
+
function recordedPullRequest(task) {
|
|
328
|
+
const metadata = task.metadata || {};
|
|
329
|
+
if (metadata.pull_request && typeof metadata.pull_request === 'object') return metadata.pull_request;
|
|
330
|
+
const events = Array.isArray(task.events) ? task.events : [];
|
|
331
|
+
let attemptStart = 0;
|
|
332
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
333
|
+
if (events[index] && events[index].event_type === 'reopened') {
|
|
334
|
+
attemptStart = index + 1;
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
for (let index = events.length - 1; index >= attemptStart; index -= 1) {
|
|
339
|
+
const event = events[index];
|
|
340
|
+
const named = event && event.event_type === 'proof_ready' && event.payload && event.payload.pull_request;
|
|
341
|
+
if (named && typeof named === 'object') return named;
|
|
342
|
+
}
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// A pull request still open, with no merge commit, is work waiting for a person:
|
|
347
|
+
// whatever the proof says, the change has not landed.
|
|
348
|
+
function openPullRequestOf(task) {
|
|
349
|
+
if (!task) return null;
|
|
350
|
+
const pullRequest = recordedPullRequest(task);
|
|
351
|
+
if (!pullRequest || pullRequest.merge_commit || pullRequest.merged_at) return null;
|
|
352
|
+
return String(pullRequest.state || '').toLowerCase() === 'open' ? pullRequest : null;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// The one refusal for a job whose pull request is still open, in any mode, whatever
|
|
356
|
+
// its proof or its stored check says. Every path that accepts without a person
|
|
357
|
+
// answers with this, so none can complete a job nobody has landed: this
|
|
358
|
+
// evaluator, the sweep, and the shared acceptor. Null when nothing is open.
|
|
359
|
+
function openPullRequestRefusal(task, ref) {
|
|
360
|
+
const openPullRequest = openPullRequestOf(task);
|
|
361
|
+
if (!openPullRequest) return null;
|
|
362
|
+
return {
|
|
363
|
+
eligible: false,
|
|
364
|
+
ref,
|
|
365
|
+
reason: 'pull_request_open',
|
|
366
|
+
pull_request: openPullRequest,
|
|
367
|
+
next_action: 'a person lands the pull request, then accepts the job with `atris task accept <ref> --as <human>`',
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
321
371
|
function distinctReviewActors(task) {
|
|
322
372
|
return reviewIntegrity.reviewEventActors(task);
|
|
323
373
|
}
|
|
@@ -1219,6 +1269,11 @@ function evaluateAutoAccept(task, options = {}) {
|
|
|
1219
1269
|
};
|
|
1220
1270
|
}
|
|
1221
1271
|
|
|
1272
|
+
// A job whose pull request is still open has not landed, in any mode, whatever
|
|
1273
|
+
// its proof says. A person lands the pull request and then accepts the job.
|
|
1274
|
+
const pullRequestOpen = openPullRequestRefusal(task, ref);
|
|
1275
|
+
if (pullRequestOpen) return pullRequestOpen;
|
|
1276
|
+
|
|
1222
1277
|
// Load lazily: the human accept gate reuses this module's parser and runner.
|
|
1223
1278
|
const verifyCommand = resolveTaskVerify(task).verify;
|
|
1224
1279
|
if (verifyCommand && require('./accept-verify-gate').nonFalsifyingIssue(verifyCommand)) {
|
|
@@ -1418,6 +1473,7 @@ module.exports = {
|
|
|
1418
1473
|
verifyRunnability,
|
|
1419
1474
|
evaluateAutoAccept,
|
|
1420
1475
|
isAutoCertifyVerifyCommandAllowed,
|
|
1476
|
+
openPullRequestRefusal,
|
|
1421
1477
|
parseVerifyChain,
|
|
1422
1478
|
isAgentCertified,
|
|
1423
1479
|
parseVerifyCommand,
|
package/lib/campaign-keep.js
CHANGED
|
@@ -29,9 +29,13 @@ const CAMPAIGN_WAKE_JOB = Object.freeze({
|
|
|
29
29
|
marker: MARKER,
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
+
// The minute field only counts within one hour: */180 would fire hourly.
|
|
32
33
|
function cronSchedule(seconds) {
|
|
33
34
|
const minutes = Math.max(1, Math.round(Number(seconds || 60) / 60));
|
|
34
|
-
|
|
35
|
+
if (minutes === 1) return '* * * * *';
|
|
36
|
+
if (minutes < 60) return `*/${minutes} * * * *`;
|
|
37
|
+
const hours = Math.round(minutes / 60);
|
|
38
|
+
return hours >= 24 ? '0 0 * * *' : `0 */${hours} * * *`;
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
// One timer per checkout: the label and marker carry a short hash of its root.
|