@ai-dossier/cli 0.55.0 → 0.57.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/README.md +147 -5
- package/dist/batch-compose.d.ts +172 -0
- package/dist/batch-compose.d.ts.map +1 -0
- package/dist/batch-compose.js +475 -0
- package/dist/batch-compose.js.map +1 -0
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/batch.d.ts +58 -0
- package/dist/commands/batch.d.ts.map +1 -0
- package/dist/commands/batch.js +395 -0
- package/dist/commands/batch.js.map +1 -0
- package/dist/commands/sched.d.ts.map +1 -1
- package/dist/commands/sched.js +60 -3
- package/dist/commands/sched.js.map +1 -1
- package/dist/gh.d.ts +3 -1
- package/dist/gh.d.ts.map +1 -1
- package/dist/gh.js +4 -1
- package/dist/gh.js.map +1 -1
- package/dist/runstate.d.ts +14 -3
- package/dist/runstate.d.ts.map +1 -1
- package/dist/runstate.js +20 -6
- package/dist/runstate.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `ai-dossier batch compose` (#773, #770 P3) — preview which issues may share a batch PR, with
|
|
4
|
+
* zero model tokens. Runs prescreen:v2 + the deterministic readiness screen over the operator's
|
|
5
|
+
* picks and/or the backlog and proposes a composition honouring the scheduler's batch invariants
|
|
6
|
+
* (≤ `max_full_review_members` review=full members, one base branch, 3–6 members), listing ranked
|
|
7
|
+
* backfill candidates when the picks fall short.
|
|
8
|
+
*
|
|
9
|
+
* I/O only: `gh` (issue reads), and a READ-ONLY look at the local sched queue/config. Never a
|
|
10
|
+
* model call, never a write (no labels, comments, or queue changes) — composing is a preview;
|
|
11
|
+
* batch-issues-preparation (or the operator) acts on it. Exits 0 once arguments validate; the
|
|
12
|
+
* `status` field is the payload, not a pass/fail gate (same contract as `classify prescreen`).
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.registerBatchCommand = registerBatchCommand;
|
|
16
|
+
const sched_1 = require("@ai-dossier/sched");
|
|
17
|
+
const batch_compose_1 = require("../batch-compose");
|
|
18
|
+
const gh_1 = require("../gh");
|
|
19
|
+
const issue_selection_1 = require("../issue-selection");
|
|
20
|
+
const plan_artifact_1 = require("../plan-artifact");
|
|
21
|
+
const prescreen_1 = require("../prescreen");
|
|
22
|
+
const runstate_1 = require("../runstate");
|
|
23
|
+
/** Default backlog page — one `gh issue list` call, bodies and comments included. */
|
|
24
|
+
const DEFAULT_BACKLOG_LIMIT = 100;
|
|
25
|
+
/** Hard ceiling on the backlog page (each issue's comments ride along in the one call). */
|
|
26
|
+
const MAX_BACKLOG_LIMIT = 500;
|
|
27
|
+
/** stdout ceiling for the backlog page — bodies and comments of up to MAX_BACKLOG_LIMIT issues. */
|
|
28
|
+
const BACKLOG_MAX_BUFFER = 256 * 1024 * 1024;
|
|
29
|
+
/** Fields every issue read requests — `comments` carries plan:v1 artifacts and runstate milestones. */
|
|
30
|
+
const ISSUE_FIELDS = 'number,title,body,labels,assignees,state,comments';
|
|
31
|
+
function names(value, key) {
|
|
32
|
+
if (!Array.isArray(value))
|
|
33
|
+
return [];
|
|
34
|
+
return value
|
|
35
|
+
.map((v) => (v && typeof v === 'object' ? v[key] : undefined))
|
|
36
|
+
.filter((v) => typeof v === 'string');
|
|
37
|
+
}
|
|
38
|
+
function commentBodies(value) {
|
|
39
|
+
if (!Array.isArray(value))
|
|
40
|
+
return [];
|
|
41
|
+
return value.map((c) => c && typeof c === 'object' && typeof c.body === 'string'
|
|
42
|
+
? c.body
|
|
43
|
+
: '');
|
|
44
|
+
}
|
|
45
|
+
/** A `gh` issue object → the core's input (dependencies and sched status filled in later). */
|
|
46
|
+
function toInput(raw, source) {
|
|
47
|
+
const bodies = commentBodies(raw.comments);
|
|
48
|
+
const plan = (0, plan_artifact_1.findLatestPlan)(bodies);
|
|
49
|
+
const milestones = (0, runstate_1.parseMilestones)(bodies);
|
|
50
|
+
return {
|
|
51
|
+
issue: Number(raw.number),
|
|
52
|
+
source,
|
|
53
|
+
title: (0, gh_1.asString)(raw.title),
|
|
54
|
+
body: (0, gh_1.asString)(raw.body),
|
|
55
|
+
labels: names(raw.labels, 'name'),
|
|
56
|
+
state: (0, gh_1.asString)(raw.state),
|
|
57
|
+
assignees: names(raw.assignees, 'login'),
|
|
58
|
+
predictedFiles: plan?.artifact.predictedFiles,
|
|
59
|
+
latestPhase: milestones.length > 0 ? milestones[milestones.length - 1].phase : null,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function fetchPick(issue, repo) {
|
|
63
|
+
const res = (0, gh_1.exec)('gh', [
|
|
64
|
+
'issue',
|
|
65
|
+
'view',
|
|
66
|
+
String(issue),
|
|
67
|
+
'--json',
|
|
68
|
+
ISSUE_FIELDS,
|
|
69
|
+
...(0, gh_1.repoArgs)(repo),
|
|
70
|
+
]);
|
|
71
|
+
const unreadable = (error) => ({
|
|
72
|
+
issue,
|
|
73
|
+
source: 'pick',
|
|
74
|
+
error,
|
|
75
|
+
title: '',
|
|
76
|
+
body: '',
|
|
77
|
+
labels: [],
|
|
78
|
+
state: '',
|
|
79
|
+
assignees: [],
|
|
80
|
+
});
|
|
81
|
+
if (!res.ok)
|
|
82
|
+
return unreadable((0, gh_1.ghFailure)(`Could not read issue #${issue}`, res.error, repo));
|
|
83
|
+
const parsed = (0, gh_1.parseGhJson)(res.stdout);
|
|
84
|
+
if (parsed === null)
|
|
85
|
+
return unreadable(`Could not read issue #${issue}: gh did not print JSON.`);
|
|
86
|
+
return toInput({ ...parsed, number: issue }, 'pick');
|
|
87
|
+
}
|
|
88
|
+
function fetchBacklog(opts, repo, warnings) {
|
|
89
|
+
const args = ['issue', 'list', '--state', 'open', '--limit', String(opts.limit)];
|
|
90
|
+
for (const label of opts.labels)
|
|
91
|
+
args.push(`--label=${label}`);
|
|
92
|
+
if (opts.search !== undefined)
|
|
93
|
+
args.push(`--search=${opts.search}`);
|
|
94
|
+
args.push('--json', ISSUE_FIELDS, ...(0, gh_1.repoArgs)(repo));
|
|
95
|
+
const res = (0, gh_1.exec)('gh', args, { maxBuffer: BACKLOG_MAX_BUFFER });
|
|
96
|
+
if (!res.ok) {
|
|
97
|
+
warnings.push((0, gh_1.ghFailure)('Could not list the backlog — no backfill proposed', res.error, repo));
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
const parsed = (0, gh_1.parseGhJson)(res.stdout);
|
|
101
|
+
if (!Array.isArray(parsed)) {
|
|
102
|
+
warnings.push('Could not list the backlog: gh did not print a JSON array — no backfill proposed.');
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
return parsed
|
|
106
|
+
.filter((r) => Number.isSafeInteger(Number(r.number)) && Number(r.number) > 0)
|
|
107
|
+
.map((r) => toInput(r, 'backlog'));
|
|
108
|
+
}
|
|
109
|
+
/** The sched project slug: explicit `--project`, else `--repo` as `owner-name`, else the cwd's repo. */
|
|
110
|
+
function resolveProject(opts) {
|
|
111
|
+
if (opts.project)
|
|
112
|
+
return opts.project;
|
|
113
|
+
if (opts.repo)
|
|
114
|
+
return (0, sched_1.sanitizeSlug)(opts.repo.replace('/', '-'));
|
|
115
|
+
return (0, sched_1.resolveProjectSlug)(sched_1.defaultExec);
|
|
116
|
+
}
|
|
117
|
+
/** Read-only sched queue + config. A missing state is an empty queue; an unreadable one is a warning. */
|
|
118
|
+
function readSched(project, warnings) {
|
|
119
|
+
const store = new sched_1.SchedStore((0, sched_1.schedStateDir)(project));
|
|
120
|
+
let state = null;
|
|
121
|
+
let config = null;
|
|
122
|
+
try {
|
|
123
|
+
state = store.load();
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
warnings.push(`Could not read the sched queue for '${project}' — the sched-active check was skipped: ${err.message}`);
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
config = store.loadConfig();
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
warnings.push(`Could not read the sched config for '${project}' — using the default review=full cap: ${err.message}`);
|
|
133
|
+
}
|
|
134
|
+
return { state, config };
|
|
135
|
+
}
|
|
136
|
+
/** Status of the issue's live queue entry (not terminal, not already merged), or null. */
|
|
137
|
+
function activeSchedStatus(state, issue) {
|
|
138
|
+
const entry = state?.entries.find((e) => e.issue === issue &&
|
|
139
|
+
!sched_1.TERMINAL_ISSUE_STATUSES.has(e.status) &&
|
|
140
|
+
!sched_1.SATISFIED_ISSUE_STATUSES.has(e.status));
|
|
141
|
+
return entry ? entry.status : null;
|
|
142
|
+
}
|
|
143
|
+
function positiveInt(raw, flag, { min = 1, max = Number.MAX_SAFE_INTEGER } = {}) {
|
|
144
|
+
const n = Number(raw);
|
|
145
|
+
if (!/^\d+$/.test(raw.trim()) || !Number.isSafeInteger(n) || n < min || n > max) {
|
|
146
|
+
(0, gh_1.fail)([`${flag} must be an integer between ${min} and ${max}, got '${raw}'.`]);
|
|
147
|
+
}
|
|
148
|
+
return n;
|
|
149
|
+
}
|
|
150
|
+
/** Terminal control characters — issue titles and label names are untrusted, network-sourced text. */
|
|
151
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: matching (and stripping) control characters is exactly this regex's job
|
|
152
|
+
const TERMINAL_CONTROL_RE = /[\u0000-\u0009\u000b-\u001f\u007f-\u009f]/g;
|
|
153
|
+
function renderText(r) {
|
|
154
|
+
// Every text line goes through one strip, so an ANSI/OSC escape in an issue title can never
|
|
155
|
+
// reach the operator's terminal raw. (JSON mode is safe: JSON.stringify escapes them.)
|
|
156
|
+
const line = (s = '') => console.log(s.replace(TERMINAL_CONTROL_RE, ''));
|
|
157
|
+
line(`batch compose — ${r.repo ?? r.project} (base ${r.base_branch}, rules ${r.rules})`);
|
|
158
|
+
line(`status: ${r.status} — ${r.members.length} member(s), ${r.members.filter((m) => m.review === 'full').length}/${r.params.max_full_review} review=full, min ${r.params.min_members}, max ${r.params.max_members}`);
|
|
159
|
+
line(`→ ${r.recommendation}`);
|
|
160
|
+
line();
|
|
161
|
+
line('Members:');
|
|
162
|
+
if (r.members.length === 0)
|
|
163
|
+
line(' (none)');
|
|
164
|
+
for (const m of r.members) {
|
|
165
|
+
const pk = m.packages.length > 0 ? ` [${m.packages.join(', ')}]` : '';
|
|
166
|
+
line(` #${m.issue} review=${m.review} (${m.source})${pk} ${m.title}`);
|
|
167
|
+
for (const why of m.review_reasons)
|
|
168
|
+
line(` full because: ${why}`);
|
|
169
|
+
}
|
|
170
|
+
if (r.shared_packages.length > 0)
|
|
171
|
+
line(` shared packages: ${r.shared_packages.join(', ')}`);
|
|
172
|
+
if (r.held.length > 0) {
|
|
173
|
+
line();
|
|
174
|
+
line('Admissible but held out:');
|
|
175
|
+
for (const h of r.held)
|
|
176
|
+
line(` #${h.issue} review=${h.review} ${h.reason} ${h.title}`);
|
|
177
|
+
}
|
|
178
|
+
if (r.excluded.length > 0) {
|
|
179
|
+
line();
|
|
180
|
+
line('Excluded:');
|
|
181
|
+
for (const e of r.excluded) {
|
|
182
|
+
line(` #${e.issue} ${e.reasons.map((x) => x.code).join(', ')} ${e.title}`);
|
|
183
|
+
for (const x of e.reasons)
|
|
184
|
+
line(` ${x.message}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (r.backfill.length > 0) {
|
|
188
|
+
line();
|
|
189
|
+
line('Backfill candidates (ranked):');
|
|
190
|
+
for (const b of r.backfill.slice(0, 10)) {
|
|
191
|
+
const sh = b.shared_packages.length > 0 ? ` shares ${b.shared_packages.join(', ')}` : '';
|
|
192
|
+
line(` ${b.rank}. #${b.issue} review=${b.review}${b.selected ? ' ← selected' : ''}${sh} ${b.title}`);
|
|
193
|
+
}
|
|
194
|
+
if (r.backfill.length > 10)
|
|
195
|
+
line(` … ${r.backfill.length - 10} more (see --json)`);
|
|
196
|
+
}
|
|
197
|
+
for (const w of r.warnings)
|
|
198
|
+
console.error(`⚠ ${w.replace(TERMINAL_CONTROL_RE, '')}`);
|
|
199
|
+
}
|
|
200
|
+
function runCompose(opts) {
|
|
201
|
+
if (opts.repo)
|
|
202
|
+
(0, gh_1.requireRepoSlug)(opts.repo);
|
|
203
|
+
if (!sched_1.SAFE_REF_RE.test(opts.base))
|
|
204
|
+
(0, gh_1.fail)([`--base must be a valid git ref name, got '${opts.base}'.`]);
|
|
205
|
+
if (opts.rules !== 'v2' && opts.rules !== 'legacy') {
|
|
206
|
+
(0, gh_1.fail)([`--rules must be 'v2' or 'legacy', got '${opts.rules}'.`]);
|
|
207
|
+
}
|
|
208
|
+
const rules = opts.rules;
|
|
209
|
+
if (!opts.issues && !opts.backlog) {
|
|
210
|
+
(0, gh_1.fail)([
|
|
211
|
+
'Nothing to compose.',
|
|
212
|
+
'Fix: pass --issues <selection> (e.g. 4,5,9..12) and/or --backlog.',
|
|
213
|
+
]);
|
|
214
|
+
}
|
|
215
|
+
let picks = [];
|
|
216
|
+
if (opts.issues) {
|
|
217
|
+
try {
|
|
218
|
+
picks = (0, issue_selection_1.parseIssueSelection)(opts.issues);
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
(0, gh_1.fail)([`--issues: ${err.message}`]);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const limit = positiveInt(opts.limit, '--limit', { max: MAX_BACKLOG_LIMIT });
|
|
225
|
+
const minMembers = positiveInt(opts.minMembers, '--min-members', { max: batch_compose_1.DEFAULT_MAX_MEMBERS });
|
|
226
|
+
const maxMembers = positiveInt(opts.maxMembers, '--max-members', { max: batch_compose_1.DEFAULT_MAX_MEMBERS });
|
|
227
|
+
if (minMembers > maxMembers)
|
|
228
|
+
(0, gh_1.fail)(['--min-members may not exceed --max-members.']);
|
|
229
|
+
const warnings = [];
|
|
230
|
+
const project = resolveProject(opts);
|
|
231
|
+
const sched = readSched(project, warnings);
|
|
232
|
+
const maxFullReview = opts.maxFullReview !== undefined
|
|
233
|
+
? positiveInt(opts.maxFullReview, '--max-full-review', { min: 0, max: batch_compose_1.DEFAULT_MAX_MEMBERS })
|
|
234
|
+
: (sched.config?.max_full_review_members ?? sched_1.MAX_FULL_REVIEW_MEMBERS);
|
|
235
|
+
const inputs = picks.map((n) => fetchPick(n, opts.repo));
|
|
236
|
+
const pickSet = new Set(picks);
|
|
237
|
+
// Backlog: explicitly requested, or automatic backfill when the picks fall short.
|
|
238
|
+
const labels = opts.label ?? [];
|
|
239
|
+
let backlogQueried = false;
|
|
240
|
+
// Dependency state lookups, cached across issues (backlog issues are known OPEN for free).
|
|
241
|
+
const knownState = new Map();
|
|
242
|
+
const unresolved = new Set();
|
|
243
|
+
const depCache = new Map();
|
|
244
|
+
/** Pick → the other picks it depends on (checked after assessment, see applyPickDependencies). */
|
|
245
|
+
const pickDeps = new Map();
|
|
246
|
+
function withDeps(input) {
|
|
247
|
+
const cached = depCache.get(input.issue);
|
|
248
|
+
if (cached)
|
|
249
|
+
return cached;
|
|
250
|
+
if (input.error !== undefined)
|
|
251
|
+
return input;
|
|
252
|
+
const open = [];
|
|
253
|
+
const unknown = [];
|
|
254
|
+
const onPicks = [];
|
|
255
|
+
for (const dep of (0, prescreen_1.extractDependencyRefs)(`${input.title}\n${input.body}`)) {
|
|
256
|
+
if (dep === input.issue)
|
|
257
|
+
continue;
|
|
258
|
+
if (pickSet.has(dep)) {
|
|
259
|
+
onPicks.push(dep);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
let state = knownState.get(dep);
|
|
263
|
+
if (state === undefined) {
|
|
264
|
+
const res = (0, gh_1.tryFetchIssueState)(String(dep), opts.repo);
|
|
265
|
+
if (!res.ok) {
|
|
266
|
+
unresolved.add(dep);
|
|
267
|
+
unknown.push(dep);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
state = res.state;
|
|
271
|
+
knownState.set(dep, state);
|
|
272
|
+
}
|
|
273
|
+
if (state.toUpperCase() === 'OPEN')
|
|
274
|
+
open.push(dep);
|
|
275
|
+
}
|
|
276
|
+
if (onPicks.length > 0)
|
|
277
|
+
pickDeps.set(input.issue, onPicks);
|
|
278
|
+
const full = {
|
|
279
|
+
...input,
|
|
280
|
+
openDependencies: open,
|
|
281
|
+
unknownDependencies: unknown,
|
|
282
|
+
schedStatus: activeSchedStatus(sched.state, input.issue),
|
|
283
|
+
};
|
|
284
|
+
depCache.set(input.issue, full);
|
|
285
|
+
return full;
|
|
286
|
+
}
|
|
287
|
+
const isOpen = (issue) => (knownState.get(issue) ?? 'OPEN').toUpperCase() === 'OPEN';
|
|
288
|
+
const assessAll = (list) => (0, batch_compose_1.applyPickDependencies)(list.map((i) => (0, batch_compose_1.assessIssue)(withDeps(i), rules)), pickDeps, isOpen);
|
|
289
|
+
const composeOpts = {
|
|
290
|
+
rules,
|
|
291
|
+
baseBranch: opts.base,
|
|
292
|
+
minMembers,
|
|
293
|
+
maxMembers,
|
|
294
|
+
maxFullReview,
|
|
295
|
+
picksMode: picks.length > 0,
|
|
296
|
+
};
|
|
297
|
+
// Backlog: explicitly requested, or automatic backfill when the picks alone cannot compose
|
|
298
|
+
// min_members (counted after the caps — five admissible review=full picks compose only two).
|
|
299
|
+
const wantBacklog = () => {
|
|
300
|
+
if (opts.backlog)
|
|
301
|
+
return true;
|
|
302
|
+
if (opts.backfill === false)
|
|
303
|
+
return false;
|
|
304
|
+
return (0, batch_compose_1.composeBatch)(assessAll(inputs), composeOpts).members.length < minMembers;
|
|
305
|
+
};
|
|
306
|
+
for (const i of inputs)
|
|
307
|
+
if (i.error === undefined)
|
|
308
|
+
knownState.set(i.issue, i.state);
|
|
309
|
+
if (wantBacklog()) {
|
|
310
|
+
backlogQueried = true;
|
|
311
|
+
const backlog = fetchBacklog({ limit, labels, search: opts.search }, opts.repo, warnings);
|
|
312
|
+
for (const b of backlog)
|
|
313
|
+
knownState.set(b.issue, b.state);
|
|
314
|
+
for (const b of backlog)
|
|
315
|
+
if (!pickSet.has(b.issue))
|
|
316
|
+
inputs.push(b);
|
|
317
|
+
}
|
|
318
|
+
const assessed = assessAll(inputs);
|
|
319
|
+
for (const a of assessed) {
|
|
320
|
+
const input = inputs.find((i) => i.issue === a.issue);
|
|
321
|
+
if (input?.error !== undefined)
|
|
322
|
+
warnings.push(input.error);
|
|
323
|
+
}
|
|
324
|
+
if (unresolved.size > 0) {
|
|
325
|
+
warnings.push(`Could not resolve open/closed state for dependency issue(s) ${[...unresolved].map((n) => `#${n}`).join(', ')} — those issues were excluded as open-dependency (fail closed).`);
|
|
326
|
+
}
|
|
327
|
+
const composition = (0, batch_compose_1.composeBatch)(assessed, composeOpts);
|
|
328
|
+
const excluded = assessed
|
|
329
|
+
.filter((a) => !a.admissible)
|
|
330
|
+
.map((a) => ({ issue: a.issue, title: a.title, source: a.source, reasons: a.excluded }));
|
|
331
|
+
const report = {
|
|
332
|
+
schema: batch_compose_1.COMPOSE_SCHEMA,
|
|
333
|
+
repo: opts.repo ?? null,
|
|
334
|
+
project,
|
|
335
|
+
base_branch: opts.base,
|
|
336
|
+
rules,
|
|
337
|
+
params: {
|
|
338
|
+
min_members: minMembers,
|
|
339
|
+
max_members: maxMembers,
|
|
340
|
+
max_full_review: maxFullReview,
|
|
341
|
+
picks,
|
|
342
|
+
backlog: { queried: backlogQueried, labels, search: opts.search ?? null, limit },
|
|
343
|
+
},
|
|
344
|
+
...composition,
|
|
345
|
+
manifest_entries: composition.members.map((m) => ({
|
|
346
|
+
issue: m.issue,
|
|
347
|
+
mode: 'slot',
|
|
348
|
+
review: m.review,
|
|
349
|
+
base_branch: opts.base,
|
|
350
|
+
})),
|
|
351
|
+
excluded,
|
|
352
|
+
counts: {
|
|
353
|
+
assessed: assessed.length,
|
|
354
|
+
admissible: assessed.length - excluded.length,
|
|
355
|
+
excluded: excluded.length,
|
|
356
|
+
},
|
|
357
|
+
model_calls: 0,
|
|
358
|
+
degraded: warnings.length > 0,
|
|
359
|
+
warnings,
|
|
360
|
+
};
|
|
361
|
+
if (opts.json) {
|
|
362
|
+
console.log(JSON.stringify(report, null, 2));
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
renderText(report);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
function collect(value, previous = []) {
|
|
369
|
+
return [...previous, value];
|
|
370
|
+
}
|
|
371
|
+
/** Registers the `batch` command tree (currently just `compose`). */
|
|
372
|
+
function registerBatchCommand(program) {
|
|
373
|
+
const batch = program
|
|
374
|
+
.command('batch')
|
|
375
|
+
.description('Batch-cycle helpers — deterministic, zero-token batch composition');
|
|
376
|
+
batch
|
|
377
|
+
.command('compose')
|
|
378
|
+
.description('Preview an admissible batch composition from operator picks and/or the backlog (prescreen + readiness, no model call)')
|
|
379
|
+
.option('--issues <selection>', `Operator picks, fleet grammar (e.g. "4114,4178" or "10..14"; at most ${issue_selection_1.MAX_ISSUE_SELECTION})`)
|
|
380
|
+
.option('--backlog', 'Also draw candidates from the open backlog (implied for backfill when picks fall short)')
|
|
381
|
+
.option('--no-backfill', 'Never query the backlog to backfill short picks')
|
|
382
|
+
.option('--label <name>', 'Backlog filter: only issues with this label (repeatable)', collect)
|
|
383
|
+
.option('--search <query>', 'Backlog filter: GitHub search query (gh issue list --search)')
|
|
384
|
+
.option('--limit <n>', `Backlog issues to read (max ${MAX_BACKLOG_LIMIT})`, String(DEFAULT_BACKLOG_LIMIT))
|
|
385
|
+
.option('--repo <owner/name>', 'Target repository (defaults to the current one)')
|
|
386
|
+
.option('--project <slug>', 'sched project whose queue/config to read (defaults to the repo slug)')
|
|
387
|
+
.option('--base <branch>', 'Base branch every member shares', 'main')
|
|
388
|
+
.option('--min-members <n>', 'Minimum viable batch; fewer ⇒ backfill proposed', String(batch_compose_1.DEFAULT_MIN_MEMBERS))
|
|
389
|
+
.option('--max-members <n>', 'Member ceiling', String(batch_compose_1.DEFAULT_MAX_MEMBERS))
|
|
390
|
+
.option('--max-full-review <n>', `Per-batch review=full cap (default: sched config max_full_review_members, else ${sched_1.MAX_FULL_REVIEW_MEMBERS})`)
|
|
391
|
+
.option('--rules <rules>', "Admission rules: 'v2' (prescreen:v2 + review=full members) or 'legacy' (pre-#770: any risk keyword excludes)", 'v2')
|
|
392
|
+
.option('--json', `Machine-readable output (schema ${batch_compose_1.COMPOSE_SCHEMA})`)
|
|
393
|
+
.action((opts) => runCompose(opts));
|
|
394
|
+
}
|
|
395
|
+
//# sourceMappingURL=batch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch.js","sourceRoot":"","sources":["../../src/commands/batch.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sched.d.ts","sourceRoot":"","sources":["../../src/commands/sched.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"sched.d.ts","sourceRoot":"","sources":["../../src/commands/sched.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAKV,oBAAoB,EAIrB,MAAM,mBAAmB,CAAC;AA+D3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkCzC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,CAAC,EAAE;IACjD,yGAAyG;IACzG,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,oBAAoB,CAiEnE;AAw3DD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgB3D"}
|
package/dist/commands/sched.js
CHANGED
|
@@ -364,7 +364,7 @@ function renderReport(report, staleness) {
|
|
|
364
364
|
'pr',
|
|
365
365
|
], report.batches.map((b) => [
|
|
366
366
|
b.id,
|
|
367
|
-
|
|
367
|
+
(0, sched_1.formatBatchStatus)(b),
|
|
368
368
|
String(b.priority),
|
|
369
369
|
b.members.length > 0 ? b.members.map((m) => `#${m}`).join(',') : '-',
|
|
370
370
|
b.executing_member > 0 ? `${b.executing_member}/${b.members.length}` : '-',
|
|
@@ -410,8 +410,54 @@ function renderReport(report, staleness) {
|
|
|
410
410
|
lines.push(stopped.length > 0
|
|
411
411
|
? stopped.map((entry) => `#${entry.issue} — ${entry.reason ?? entry.status}`).join('\n')
|
|
412
412
|
: '(none)');
|
|
413
|
+
// #768: report-only anchor sweep — never closes anything. Omitted entirely
|
|
414
|
+
// when the report was built without GitHub (`--no-anchors`).
|
|
415
|
+
if (report.anchors !== null) {
|
|
416
|
+
lines.push('');
|
|
417
|
+
lines.push('== Open batch anchors ==');
|
|
418
|
+
lines.push(report.anchors.length > 0 ? report.anchors.map(renderAnchorItem).join('\n') : '(none)');
|
|
419
|
+
}
|
|
413
420
|
return lines.join('\n');
|
|
414
421
|
}
|
|
422
|
+
/** Per-call budget for the sweep's reads — `status` must never hang for minutes. */
|
|
423
|
+
const ANCHOR_SWEEP_TIMEOUT_MS = 10_000;
|
|
424
|
+
/**
|
|
425
|
+
* `sched status --anchors`' readers (#768), or `undefined` (with a stderr
|
|
426
|
+
* line) when the cwd is not `project`'s repository — the sweep never reads
|
|
427
|
+
* another repository's issue numbers as if they were this project's.
|
|
428
|
+
*/
|
|
429
|
+
function anchorSweepFor(project) {
|
|
430
|
+
const repo = (0, sched_1.resolveProjectRepo)(project, sched_1.defaultExec);
|
|
431
|
+
if (repo === null) {
|
|
432
|
+
process.stderr.write(`⚠ sched status: anchor sweep skipped — the current directory is not ${project}'s GitHub repository\n`);
|
|
433
|
+
return undefined;
|
|
434
|
+
}
|
|
435
|
+
const exec = (0, sched_1.createExecFn)(ANCHOR_SWEEP_TIMEOUT_MS, {
|
|
436
|
+
onError: (file, args, err) => process.stderr.write(`⚠ sched anchor sweep: '${file} ${args.join(' ')}' failed: ${err.message}\n`),
|
|
437
|
+
});
|
|
438
|
+
const read = (0, sched_1.issueCloseReader)((0, sched_1.createExecGroundTruth)(exec, { repoDir: process.cwd(), repo }));
|
|
439
|
+
if (read === undefined)
|
|
440
|
+
return undefined;
|
|
441
|
+
return {
|
|
442
|
+
read,
|
|
443
|
+
repo,
|
|
444
|
+
// Read-only reachability probe against the already-fetched remote ref.
|
|
445
|
+
commitInBase: (oid, base) => sched_1.GIT_OID_RE.test(oid) &&
|
|
446
|
+
sched_1.SAFE_REF_RE.test(base) &&
|
|
447
|
+
exec('git', ['merge-base', '--is-ancestor', oid, `origin/${base}`], process.cwd()) !== null,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
/** One `== Open batch anchors ==` row (#768): the anchor, its verdict and why, then its members. */
|
|
451
|
+
function renderAnchorItem(a) {
|
|
452
|
+
const reasons = a.reasons.length > 0 ? ` — ${a.reasons.join(', ')}` : '';
|
|
453
|
+
return (`#${a.anchor} (batch ${a.batch}, ${a.batch_status}) [${a.verdict}]${reasons}\n` +
|
|
454
|
+
` members: ${a.members.map(renderAnchorMember).join(', ')}`);
|
|
455
|
+
}
|
|
456
|
+
/** `#4146 CLOSED/COMPLETED (ledger in-work)` — GitHub state beside the ledger's. */
|
|
457
|
+
function renderAnchorMember(m) {
|
|
458
|
+
const github = m.state_reason ? `${m.github}/${m.state_reason}` : m.github;
|
|
459
|
+
return `#${m.issue} ${github} (ledger ${m.ledger_status ?? 'none'})`;
|
|
460
|
+
}
|
|
415
461
|
/** `5m ago` / `2h ago` — compact last-progress rendering for the slot table. */
|
|
416
462
|
function relativeTime(iso, now = Date.now()) {
|
|
417
463
|
const then = Date.parse(iso);
|
|
@@ -919,10 +965,11 @@ function registerStatusSubcommand(cmd) {
|
|
|
919
965
|
.description('Render the queue, slots, batches, and blocked/failed sets')
|
|
920
966
|
.option('--project <slug>', 'Project slug (default: owner-repo of the current directory)')
|
|
921
967
|
.option('--json', 'Output the report as JSON')
|
|
968
|
+
.option('--anchors', "Also sweep open batch anchors (reads issue state from GitHub; run from the project's repository)")
|
|
922
969
|
.action(async (opts) => {
|
|
923
970
|
const { store, project } = resolveStore(opts);
|
|
924
971
|
try {
|
|
925
|
-
const report = (0, sched_1.buildStatusReport)(store.load(), store.loadConfig(), project, store.engineLeaseStatus());
|
|
972
|
+
const report = (0, sched_1.buildStatusReport)(store.load(), store.loadConfig(), project, store.engineLeaseStatus(), new Date(), opts.anchors === true ? anchorSweepFor(project) : undefined);
|
|
926
973
|
// Cache-only (#537): `status` is a fast, offline-friendly diagnostic
|
|
927
974
|
// — it reads whatever `sched start` last cached rather than risking
|
|
928
975
|
// a multi-second hang on an unreachable npm registry.
|
|
@@ -1548,10 +1595,20 @@ function registerStartSubcommand(cmd) {
|
|
|
1548
1595
|
console.log(`▶ sched profile ${name}: ${(0, sched_1.dispatchSummary)((0, sched_1.tierExecutors)((0, sched_1.resolveProfiledDispatch)(engineConfig, name)))}`);
|
|
1549
1596
|
}
|
|
1550
1597
|
}
|
|
1598
|
+
// #768: the anchor close writes to GitHub, so it runs only against the
|
|
1599
|
+
// repository verified to BE this project's — never whatever the cwd is.
|
|
1600
|
+
const anchorRepo = (0, sched_1.resolveProjectRepo)(project, sched_1.defaultExec) ?? undefined;
|
|
1601
|
+
if (anchorRepo === undefined && !(opts.once && opts.json)) {
|
|
1602
|
+
console.log(`▶ sched anchor close: off — the current directory is not ${project}'s GitHub repository`);
|
|
1603
|
+
}
|
|
1551
1604
|
const deps = {
|
|
1552
1605
|
store,
|
|
1553
1606
|
journal: new sched_1.Journal(store.dir),
|
|
1554
|
-
groundTruth: (0, sched_1.createExecGroundTruth)(undefined, {
|
|
1607
|
+
groundTruth: (0, sched_1.createExecGroundTruth)(undefined, {
|
|
1608
|
+
repoDir: process.cwd(),
|
|
1609
|
+
...(anchorRepo !== undefined ? { repo: anchorRepo } : {}),
|
|
1610
|
+
}),
|
|
1611
|
+
...(anchorRepo !== undefined ? { anchorRepo } : {}),
|
|
1555
1612
|
spawnDeps: (0, sched_1.createSpawnDeps)(process.cwd()),
|
|
1556
1613
|
now: () => new Date(),
|
|
1557
1614
|
repoDir: process.cwd(),
|