@rasensio/aidlc 1.20.0 → 1.21.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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/roadmap.d.ts +66 -0
- package/dist/commands/roadmap.d.ts.map +1 -0
- package/dist/commands/roadmap.js +188 -0
- package/dist/commands/roadmap.js.map +1 -0
- package/dist/menu/roster.d.ts.map +1 -1
- package/dist/menu/roster.js +4 -0
- package/dist/menu/roster.js.map +1 -1
- package/dist/roadmap/sync/body.d.ts +37 -0
- package/dist/roadmap/sync/body.d.ts.map +1 -0
- package/dist/roadmap/sync/body.js +52 -0
- package/dist/roadmap/sync/body.js.map +1 -0
- package/dist/roadmap/sync/collect.d.ts +45 -0
- package/dist/roadmap/sync/collect.d.ts.map +1 -0
- package/dist/roadmap/sync/collect.js +93 -0
- package/dist/roadmap/sync/collect.js.map +1 -0
- package/dist/roadmap/sync/config.d.ts +95 -0
- package/dist/roadmap/sync/config.d.ts.map +1 -0
- package/dist/roadmap/sync/config.js +236 -0
- package/dist/roadmap/sync/config.js.map +1 -0
- package/dist/roadmap/sync/discover.d.ts +56 -0
- package/dist/roadmap/sync/discover.d.ts.map +1 -0
- package/dist/roadmap/sync/discover.js +126 -0
- package/dist/roadmap/sync/discover.js.map +1 -0
- package/dist/roadmap/sync/execute.d.ts +41 -0
- package/dist/roadmap/sync/execute.d.ts.map +1 -0
- package/dist/roadmap/sync/execute.js +164 -0
- package/dist/roadmap/sync/execute.js.map +1 -0
- package/dist/roadmap/sync/gh.d.ts +64 -0
- package/dist/roadmap/sync/gh.d.ts.map +1 -0
- package/dist/roadmap/sync/gh.js +86 -0
- package/dist/roadmap/sync/gh.js.map +1 -0
- package/dist/roadmap/sync/import.d.ts +73 -0
- package/dist/roadmap/sync/import.d.ts.map +1 -0
- package/dist/roadmap/sync/import.js +269 -0
- package/dist/roadmap/sync/import.js.map +1 -0
- package/dist/roadmap/sync/labels.d.ts +57 -0
- package/dist/roadmap/sync/labels.d.ts.map +1 -0
- package/dist/roadmap/sync/labels.js +80 -0
- package/dist/roadmap/sync/labels.js.map +1 -0
- package/dist/roadmap/sync/marker.d.ts +38 -0
- package/dist/roadmap/sync/marker.d.ts.map +1 -0
- package/dist/roadmap/sync/marker.js +58 -0
- package/dist/roadmap/sync/marker.js.map +1 -0
- package/dist/roadmap/sync/plan.d.ts +40 -0
- package/dist/roadmap/sync/plan.d.ts.map +1 -0
- package/dist/roadmap/sync/plan.js +272 -0
- package/dist/roadmap/sync/plan.js.map +1 -0
- package/dist/roadmap/sync/render.d.ts +28 -0
- package/dist/roadmap/sync/render.d.ts.map +1 -0
- package/dist/roadmap/sync/render.js +110 -0
- package/dist/roadmap/sync/render.js.map +1 -0
- package/dist/roadmap/sync/types.d.ts +111 -0
- package/dist/roadmap/sync/types.d.ts.map +1 -0
- package/dist/roadmap/sync/types.js +43 -0
- package/dist/roadmap/sync/types.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The projection planner. Pure — and the purity is the point.
|
|
3
|
+
*
|
|
4
|
+
* This module imports no `node:fs`, no `node:child_process`, and not `gh.ts`. A test
|
|
5
|
+
* pins that over the import graph, which is what makes "planning needs no network" a
|
|
6
|
+
* property of the code rather than a claim about the test suite: hand the command a
|
|
7
|
+
* runner that throws on every invocation and planning still succeeds, because the
|
|
8
|
+
* planner never had one.
|
|
9
|
+
*
|
|
10
|
+
* Refusals are **values**, in a fixed order, so a tree with two problems always yields
|
|
11
|
+
* the same message and the command layer — not this module — decides the exit code.
|
|
12
|
+
*
|
|
13
|
+
* Requirements: roadmap-issue-projection/AC-14 … roadmap-issue-projection/AC-32,
|
|
14
|
+
* roadmap-issue-projection/AC-44
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import { ROADMAP_STATUSES } from '../paths.js';
|
|
19
|
+
import { isStatusLabel, statusLabel } from './labels.js';
|
|
20
|
+
import { findMarkerIds } from './marker.js';
|
|
21
|
+
import { WRITE_ORDER, isWrite, } from './types.js';
|
|
22
|
+
/** GitHub's own issue-title limit. */
|
|
23
|
+
export const MAX_ISSUE_TITLE_LENGTH = 256;
|
|
24
|
+
export function planProjection(input) {
|
|
25
|
+
const { config, items, unprojectable, issues, retireIneligible, repoLabel } = input;
|
|
26
|
+
const eligible = new Set(config.statuses);
|
|
27
|
+
// -------------------------------------------------------------------------
|
|
28
|
+
// Refusals, in a fixed order (design: one deterministic message per tree)
|
|
29
|
+
// -------------------------------------------------------------------------
|
|
30
|
+
const duplicateIds = findDuplicateIds(items);
|
|
31
|
+
if (duplicateIds !== null)
|
|
32
|
+
return { kind: 'refused', error: duplicateIds };
|
|
33
|
+
const blockingItems = unprojectable.filter((u) => eligible.has(u.status));
|
|
34
|
+
if (blockingItems.length > 0) {
|
|
35
|
+
return { kind: 'refused', error: unprojectableMessage(blockingItems) };
|
|
36
|
+
}
|
|
37
|
+
const markerIndex = indexByMarker(issues);
|
|
38
|
+
if (markerIndex.kind === 'ambiguous') {
|
|
39
|
+
return { kind: 'refused', error: markerIndex.error };
|
|
40
|
+
}
|
|
41
|
+
const overLong = items.filter((i) => eligible.has(i.status) && i.title.length > MAX_ISSUE_TITLE_LENGTH);
|
|
42
|
+
if (overLong.length > 0) {
|
|
43
|
+
return {
|
|
44
|
+
kind: 'refused',
|
|
45
|
+
error: `these item titles exceed GitHub's ${MAX_ISSUE_TITLE_LENGTH}-character issue title limit ` +
|
|
46
|
+
'and would fail mid-run, after consent:\n' +
|
|
47
|
+
overLong.map((i) => ` ${i.status}/${i.filename} (${i.title.length} characters)`).join('\n'),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// -------------------------------------------------------------------------
|
|
51
|
+
// Outcomes
|
|
52
|
+
// -------------------------------------------------------------------------
|
|
53
|
+
const warnings = unprojectable
|
|
54
|
+
.filter((u) => !eligible.has(u.status))
|
|
55
|
+
.map((u) => `${u.label} is not projectable (${u.reason}), and its status is not projected`);
|
|
56
|
+
const byId = markerIndex.byId;
|
|
57
|
+
const lines = [];
|
|
58
|
+
const claimedIssues = new Set();
|
|
59
|
+
for (const item of items) {
|
|
60
|
+
const issue = byId.get(item.id) ?? null;
|
|
61
|
+
if (issue !== null)
|
|
62
|
+
claimedIssues.add(issue.number);
|
|
63
|
+
lines.push(...linesForItem(item, issue, eligible, retireIneligible));
|
|
64
|
+
}
|
|
65
|
+
// Issue-only lines: an issue nothing on disk claims.
|
|
66
|
+
for (const issue of issues) {
|
|
67
|
+
if (claimedIssues.has(issue.number))
|
|
68
|
+
continue;
|
|
69
|
+
const markers = findMarkerIds(issue.body);
|
|
70
|
+
if (markers.length === 0) {
|
|
71
|
+
lines.push(line('label-without-marker', null, issue.number, 'carries the discovery label but no aidlc-item marker'));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
lines.push(line('orphan-missing', null, issue.number, `marker names ${markers[0]}, which no item on disk has`));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { kind: 'ok', plan: assemble(lines, config, repoLabel), warnings };
|
|
78
|
+
}
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Outcome derivation
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
/**
|
|
83
|
+
* The lines one item produces.
|
|
84
|
+
*
|
|
85
|
+
* A **terminal report** — `state-divergent`, `ineligible-with-issue` — is the only line
|
|
86
|
+
* its item emits. That is not a stylistic choice: collecting outcomes unconditionally
|
|
87
|
+
* would emit `update-title` alongside `state-divergent`, writing to an issue a human
|
|
88
|
+
* deliberately closed. Closing an issue is the primary triage act of the very user this
|
|
89
|
+
* feature is for, so a projection that edits a closed issue relocates the two-writer
|
|
90
|
+
* loop rather than removing it.
|
|
91
|
+
*
|
|
92
|
+
* Non-terminal branches *are* collected, so a `done` item that was also retitled in the
|
|
93
|
+
* same run emits both `update-title` and `close` and converges in one pass.
|
|
94
|
+
*/
|
|
95
|
+
function linesForItem(item, issue, eligible, retireIneligible) {
|
|
96
|
+
const isEligible = eligible.has(item.status);
|
|
97
|
+
if (issue === null) {
|
|
98
|
+
if (!isEligible)
|
|
99
|
+
return [];
|
|
100
|
+
if (item.status === 'done') {
|
|
101
|
+
return [line('skip', item, null, 'not-backfilled')];
|
|
102
|
+
}
|
|
103
|
+
return [
|
|
104
|
+
{
|
|
105
|
+
outcome: 'create',
|
|
106
|
+
item,
|
|
107
|
+
issueNumber: null,
|
|
108
|
+
detail: null,
|
|
109
|
+
addLabels: [statusLabel(item.status)],
|
|
110
|
+
removeLabels: [],
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
if (!isEligible) {
|
|
115
|
+
if (retireIneligible) {
|
|
116
|
+
return [line('close', item, issue.number, `${item.status} is not a projected status`)];
|
|
117
|
+
}
|
|
118
|
+
return [
|
|
119
|
+
line('ineligible-with-issue', item, issue.number, `item is in ${item.status}, which is not projected; the issue is still open`),
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
if (item.status !== 'done' && issue.state === 'CLOSED') {
|
|
123
|
+
return [
|
|
124
|
+
line('state-divergent', item, issue.number, `issue is closed but the item is still in ${item.status} — left alone`),
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
const collected = [];
|
|
128
|
+
if (issue.title !== item.title) {
|
|
129
|
+
collected.push(line('update-title', item, issue.number, null));
|
|
130
|
+
}
|
|
131
|
+
const wanted = statusLabel(item.status);
|
|
132
|
+
const stale = issue.labels.filter((l) => isStatusLabel(l) && l !== wanted);
|
|
133
|
+
const hasWanted = issue.labels.includes(wanted);
|
|
134
|
+
if (!hasWanted || stale.length > 0) {
|
|
135
|
+
collected.push({
|
|
136
|
+
outcome: 'update-labels',
|
|
137
|
+
item,
|
|
138
|
+
issueNumber: issue.number,
|
|
139
|
+
detail: null,
|
|
140
|
+
addLabels: hasWanted ? [] : [wanted],
|
|
141
|
+
removeLabels: stale,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (item.status === 'done' && issue.state === 'OPEN') {
|
|
145
|
+
collected.push(line('close', item, issue.number, null));
|
|
146
|
+
}
|
|
147
|
+
if (collected.length === 0) {
|
|
148
|
+
return [line('unchanged', item, issue.number, null)];
|
|
149
|
+
}
|
|
150
|
+
return collected;
|
|
151
|
+
}
|
|
152
|
+
function line(outcome, item, issueNumber, detail) {
|
|
153
|
+
return { outcome, item, issueNumber, detail, addLabels: [], removeLabels: [] };
|
|
154
|
+
}
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// Indexing and refusal messages
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
/** Two items sharing an id would plan opposite writes against one issue, every run. */
|
|
159
|
+
function findDuplicateIds(items) {
|
|
160
|
+
const seen = new Map();
|
|
161
|
+
const clashes = [];
|
|
162
|
+
for (const item of items) {
|
|
163
|
+
const prior = seen.get(item.id);
|
|
164
|
+
if (prior === undefined) {
|
|
165
|
+
seen.set(item.id, item);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
clashes.push(` ${item.id}\n ${prior.status}/${prior.filename}\n ${item.status}/${item.filename}`);
|
|
169
|
+
}
|
|
170
|
+
if (clashes.length === 0)
|
|
171
|
+
return null;
|
|
172
|
+
return ('two roadmap items share one id, so the projection cannot tell which one an issue ' +
|
|
173
|
+
'belongs to:\n' +
|
|
174
|
+
clashes.join('\n') +
|
|
175
|
+
'\nRemove or re-id one of each pair, then run again.');
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Index issues by the item id in their marker.
|
|
179
|
+
*
|
|
180
|
+
* Two issues carrying one marker is refused rather than resolved: picking either would
|
|
181
|
+
* mean confidently retitling or closing the wrong one.
|
|
182
|
+
*/
|
|
183
|
+
function indexByMarker(issues) {
|
|
184
|
+
const byId = new Map();
|
|
185
|
+
const clashes = [];
|
|
186
|
+
for (const issue of issues) {
|
|
187
|
+
for (const id of findMarkerIds(issue.body)) {
|
|
188
|
+
const prior = byId.get(id);
|
|
189
|
+
if (prior === undefined) {
|
|
190
|
+
byId.set(id, issue);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
clashes.push(` ${id} — issues #${prior.number} and #${issue.number}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (clashes.length > 0) {
|
|
197
|
+
return {
|
|
198
|
+
kind: 'ambiguous',
|
|
199
|
+
error: 'more than one issue carries the same aidlc-item marker, so the projection cannot ' +
|
|
200
|
+
'tell which is canonical:\n' +
|
|
201
|
+
clashes.join('\n') +
|
|
202
|
+
'\nRemove the marker from whichever issue is not the canonical one, then run again.',
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return { kind: 'ok', byId };
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* The unprojectable-item refusal.
|
|
209
|
+
*
|
|
210
|
+
* Split by class, because the remedies differ and only one of them has a tool. Sending
|
|
211
|
+
* somebody to `aidlc doctor` for a missing `id` would send them to a command that reports
|
|
212
|
+
* nothing at all.
|
|
213
|
+
*/
|
|
214
|
+
function unprojectableMessage(blocking) {
|
|
215
|
+
const repairable = blocking.filter((u) => u.cls === 'unparseable');
|
|
216
|
+
const manual = blocking.filter((u) => u.cls === 'missing-id');
|
|
217
|
+
const parts = [
|
|
218
|
+
'these roadmap items are in a projected status but cannot be read, so the projection ' +
|
|
219
|
+
'would silently leave them out of both the repo and the tracker:',
|
|
220
|
+
];
|
|
221
|
+
if (repairable.length > 0) {
|
|
222
|
+
parts.push('', ' frontmatter will not parse — run `aidlc doctor`, which repairs the common case ' +
|
|
223
|
+
'(an unquoted title):', ...repairable.map((u) => ` ${u.label} — ${u.reason}`));
|
|
224
|
+
}
|
|
225
|
+
if (manual.length > 0) {
|
|
226
|
+
parts.push('', ' no `id:` — `aidlc doctor` does not detect this class; add an id by hand:', ...manual.map((u) => ` ${u.label} — ${u.reason}`));
|
|
227
|
+
}
|
|
228
|
+
return parts.join('\n');
|
|
229
|
+
}
|
|
230
|
+
// ---------------------------------------------------------------------------
|
|
231
|
+
// Assembly and ordering
|
|
232
|
+
// ---------------------------------------------------------------------------
|
|
233
|
+
/**
|
|
234
|
+
* Total order (so two runs over identical inputs print byte-identically):
|
|
235
|
+
* item lines by status then filename then execution order; issue-only lines after them,
|
|
236
|
+
* by issue number.
|
|
237
|
+
*
|
|
238
|
+
* The outcome component is compared through `WRITE_ORDER`, not as a string, so two lines
|
|
239
|
+
* for one item appear in the order they will be executed rather than in alphabetical
|
|
240
|
+
* accident.
|
|
241
|
+
*/
|
|
242
|
+
function assemble(lines, config, repoLabel) {
|
|
243
|
+
const sorted = [...lines].sort(compareLines);
|
|
244
|
+
const counts = {};
|
|
245
|
+
let writeCount = 0;
|
|
246
|
+
for (const l of sorted) {
|
|
247
|
+
counts[l.outcome] = (counts[l.outcome] ?? 0) + 1;
|
|
248
|
+
if (isWrite(l.outcome))
|
|
249
|
+
writeCount += 1;
|
|
250
|
+
}
|
|
251
|
+
return { repoLabel, repo: config.repo, lines: sorted, counts, writeCount };
|
|
252
|
+
}
|
|
253
|
+
function compareLines(a, b) {
|
|
254
|
+
if (a.item === null && b.item === null)
|
|
255
|
+
return (a.issueNumber ?? 0) - (b.issueNumber ?? 0);
|
|
256
|
+
if (a.item === null)
|
|
257
|
+
return 1;
|
|
258
|
+
if (b.item === null)
|
|
259
|
+
return -1;
|
|
260
|
+
const statusDelta = ROADMAP_STATUSES.indexOf(a.item.status) - ROADMAP_STATUSES.indexOf(b.item.status);
|
|
261
|
+
if (statusDelta !== 0)
|
|
262
|
+
return statusDelta;
|
|
263
|
+
if (a.item.filename !== b.item.filename)
|
|
264
|
+
return a.item.filename < b.item.filename ? -1 : 1;
|
|
265
|
+
return outcomeRank(a.outcome) - outcomeRank(b.outcome);
|
|
266
|
+
}
|
|
267
|
+
/** Execution order first, then everything else in a fixed position. */
|
|
268
|
+
function outcomeRank(outcome) {
|
|
269
|
+
const index = WRITE_ORDER.indexOf(outcome);
|
|
270
|
+
return index === -1 ? WRITE_ORDER.length : index;
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/roadmap/sync/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan → text.
|
|
3
|
+
*
|
|
4
|
+
* Two rules the plan output has to keep:
|
|
5
|
+
*
|
|
6
|
+
* - **The resolved repository is named in the header.** A well-formed but wrong
|
|
7
|
+
* repository coordinate publishes the roadmap to somebody else's repo, and that is only
|
|
8
|
+
* reversible before the first write. Printing it is the whole mitigation.
|
|
9
|
+
* - **Every outcome prints as a word.** Colour, if ever added, is decoration; the
|
|
10
|
+
* accessibility guidance forbids colour as the sole carrier of meaning, and a piped or
|
|
11
|
+
* logged plan has no colour at all.
|
|
12
|
+
*
|
|
13
|
+
* Requirements: roadmap-issue-projection/AC-40
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import { type Plan } from './types.js';
|
|
18
|
+
export declare function renderPlan(plan: Plan): string;
|
|
19
|
+
/**
|
|
20
|
+
* The counts, writes first.
|
|
21
|
+
*
|
|
22
|
+
* Printed before consent so a first run against a mature roadmap — forty creates — is a
|
|
23
|
+
* visible decision rather than a surprise.
|
|
24
|
+
*/
|
|
25
|
+
export declare function summary(plan: Plan): string;
|
|
26
|
+
/** The confirmation question. Names the repository again, deliberately. */
|
|
27
|
+
export declare function confirmMessage(plan: Plan): string;
|
|
28
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/roadmap/sync/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAyB,KAAK,IAAI,EAAiB,MAAM,YAAY,CAAC;AA8B7E,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAoB7C;AAwBD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAiB1C;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAEjD"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan → text.
|
|
3
|
+
*
|
|
4
|
+
* Two rules the plan output has to keep:
|
|
5
|
+
*
|
|
6
|
+
* - **The resolved repository is named in the header.** A well-formed but wrong
|
|
7
|
+
* repository coordinate publishes the roadmap to somebody else's repo, and that is only
|
|
8
|
+
* reversible before the first write. Printing it is the whole mitigation.
|
|
9
|
+
* - **Every outcome prints as a word.** Colour, if ever added, is decoration; the
|
|
10
|
+
* accessibility guidance forbids colour as the sole carrier of meaning, and a piped or
|
|
11
|
+
* logged plan has no colour at all.
|
|
12
|
+
*
|
|
13
|
+
* Requirements: roadmap-issue-projection/AC-40
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import { isWrite } from './types.js';
|
|
18
|
+
/** Display order for the counts summary: writes first, then reports. */
|
|
19
|
+
const COUNT_ORDER = [
|
|
20
|
+
'create',
|
|
21
|
+
'update-title',
|
|
22
|
+
'update-labels',
|
|
23
|
+
'close',
|
|
24
|
+
'unchanged',
|
|
25
|
+
'skip',
|
|
26
|
+
'state-divergent',
|
|
27
|
+
'ineligible-with-issue',
|
|
28
|
+
'orphan-missing',
|
|
29
|
+
'label-without-marker',
|
|
30
|
+
];
|
|
31
|
+
/** One-line human gloss per outcome, so the plan reads without a legend. */
|
|
32
|
+
const GLOSS = {
|
|
33
|
+
create: 'create an issue',
|
|
34
|
+
'update-title': 'update the issue title',
|
|
35
|
+
'update-labels': 'update the aidlc: status label',
|
|
36
|
+
close: 'close the issue',
|
|
37
|
+
unchanged: 'already matches',
|
|
38
|
+
skip: 'not projected',
|
|
39
|
+
'state-divergent': 'closed remotely, item still live — left alone',
|
|
40
|
+
'ineligible-with-issue': 'status no longer projected, issue still open',
|
|
41
|
+
'orphan-missing': 'no item on disk',
|
|
42
|
+
'label-without-marker': 'labelled but not projected by aidlc',
|
|
43
|
+
};
|
|
44
|
+
export function renderPlan(plan) {
|
|
45
|
+
const out = [];
|
|
46
|
+
out.push(`Roadmap projection plan — ${plan.repoLabel}`);
|
|
47
|
+
out.push('');
|
|
48
|
+
if (plan.lines.length === 0) {
|
|
49
|
+
out.push(' nothing to project: no items in a projected status, and no labelled issues.');
|
|
50
|
+
out.push('');
|
|
51
|
+
return out.join('\n');
|
|
52
|
+
}
|
|
53
|
+
for (const line of plan.lines) {
|
|
54
|
+
out.push(` ${renderLine(line)}`);
|
|
55
|
+
}
|
|
56
|
+
out.push('');
|
|
57
|
+
out.push(summary(plan));
|
|
58
|
+
out.push('');
|
|
59
|
+
return out.join('\n');
|
|
60
|
+
}
|
|
61
|
+
function renderLine(line) {
|
|
62
|
+
const subject = line.item === null
|
|
63
|
+
? `#${line.issueNumber}`
|
|
64
|
+
: `${line.item.status}/${line.item.filename}` +
|
|
65
|
+
(line.issueNumber === null ? '' : ` → #${line.issueNumber}`);
|
|
66
|
+
const parts = [pad(line.outcome), subject];
|
|
67
|
+
const notes = [];
|
|
68
|
+
if (line.addLabels.length > 0)
|
|
69
|
+
notes.push(`+${line.addLabels.join(' +')}`);
|
|
70
|
+
if (line.removeLabels.length > 0)
|
|
71
|
+
notes.push(`-${line.removeLabels.join(' -')}`);
|
|
72
|
+
if (line.detail !== null)
|
|
73
|
+
notes.push(line.detail);
|
|
74
|
+
if (notes.length > 0)
|
|
75
|
+
parts.push(`(${notes.join('; ')})`);
|
|
76
|
+
return parts.join(' ');
|
|
77
|
+
}
|
|
78
|
+
/** Left-pad the outcome word so the subjects line up without a table. */
|
|
79
|
+
function pad(outcome) {
|
|
80
|
+
const width = Math.max(...COUNT_ORDER.map((o) => o.length));
|
|
81
|
+
return outcome.padEnd(width, ' ');
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The counts, writes first.
|
|
85
|
+
*
|
|
86
|
+
* Printed before consent so a first run against a mature roadmap — forty creates — is a
|
|
87
|
+
* visible decision rather than a surprise.
|
|
88
|
+
*/
|
|
89
|
+
export function summary(plan) {
|
|
90
|
+
const present = COUNT_ORDER.filter((o) => (plan.counts[o] ?? 0) > 0);
|
|
91
|
+
const writes = present.filter(isWrite);
|
|
92
|
+
const reports = present.filter((o) => !isWrite(o));
|
|
93
|
+
const lines = [];
|
|
94
|
+
lines.push(plan.writeCount === 0
|
|
95
|
+
? ' No writes. Nothing on GitHub would change.'
|
|
96
|
+
: ` ${plan.writeCount} write${plan.writeCount === 1 ? '' : 's'}:`);
|
|
97
|
+
for (const o of writes)
|
|
98
|
+
lines.push(` ${plan.counts[o]} × ${o} — ${GLOSS[o]}`);
|
|
99
|
+
if (reports.length > 0) {
|
|
100
|
+
lines.push(' Reported only:');
|
|
101
|
+
for (const o of reports)
|
|
102
|
+
lines.push(` ${plan.counts[o]} × ${o} — ${GLOSS[o]}`);
|
|
103
|
+
}
|
|
104
|
+
return lines.join('\n');
|
|
105
|
+
}
|
|
106
|
+
/** The confirmation question. Names the repository again, deliberately. */
|
|
107
|
+
export function confirmMessage(plan) {
|
|
108
|
+
return `Apply ${plan.writeCount} write${plan.writeCount === 1 ? '' : 's'} to ${plan.repoLabel}?`;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/roadmap/sync/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the roadmap → GitHub Issues projection.
|
|
3
|
+
*
|
|
4
|
+
* The projection is one-way: disk is the source of truth and the tracker is a
|
|
5
|
+
* rendering of it. Two consequences show up throughout these types.
|
|
6
|
+
*
|
|
7
|
+
* First, `sync` writes nothing to disk (design DD-1). There is no `remote:`
|
|
8
|
+
* frontmatter field and no cache: the durable link is the item `id`, carried in a
|
|
9
|
+
* body marker on the issue. Creating an issue and writing a local link would be two
|
|
10
|
+
* writes to two systems, and every failure of the second produces a duplicate on the
|
|
11
|
+
* next run.
|
|
12
|
+
*
|
|
13
|
+
* Second, an outcome is a *value*, not an action. `planProjection` returns a plan of
|
|
14
|
+
* outcomes and the command layer decides what to do with it, which is what makes the
|
|
15
|
+
* whole projection testable with no network and no `gh` binary.
|
|
16
|
+
*
|
|
17
|
+
* Requirements: roadmap-issue-projection/AC-14, roadmap-issue-projection/AC-46
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import type { RoadmapStatus } from '../paths.js';
|
|
22
|
+
/**
|
|
23
|
+
* What the projection concluded about one item, or one issue.
|
|
24
|
+
*
|
|
25
|
+
* A closed set. The design review found that an open-ended vocabulary made two
|
|
26
|
+
* criteria unachievable — "the second plan contains only X or Y" cannot be checked
|
|
27
|
+
* against a list nobody wrote down.
|
|
28
|
+
*/
|
|
29
|
+
export type Outcome = 'create' | 'update-title' | 'update-labels' | 'close' | 'unchanged' | 'skip' | 'state-divergent' | 'ineligible-with-issue' | 'orphan-missing' | 'label-without-marker';
|
|
30
|
+
/** The four outcomes that write. Everything else is a report. */
|
|
31
|
+
export declare const WRITE_OUTCOMES: readonly Outcome[];
|
|
32
|
+
/**
|
|
33
|
+
* Outcomes that suppress every write for their item (design DE-18).
|
|
34
|
+
*
|
|
35
|
+
* `state-divergent` means a human closed the issue while the item is still live.
|
|
36
|
+
* Reopening it would relocate the two-writer loop rather than remove it, and
|
|
37
|
+
* retitling it would write to an issue somebody deliberately closed. So a terminal
|
|
38
|
+
* report is the *only* line its item emits.
|
|
39
|
+
*/
|
|
40
|
+
export declare const TERMINAL_REPORTS: readonly Outcome[];
|
|
41
|
+
/** Execution order within one item: edit while the issue is still open, then close. */
|
|
42
|
+
export declare const WRITE_ORDER: readonly Outcome[];
|
|
43
|
+
/** True when this outcome performs a `gh` write. */
|
|
44
|
+
export declare function isWrite(outcome: Outcome): boolean;
|
|
45
|
+
/** An item that can be projected: parseable, with an id. */
|
|
46
|
+
export interface ProjectableItem {
|
|
47
|
+
id: string;
|
|
48
|
+
/** Falls back to the filename slug when frontmatter carries no title. */
|
|
49
|
+
title: string;
|
|
50
|
+
status: RoadmapStatus;
|
|
51
|
+
filename: string;
|
|
52
|
+
/** Repo-relative path, for the issue body. */
|
|
53
|
+
relPath: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Why an item cannot be projected.
|
|
57
|
+
*
|
|
58
|
+
* The two classes are distinguished because their remedies differ and only one of
|
|
59
|
+
* them has a tool. `aidlc doctor` repairs an unquoted title; nothing reports an item
|
|
60
|
+
* that parses fine with no `id`, so pointing a user at `doctor` for that class would
|
|
61
|
+
* send them to a command that says nothing (design DE-14).
|
|
62
|
+
*/
|
|
63
|
+
export type UnprojectableClass = 'unparseable' | 'missing-id';
|
|
64
|
+
export interface UnprojectableRef {
|
|
65
|
+
/** `<status>/<filename>` — the form doctor output uses. */
|
|
66
|
+
label: string;
|
|
67
|
+
status: RoadmapStatus;
|
|
68
|
+
cls: UnprojectableClass;
|
|
69
|
+
reason: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* One issue as the projection needs it.
|
|
73
|
+
*
|
|
74
|
+
* `labels` is already flattened to names. `gh issue list --json labels` returns
|
|
75
|
+
* objects (`{id,name,description,color}`), and treating them as strings would make
|
|
76
|
+
* every status-label comparison fail — so every item would plan `update-labels` on
|
|
77
|
+
* every run, forever, and the projection would never converge (design DE-9).
|
|
78
|
+
*/
|
|
79
|
+
export interface RemoteIssue {
|
|
80
|
+
number: number;
|
|
81
|
+
title: string;
|
|
82
|
+
state: 'OPEN' | 'CLOSED';
|
|
83
|
+
labels: readonly string[];
|
|
84
|
+
body: string;
|
|
85
|
+
}
|
|
86
|
+
/** One line of a plan. */
|
|
87
|
+
export interface PlanLine {
|
|
88
|
+
outcome: Outcome;
|
|
89
|
+
/** null on issue-only lines (`orphan-missing`, `label-without-marker`). */
|
|
90
|
+
item: ProjectableItem | null;
|
|
91
|
+
issueNumber: number | null;
|
|
92
|
+
/** Short reason, e.g. `not-backfilled`, or the divergence in words. */
|
|
93
|
+
detail: string | null;
|
|
94
|
+
addLabels: readonly string[];
|
|
95
|
+
removeLabels: readonly string[];
|
|
96
|
+
}
|
|
97
|
+
export interface Plan {
|
|
98
|
+
/**
|
|
99
|
+
* Printed in the plan header *and* the confirmation prompt. A projection aimed at
|
|
100
|
+
* the wrong repository is only reversible before the first write, so the resolved
|
|
101
|
+
* target is stated at both moments a human can still stop it.
|
|
102
|
+
*/
|
|
103
|
+
repoLabel: string;
|
|
104
|
+
/** `owner/name`, or null when `gh` resolves the current repository. */
|
|
105
|
+
repo: string | null;
|
|
106
|
+
lines: readonly PlanLine[];
|
|
107
|
+
/** Only outcomes actually present appear as keys. */
|
|
108
|
+
counts: Readonly<Partial<Record<Outcome, number>>>;
|
|
109
|
+
writeCount: number;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/roadmap/sync/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,MAAM,OAAO,GACf,QAAQ,GACR,cAAc,GACd,eAAe,GACf,OAAO,GACP,WAAW,GACX,MAAM,GACN,iBAAiB,GACjB,uBAAuB,GACvB,gBAAgB,GAChB,sBAAsB,CAAC;AAE3B,iEAAiE;AACjE,eAAO,MAAM,cAAc,EAAE,SAAS,OAAO,EAK5C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,OAAO,EAAiD,CAAC;AAEjG,uFAAuF;AACvF,eAAO,MAAM,WAAW,EAAE,SAAS,OAAO,EAAyD,CAAC;AAEpG,oDAAoD;AACpD,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEjD;AAED,4DAA4D;AAC5D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,aAAa,GAAG,YAAY,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,aAAa,CAAC;IACtB,GAAG,EAAE,kBAAkB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,0BAA0B;AAC1B,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,uEAAuE;IACvE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,IAAI;IACnB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC3B,qDAAqD;IACrD,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACnD,UAAU,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the roadmap → GitHub Issues projection.
|
|
3
|
+
*
|
|
4
|
+
* The projection is one-way: disk is the source of truth and the tracker is a
|
|
5
|
+
* rendering of it. Two consequences show up throughout these types.
|
|
6
|
+
*
|
|
7
|
+
* First, `sync` writes nothing to disk (design DD-1). There is no `remote:`
|
|
8
|
+
* frontmatter field and no cache: the durable link is the item `id`, carried in a
|
|
9
|
+
* body marker on the issue. Creating an issue and writing a local link would be two
|
|
10
|
+
* writes to two systems, and every failure of the second produces a duplicate on the
|
|
11
|
+
* next run.
|
|
12
|
+
*
|
|
13
|
+
* Second, an outcome is a *value*, not an action. `planProjection` returns a plan of
|
|
14
|
+
* outcomes and the command layer decides what to do with it, which is what makes the
|
|
15
|
+
* whole projection testable with no network and no `gh` binary.
|
|
16
|
+
*
|
|
17
|
+
* Requirements: roadmap-issue-projection/AC-14, roadmap-issue-projection/AC-46
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
/** The four outcomes that write. Everything else is a report. */
|
|
22
|
+
export const WRITE_OUTCOMES = [
|
|
23
|
+
'create',
|
|
24
|
+
'update-title',
|
|
25
|
+
'update-labels',
|
|
26
|
+
'close',
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Outcomes that suppress every write for their item (design DE-18).
|
|
30
|
+
*
|
|
31
|
+
* `state-divergent` means a human closed the issue while the item is still live.
|
|
32
|
+
* Reopening it would relocate the two-writer loop rather than remove it, and
|
|
33
|
+
* retitling it would write to an issue somebody deliberately closed. So a terminal
|
|
34
|
+
* report is the *only* line its item emits.
|
|
35
|
+
*/
|
|
36
|
+
export const TERMINAL_REPORTS = ['state-divergent', 'ineligible-with-issue'];
|
|
37
|
+
/** Execution order within one item: edit while the issue is still open, then close. */
|
|
38
|
+
export const WRITE_ORDER = ['create', 'update-title', 'update-labels', 'close'];
|
|
39
|
+
/** True when this outcome performs a `gh` write. */
|
|
40
|
+
export function isWrite(outcome) {
|
|
41
|
+
return WRITE_OUTCOMES.includes(outcome);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/roadmap/sync/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAuBH,iEAAiE;AACjE,MAAM,CAAC,MAAM,cAAc,GAAuB;IAChD,QAAQ;IACR,cAAc;IACd,eAAe;IACf,OAAO;CACR,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAuB,CAAC,iBAAiB,EAAE,uBAAuB,CAAC,CAAC;AAEjG,uFAAuF;AACvF,MAAM,CAAC,MAAM,WAAW,GAAuB,CAAC,QAAQ,EAAE,cAAc,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;AAEpG,oDAAoD;AACpD,MAAM,UAAU,OAAO,CAAC,OAAgB;IACtC,OAAO,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC1C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rasensio/aidlc",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.0",
|
|
4
4
|
"description": "AI Development Lifecycle Framework — structured lifecycle guidance for AI coding agents across platforms",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cli.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"commander": "15.0.0",
|
|
25
25
|
"picomatch": "4.0.5",
|
|
26
26
|
"yaml": "2.9.0",
|
|
27
|
-
"@rasensio/aidlc-content": "1.
|
|
27
|
+
"@rasensio/aidlc-content": "1.21.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/node": "22.15.32",
|