@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.
Files changed (59) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +2 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/roadmap.d.ts +66 -0
  5. package/dist/commands/roadmap.d.ts.map +1 -0
  6. package/dist/commands/roadmap.js +188 -0
  7. package/dist/commands/roadmap.js.map +1 -0
  8. package/dist/menu/roster.d.ts.map +1 -1
  9. package/dist/menu/roster.js +4 -0
  10. package/dist/menu/roster.js.map +1 -1
  11. package/dist/roadmap/sync/body.d.ts +37 -0
  12. package/dist/roadmap/sync/body.d.ts.map +1 -0
  13. package/dist/roadmap/sync/body.js +52 -0
  14. package/dist/roadmap/sync/body.js.map +1 -0
  15. package/dist/roadmap/sync/collect.d.ts +45 -0
  16. package/dist/roadmap/sync/collect.d.ts.map +1 -0
  17. package/dist/roadmap/sync/collect.js +93 -0
  18. package/dist/roadmap/sync/collect.js.map +1 -0
  19. package/dist/roadmap/sync/config.d.ts +95 -0
  20. package/dist/roadmap/sync/config.d.ts.map +1 -0
  21. package/dist/roadmap/sync/config.js +236 -0
  22. package/dist/roadmap/sync/config.js.map +1 -0
  23. package/dist/roadmap/sync/discover.d.ts +56 -0
  24. package/dist/roadmap/sync/discover.d.ts.map +1 -0
  25. package/dist/roadmap/sync/discover.js +126 -0
  26. package/dist/roadmap/sync/discover.js.map +1 -0
  27. package/dist/roadmap/sync/execute.d.ts +41 -0
  28. package/dist/roadmap/sync/execute.d.ts.map +1 -0
  29. package/dist/roadmap/sync/execute.js +164 -0
  30. package/dist/roadmap/sync/execute.js.map +1 -0
  31. package/dist/roadmap/sync/gh.d.ts +64 -0
  32. package/dist/roadmap/sync/gh.d.ts.map +1 -0
  33. package/dist/roadmap/sync/gh.js +86 -0
  34. package/dist/roadmap/sync/gh.js.map +1 -0
  35. package/dist/roadmap/sync/import.d.ts +73 -0
  36. package/dist/roadmap/sync/import.d.ts.map +1 -0
  37. package/dist/roadmap/sync/import.js +269 -0
  38. package/dist/roadmap/sync/import.js.map +1 -0
  39. package/dist/roadmap/sync/labels.d.ts +57 -0
  40. package/dist/roadmap/sync/labels.d.ts.map +1 -0
  41. package/dist/roadmap/sync/labels.js +80 -0
  42. package/dist/roadmap/sync/labels.js.map +1 -0
  43. package/dist/roadmap/sync/marker.d.ts +38 -0
  44. package/dist/roadmap/sync/marker.d.ts.map +1 -0
  45. package/dist/roadmap/sync/marker.js +58 -0
  46. package/dist/roadmap/sync/marker.js.map +1 -0
  47. package/dist/roadmap/sync/plan.d.ts +40 -0
  48. package/dist/roadmap/sync/plan.d.ts.map +1 -0
  49. package/dist/roadmap/sync/plan.js +272 -0
  50. package/dist/roadmap/sync/plan.js.map +1 -0
  51. package/dist/roadmap/sync/render.d.ts +28 -0
  52. package/dist/roadmap/sync/render.d.ts.map +1 -0
  53. package/dist/roadmap/sync/render.js +110 -0
  54. package/dist/roadmap/sync/render.js.map +1 -0
  55. package/dist/roadmap/sync/types.d.ts +111 -0
  56. package/dist/roadmap/sync/types.d.ts.map +1 -0
  57. package/dist/roadmap/sync/types.js +43 -0
  58. package/dist/roadmap/sync/types.js.map +1 -0
  59. package/package.json +2 -2
@@ -0,0 +1,95 @@
1
+ /**
2
+ * The `roadmap.sync` section of `.aidlc/config.yaml`.
3
+ *
4
+ * Follows the convention every other module's config reader in this package follows —
5
+ * there is no central config loader here, ten call sites each parse the file inline —
6
+ * with one boundary drawn explicitly, because the requirements review found revision 1
7
+ * contradicting itself about it:
8
+ *
9
+ * - A malformed **container** reads as *not configured*: unparseable YAML, `roadmap`
10
+ * not a mapping, `roadmap.sync` not a mapping. One bad section must never break an
11
+ * unrelated command.
12
+ * - Anything wrong **inside** a well-formed `sync` mapping is a *named refusal*,
13
+ * including a wrong-typed value. `provider: 123` is a mistake somebody made on
14
+ * purpose and wants told about; silently reading it as "you have not configured this"
15
+ * would send them looking in the wrong place.
16
+ *
17
+ * The section is read from the **primary checkout**, the same tree the items come from.
18
+ * Items and eligibility are one fact; reading them from two trees would let a feature
19
+ * branch change what a colleague's `sync` publishes.
20
+ *
21
+ * Requirements: roadmap-issue-projection/AC-1 … roadmap-issue-projection/AC-9
22
+ *
23
+ * @module
24
+ */
25
+ import { type RoadmapStatus } from '../paths.js';
26
+ /** The `roadmap.sync` section, validated. */
27
+ export interface SyncConfig {
28
+ provider: 'github';
29
+ /** `owner/name`, or null when `gh` resolves the current repository. */
30
+ repo: string | null;
31
+ statuses: readonly RoadmapStatus[];
32
+ label: string;
33
+ }
34
+ export type SyncConfigResult = {
35
+ kind: 'ok';
36
+ config: SyncConfig;
37
+ } | {
38
+ kind: 'not-configured';
39
+ } | {
40
+ kind: 'invalid';
41
+ error: string;
42
+ };
43
+ /**
44
+ * The default eligible statuses.
45
+ *
46
+ * The line falls between "thinking" and "work". `inbox/` means captured, not committed
47
+ * to — projecting it puts issues on a board for decisions nobody has made. `hold/`
48
+ * holds parked and declined work, which on this project means pricing thinking and a
49
+ * competitor teardown; a markdown file in a repo and an indexed, notification-generating
50
+ * issue are not the same exposure even when both are technically public.
51
+ */
52
+ export declare const DEFAULT_STATUSES: readonly RoadmapStatus[];
53
+ /**
54
+ * Validate a repository coordinate. Shared by the config value and `--repo`, so the two
55
+ * can never diverge.
56
+ */
57
+ export declare function validateRepo(raw: unknown, source: string): {
58
+ ok: true;
59
+ repo: string;
60
+ } | {
61
+ ok: false;
62
+ error: string;
63
+ };
64
+ /**
65
+ * Validate the discovery label.
66
+ *
67
+ * A comma is refused explicitly rather than folded into a charset message, because the
68
+ * failure it causes is silent and expensive: `gh`'s `--label` is a comma-split slice, so
69
+ * `aidlc,urgent` would AND two labels in discovery, return an empty issue map, and
70
+ * re-create every issue on every run. The discovery label *is* the identity of a
71
+ * projected issue, so a wrong one is a duplicate-issue generator, not a cosmetic error.
72
+ */
73
+ export declare function validateLabel(raw: unknown): {
74
+ ok: true;
75
+ label: string;
76
+ } | {
77
+ ok: false;
78
+ error: string;
79
+ };
80
+ /**
81
+ * Read and validate the `roadmap.sync` section from a checkout's config.
82
+ *
83
+ * @param primaryCheckoutRoot - The primary checkout's working tree.
84
+ */
85
+ export declare function readSyncConfig(primaryCheckoutRoot: string): SyncConfigResult;
86
+ /**
87
+ * Apply a `--repo` flag over a config, with identical validation.
88
+ *
89
+ * The flag wins. It is the likelier source of a wrong value — typed by hand, once —
90
+ * which is why it goes through the same validator rather than a looser one.
91
+ */
92
+ export declare function withRepoOverride(config: SyncConfig, repo: string | undefined): SyncConfigResult;
93
+ /** The message for a project that has not opted in. */
94
+ export declare function notConfiguredMessage(): string;
95
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/roadmap/sync/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAGnE,6CAA6C;AAC7C,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,uEAAuE;IACvE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,aAAa,EAAuC,CAAC;AAkC7F;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAmBpH;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CA0BtG;AA+BD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,mBAAmB,EAAE,MAAM,GAAG,gBAAgB,CAiD5E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,gBAAgB,CAK/F;AAED,uDAAuD;AACvD,wBAAgB,oBAAoB,IAAI,MAAM,CAW7C"}
@@ -0,0 +1,236 @@
1
+ /**
2
+ * The `roadmap.sync` section of `.aidlc/config.yaml`.
3
+ *
4
+ * Follows the convention every other module's config reader in this package follows —
5
+ * there is no central config loader here, ten call sites each parse the file inline —
6
+ * with one boundary drawn explicitly, because the requirements review found revision 1
7
+ * contradicting itself about it:
8
+ *
9
+ * - A malformed **container** reads as *not configured*: unparseable YAML, `roadmap`
10
+ * not a mapping, `roadmap.sync` not a mapping. One bad section must never break an
11
+ * unrelated command.
12
+ * - Anything wrong **inside** a well-formed `sync` mapping is a *named refusal*,
13
+ * including a wrong-typed value. `provider: 123` is a mistake somebody made on
14
+ * purpose and wants told about; silently reading it as "you have not configured this"
15
+ * would send them looking in the wrong place.
16
+ *
17
+ * The section is read from the **primary checkout**, the same tree the items come from.
18
+ * Items and eligibility are one fact; reading them from two trees would let a feature
19
+ * branch change what a colleague's `sync` publishes.
20
+ *
21
+ * Requirements: roadmap-issue-projection/AC-1 … roadmap-issue-projection/AC-9
22
+ *
23
+ * @module
24
+ */
25
+ import { existsSync, readFileSync } from 'node:fs';
26
+ import { join } from 'node:path';
27
+ import { parse as parseYaml } from 'yaml';
28
+ import { ROADMAP_STATUSES } from '../paths.js';
29
+ import { DEFAULT_DISCOVERY_LABEL, MAX_LABEL_LENGTH } from './labels.js';
30
+ /**
31
+ * The default eligible statuses.
32
+ *
33
+ * The line falls between "thinking" and "work". `inbox/` means captured, not committed
34
+ * to — projecting it puts issues on a board for decisions nobody has made. `hold/`
35
+ * holds parked and declined work, which on this project means pricing thinking and a
36
+ * competitor teardown; a markdown file in a repo and an indexed, notification-generating
37
+ * issue are not the same exposure even when both are technically public.
38
+ */
39
+ export const DEFAULT_STATUSES = ['backlog', 'in-progress', 'done'];
40
+ /** `owner/name`, each half on a conservative charset. */
41
+ const REPO_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*\/[A-Za-z0-9][A-Za-z0-9._-]*$/;
42
+ /** Three slash-separated parts — `gh`'s `[HOST/]OWNER/REPO`, which v1 does not support. */
43
+ const GHE_REPO_RE = /^[^/]+\/[^/]+\/[^/]+$/;
44
+ /** Absolute path of a checkout's config file. */
45
+ function configPath(root) {
46
+ return join(root, '.aidlc', 'config.yaml');
47
+ }
48
+ /** The whole config document, or `{}` when absent or unusable. */
49
+ function readDocument(root) {
50
+ const path = configPath(root);
51
+ if (!existsSync(path))
52
+ return {};
53
+ try {
54
+ const parsed = parseYaml(readFileSync(path, 'utf8'));
55
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
56
+ return {};
57
+ return parsed;
58
+ }
59
+ catch {
60
+ return {};
61
+ }
62
+ }
63
+ /** Describe a value's type for an error message, without printing a whole object. */
64
+ function describe(value) {
65
+ if (value === null)
66
+ return 'null';
67
+ if (Array.isArray(value))
68
+ return 'a list';
69
+ if (typeof value === 'object')
70
+ return 'a mapping';
71
+ return JSON.stringify(value);
72
+ }
73
+ /**
74
+ * Validate a repository coordinate. Shared by the config value and `--repo`, so the two
75
+ * can never diverge.
76
+ */
77
+ export function validateRepo(raw, source) {
78
+ if (typeof raw !== 'string' || raw.length === 0) {
79
+ return { ok: false, error: `${source} must be a string of the form owner/name, got ${describe(raw)}` };
80
+ }
81
+ if (REPO_RE.test(raw))
82
+ return { ok: true, repo: raw };
83
+ if (GHE_REPO_RE.test(raw)) {
84
+ return {
85
+ ok: false,
86
+ error: `${source} ${JSON.stringify(raw)} looks like gh's HOST/OWNER/REPO form. ` +
87
+ 'GitHub Enterprise is not supported in this version — use owner/name against github.com.',
88
+ };
89
+ }
90
+ return {
91
+ ok: false,
92
+ error: `${source} ${JSON.stringify(raw)} is not of the form owner/name ` +
93
+ '(each half must start with a letter or digit and contain only letters, digits, dot, dash, underscore)',
94
+ };
95
+ }
96
+ /**
97
+ * Validate the discovery label.
98
+ *
99
+ * A comma is refused explicitly rather than folded into a charset message, because the
100
+ * failure it causes is silent and expensive: `gh`'s `--label` is a comma-split slice, so
101
+ * `aidlc,urgent` would AND two labels in discovery, return an empty issue map, and
102
+ * re-create every issue on every run. The discovery label *is* the identity of a
103
+ * projected issue, so a wrong one is a duplicate-issue generator, not a cosmetic error.
104
+ */
105
+ export function validateLabel(raw) {
106
+ if (typeof raw !== 'string') {
107
+ return { ok: false, error: `roadmap.sync.label must be a string, got ${describe(raw)}` };
108
+ }
109
+ if (raw.length === 0) {
110
+ return { ok: false, error: 'roadmap.sync.label must not be empty' };
111
+ }
112
+ if (raw.includes(',')) {
113
+ return {
114
+ ok: false,
115
+ error: `roadmap.sync.label ${JSON.stringify(raw)} contains a comma. gh splits --label on ` +
116
+ 'commas, so this would search for several labels at once, find nothing, and re-create ' +
117
+ 'every issue on every run.',
118
+ };
119
+ }
120
+ if (/\s/.test(raw)) {
121
+ return { ok: false, error: `roadmap.sync.label ${JSON.stringify(raw)} contains whitespace` };
122
+ }
123
+ if (raw.length > MAX_LABEL_LENGTH) {
124
+ return {
125
+ ok: false,
126
+ error: `roadmap.sync.label is ${raw.length} characters; the maximum is ${MAX_LABEL_LENGTH}`,
127
+ };
128
+ }
129
+ return { ok: true, label: raw };
130
+ }
131
+ /** Validate the eligible-status list. */
132
+ function validateStatuses(raw) {
133
+ if (!Array.isArray(raw)) {
134
+ return {
135
+ ok: false,
136
+ error: `roadmap.sync.statuses must be a list, got ${describe(raw)} (valid names: ${ROADMAP_STATUSES.join(', ')})`,
137
+ };
138
+ }
139
+ const statuses = [];
140
+ for (const entry of raw) {
141
+ if (typeof entry !== 'string' || !ROADMAP_STATUSES.includes(entry)) {
142
+ return {
143
+ ok: false,
144
+ error: `roadmap.sync.statuses contains ${describe(entry)}; valid names are ${ROADMAP_STATUSES.join(', ')}`,
145
+ };
146
+ }
147
+ if (!statuses.includes(entry))
148
+ statuses.push(entry);
149
+ }
150
+ if (!statuses.includes('done')) {
151
+ return {
152
+ ok: false,
153
+ error: 'roadmap.sync.statuses must include `done`. Without it the close path never runs, so ' +
154
+ 'issues for finished work stay open forever and the projection never converges.',
155
+ };
156
+ }
157
+ return { ok: true, statuses };
158
+ }
159
+ /**
160
+ * Read and validate the `roadmap.sync` section from a checkout's config.
161
+ *
162
+ * @param primaryCheckoutRoot - The primary checkout's working tree.
163
+ */
164
+ export function readSyncConfig(primaryCheckoutRoot) {
165
+ const doc = readDocument(primaryCheckoutRoot);
166
+ const roadmap = doc.roadmap;
167
+ if (roadmap === undefined)
168
+ return { kind: 'not-configured' };
169
+ if (typeof roadmap !== 'object' || roadmap === null || Array.isArray(roadmap)) {
170
+ return { kind: 'not-configured' };
171
+ }
172
+ const sync = roadmap.sync;
173
+ if (sync === undefined)
174
+ return { kind: 'not-configured' };
175
+ if (typeof sync !== 'object' || sync === null || Array.isArray(sync)) {
176
+ return { kind: 'not-configured' };
177
+ }
178
+ const s = sync;
179
+ if (s.provider === undefined) {
180
+ return { kind: 'invalid', error: 'roadmap.sync.provider is required; the only supported value is `github`' };
181
+ }
182
+ if (s.provider !== 'github') {
183
+ return {
184
+ kind: 'invalid',
185
+ error: `roadmap.sync.provider ${describe(s.provider)} is not supported; the only supported value is \`github\``,
186
+ };
187
+ }
188
+ let repo = null;
189
+ if (s.repo !== undefined && s.repo !== null) {
190
+ const checked = validateRepo(s.repo, 'roadmap.sync.repo');
191
+ if (!checked.ok)
192
+ return { kind: 'invalid', error: checked.error };
193
+ repo = checked.repo;
194
+ }
195
+ let statuses = DEFAULT_STATUSES;
196
+ if (s.statuses !== undefined) {
197
+ const checked = validateStatuses(s.statuses);
198
+ if (!checked.ok)
199
+ return { kind: 'invalid', error: checked.error };
200
+ statuses = checked.statuses;
201
+ }
202
+ let label = DEFAULT_DISCOVERY_LABEL;
203
+ if (s.label !== undefined) {
204
+ const checked = validateLabel(s.label);
205
+ if (!checked.ok)
206
+ return { kind: 'invalid', error: checked.error };
207
+ label = checked.label;
208
+ }
209
+ return { kind: 'ok', config: { provider: 'github', repo, statuses, label } };
210
+ }
211
+ /**
212
+ * Apply a `--repo` flag over a config, with identical validation.
213
+ *
214
+ * The flag wins. It is the likelier source of a wrong value — typed by hand, once —
215
+ * which is why it goes through the same validator rather than a looser one.
216
+ */
217
+ export function withRepoOverride(config, repo) {
218
+ if (repo === undefined)
219
+ return { kind: 'ok', config };
220
+ const checked = validateRepo(repo, '--repo');
221
+ if (!checked.ok)
222
+ return { kind: 'invalid', error: checked.error };
223
+ return { kind: 'ok', config: { ...config, repo: checked.repo } };
224
+ }
225
+ /** The message for a project that has not opted in. */
226
+ export function notConfiguredMessage() {
227
+ return ('roadmap projection is not configured. Add a `roadmap.sync` section to ' +
228
+ '.aidlc/config.yaml:\n\n' +
229
+ ' roadmap:\n' +
230
+ ' sync:\n' +
231
+ ' provider: github\n' +
232
+ ` statuses: [${DEFAULT_STATUSES.join(', ')}]\n\n` +
233
+ `By default ${DEFAULT_STATUSES.join(', ')} are projected; inbox and hold are not, ` +
234
+ 'because an untriaged idea and a parked one are not decisions anybody has published.');
235
+ }
236
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/roadmap/sync/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,EAAE,gBAAgB,EAAsB,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAgBxE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA6B,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;AAE7F,yDAAyD;AACzD,MAAM,OAAO,GAAG,0DAA0D,CAAC;AAE3E,2FAA2F;AAC3F,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAE5C,iDAAiD;AACjD,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;AAC7C,CAAC;AAED,kEAAkE;AAClE,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QACrD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QACtF,OAAO,MAAiC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,qFAAqF;AACrF,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,WAAW,CAAC;IAClD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,GAAY,EAAE,MAAc;IACvD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,iDAAiD,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;IACzG,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IACtD,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EACH,GAAG,MAAM,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,yCAAyC;gBACzE,yFAAyF;SAC5F,CAAC;IACJ,CAAC;IACD,OAAO;QACL,EAAE,EAAE,KAAK;QACT,KAAK,EACH,GAAG,MAAM,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,iCAAiC;YACjE,uGAAuG;KAC1G,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,GAAY;IACxC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,4CAA4C,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;IAC3F,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,sCAAsC,EAAE,CAAC;IACtE,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EACH,sBAAsB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,0CAA0C;gBACnF,uFAAuF;gBACvF,2BAA2B;SAC9B,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACnB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC;IAC/F,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;QAClC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,yBAAyB,GAAG,CAAC,MAAM,+BAA+B,gBAAgB,EAAE;SAC5F,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AAClC,CAAC;AAED,yCAAyC;AACzC,SAAS,gBAAgB,CAAC,GAAY;IACpC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,6CAA6C,QAAQ,CAAC,GAAG,CAAC,kBAAkB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;SAClH,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAE,gBAAsC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1F,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,kCAAkC,QAAQ,CAAC,KAAK,CAAC,qBAAqB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;aAC3G,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAsB,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,KAAsB,CAAC,CAAC;IACxF,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EACH,sFAAsF;gBACtF,gFAAgF;SACnF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,mBAA2B;IACxD,MAAM,GAAG,GAAG,YAAY,CAAC,mBAAmB,CAAC,CAAC;IAE9C,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;IAC5B,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;IAC7D,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9E,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;IACpC,CAAC;IAED,MAAM,IAAI,GAAI,OAAmC,CAAC,IAAI,CAAC;IACvD,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;IAC1D,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;IACpC,CAAC;IAED,MAAM,CAAC,GAAG,IAA+B,CAAC;IAE1C,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,yEAAyE,EAAE,CAAC;IAC/G,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO;YACL,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,yBAAyB,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,2DAA2D;SAChH,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,GAAkB,IAAI,CAAC;IAC/B,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;QAC1D,IAAI,CAAC,OAAO,CAAC,EAAE;YAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;QAClE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IACtB,CAAC;IAED,IAAI,QAAQ,GAA6B,gBAAgB,CAAC;IAC1D,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO,CAAC,EAAE;YAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;QAClE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAC9B,CAAC;IAED,IAAI,KAAK,GAAG,uBAAuB,CAAC;IACpC,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO,CAAC,EAAE;YAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;QAClE,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IACxB,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC;AAC/E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAkB,EAAE,IAAwB;IAC3E,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACtD,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC7C,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;IAClE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;AACnE,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,oBAAoB;IAClC,OAAO,CACL,wEAAwE;QACxE,yBAAyB;QACzB,cAAc;QACd,aAAa;QACb,0BAA0B;QAC1B,oBAAoB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO;QACtD,cAAc,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,0CAA0C;QACnF,qFAAqF,CACtF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Build the id → issue map the planner reconciles against.
3
+ *
4
+ * One `gh issue list` invocation over the discovery label. Three details are load-bearing
5
+ * and all three were wrong in the first draft:
6
+ *
7
+ * - **`--limit` must be explicit.** `gh issue list` defaults to 30 results. A single call
8
+ * without a limit therefore returns at most 30 issues on a repo that has more, and every
9
+ * item missing from the map plans a `create` — producing exactly the duplicate issues the
10
+ * whole design exists to prevent, on every run, undetectably.
11
+ * - **Truncation must be a refusal, not a shrug.** A response of N issues is otherwise
12
+ * indistinguishable from "N is all there are". So the requested limit travels with the
13
+ * result and `count === limit` refuses before anything can plan a create.
14
+ * - **`labels` are objects.** `gh issue list --json labels` returns
15
+ * `{id,name,description,color}`, not strings. Treating them as strings makes every
16
+ * comparison against `aidlc:<status>` fail, so every item plans `update-labels` on every
17
+ * run and the projection never converges. They are flattened to names here, at the
18
+ * boundary, once.
19
+ *
20
+ * Requirements: roadmap-issue-projection/AC-11, roadmap-issue-projection/AC-12,
21
+ * roadmap-issue-projection/AC-13
22
+ *
23
+ * @module
24
+ */
25
+ import { type GhRunner } from './gh.js';
26
+ import type { RemoteIssue } from './types.js';
27
+ /**
28
+ * How many issues one map may hold.
29
+ *
30
+ * `gh` pages internally up to `--limit`, so this is one paginated sequence rather than a
31
+ * cap on a single page. A repo that reaches it gets a named refusal; that is a better
32
+ * outcome than a partial map, and better than reimplementing cursors against an interface
33
+ * (`gh issue list`) that exposes none.
34
+ */
35
+ export declare const ISSUE_LIST_LIMIT = 1000;
36
+ export type DiscoverResult = {
37
+ kind: 'ok';
38
+ issues: readonly RemoteIssue[];
39
+ } | {
40
+ kind: 'truncated';
41
+ count: number;
42
+ limit: number;
43
+ } | {
44
+ kind: 'failed';
45
+ error: string;
46
+ };
47
+ export interface DiscoverOpts {
48
+ repo: string | null;
49
+ label: string;
50
+ limit?: number;
51
+ }
52
+ /** Read every labelled issue, open and closed. */
53
+ export declare function buildIssueMap(gh: GhRunner, opts: DiscoverOpts): DiscoverResult;
54
+ /** The message for a truncated map. */
55
+ export declare function truncatedMessage(count: number, limit: number): string;
56
+ //# sourceMappingURL=discover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../../src/roadmap/sync/discover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAuB,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAErC,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,kDAAkD;AAClD,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,cAAc,CAoD9E;AAmCD,uCAAuC;AACvC,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMrE"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Build the id → issue map the planner reconciles against.
3
+ *
4
+ * One `gh issue list` invocation over the discovery label. Three details are load-bearing
5
+ * and all three were wrong in the first draft:
6
+ *
7
+ * - **`--limit` must be explicit.** `gh issue list` defaults to 30 results. A single call
8
+ * without a limit therefore returns at most 30 issues on a repo that has more, and every
9
+ * item missing from the map plans a `create` — producing exactly the duplicate issues the
10
+ * whole design exists to prevent, on every run, undetectably.
11
+ * - **Truncation must be a refusal, not a shrug.** A response of N issues is otherwise
12
+ * indistinguishable from "N is all there are". So the requested limit travels with the
13
+ * result and `count === limit` refuses before anything can plan a create.
14
+ * - **`labels` are objects.** `gh issue list --json labels` returns
15
+ * `{id,name,description,color}`, not strings. Treating them as strings makes every
16
+ * comparison against `aidlc:<status>` fail, so every item plans `update-labels` on every
17
+ * run and the projection never converges. They are flattened to names here, at the
18
+ * boundary, once.
19
+ *
20
+ * Requirements: roadmap-issue-projection/AC-11, roadmap-issue-projection/AC-12,
21
+ * roadmap-issue-projection/AC-13
22
+ *
23
+ * @module
24
+ */
25
+ import { firstLine, repoArgs } from './gh.js';
26
+ /**
27
+ * How many issues one map may hold.
28
+ *
29
+ * `gh` pages internally up to `--limit`, so this is one paginated sequence rather than a
30
+ * cap on a single page. A repo that reaches it gets a named refusal; that is a better
31
+ * outcome than a partial map, and better than reimplementing cursors against an interface
32
+ * (`gh issue list`) that exposes none.
33
+ */
34
+ export const ISSUE_LIST_LIMIT = 1000;
35
+ /** Read every labelled issue, open and closed. */
36
+ export function buildIssueMap(gh, opts) {
37
+ const limit = opts.limit ?? ISSUE_LIST_LIMIT;
38
+ const result = gh.run([
39
+ 'issue',
40
+ 'list',
41
+ ...repoArgs(opts.repo),
42
+ '--label',
43
+ opts.label,
44
+ '--state',
45
+ 'all',
46
+ '--limit',
47
+ String(limit),
48
+ '--json',
49
+ 'number,title,state,labels,body',
50
+ ]);
51
+ if (!result.ok) {
52
+ return { kind: 'failed', error: firstLine(result.error) };
53
+ }
54
+ let parsed;
55
+ try {
56
+ parsed = JSON.parse(result.stdout);
57
+ }
58
+ catch (err) {
59
+ return { kind: 'failed', error: `gh returned output that is not JSON: ${err.message}` };
60
+ }
61
+ if (!Array.isArray(parsed)) {
62
+ return { kind: 'failed', error: `gh returned ${typeof parsed} where a list of issues was expected` };
63
+ }
64
+ const issues = [];
65
+ for (const raw of parsed) {
66
+ const issue = toRemoteIssue(raw);
67
+ if (issue === null) {
68
+ return {
69
+ kind: 'failed',
70
+ error: 'gh returned an issue this version does not understand — expected number, title, ' +
71
+ `state, labels[].name and body, got keys ${describeKeys(raw)}`,
72
+ };
73
+ }
74
+ issues.push(issue);
75
+ }
76
+ // Deliberately after parsing, so a truncated response is still shape-checked: a limit
77
+ // hit alongside a shape change should report the shape change too on the next run.
78
+ if (issues.length === limit) {
79
+ return { kind: 'truncated', count: issues.length, limit };
80
+ }
81
+ return { kind: 'ok', issues };
82
+ }
83
+ /**
84
+ * Narrow one `gh` issue object, or null when the shape is not what this version expects.
85
+ *
86
+ * Refusing beats coercing. A `title` read as `undefined` would compare unequal to every
87
+ * item title and plan an `update-title` for the whole roadmap.
88
+ */
89
+ function toRemoteIssue(raw) {
90
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
91
+ return null;
92
+ const r = raw;
93
+ if (typeof r.number !== 'number')
94
+ return null;
95
+ if (typeof r.title !== 'string')
96
+ return null;
97
+ if (typeof r.body !== 'string')
98
+ return null;
99
+ if (r.state !== 'OPEN' && r.state !== 'CLOSED')
100
+ return null;
101
+ if (!Array.isArray(r.labels))
102
+ return null;
103
+ const labels = [];
104
+ for (const entry of r.labels) {
105
+ if (typeof entry !== 'object' || entry === null)
106
+ return null;
107
+ const name = entry.name;
108
+ if (typeof name !== 'string')
109
+ return null;
110
+ labels.push(name);
111
+ }
112
+ return { number: r.number, title: r.title, state: r.state, labels, body: r.body };
113
+ }
114
+ /** Key list of an unexpected payload, for the shape-failure message. */
115
+ function describeKeys(raw) {
116
+ if (typeof raw !== 'object' || raw === null)
117
+ return typeof raw;
118
+ return Object.keys(raw).sort().join(', ') || '(none)';
119
+ }
120
+ /** The message for a truncated map. */
121
+ export function truncatedMessage(count, limit) {
122
+ return (`the issue map may be incomplete: gh returned ${count} issues, which is the limit ` +
123
+ `requested (${limit}). Refusing rather than planning creates for issues that may already ` +
124
+ 'exist — a partial map turns every missing issue into a duplicate.');
125
+ }
126
+ //# sourceMappingURL=discover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../../../src/roadmap/sync/discover.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Apply a plan. The only module in this feature that writes anything to GitHub.
3
+ *
4
+ * It imports no `node:fs` — deliberately, and pinned by a test. `sync` writes nothing to
5
+ * disk, and the cheapest way to keep that true is for the writing module to have no
6
+ * ability to. Snapshotting a directory around a run would be the weaker check: cost
7
+ * capture writes into `.aidlc/` during a session, so a whole-tree snapshot is either
8
+ * flaky or has to exclude so much that it stops proving anything.
9
+ *
10
+ * A `create` is **one** invocation carrying the discovery label, the status label, and the
11
+ * body marker. If the label were applied by a second call, a process death between the two
12
+ * would strand an issue invisible to discovery — which the next run would duplicate. One
13
+ * invocation makes the issue discoverable the instant it exists, and that atomicity is
14
+ * what the whole no-local-state design rests on.
15
+ *
16
+ * Execution **aborts on the first failure**. A rate limit or an authorization failure will
17
+ * fail everything after it too, so continuing would turn one legible error into forty.
18
+ *
19
+ * Requirements: roadmap-issue-projection/AC-23, roadmap-issue-projection/AC-41,
20
+ * roadmap-issue-projection/AC-42, roadmap-issue-projection/AC-43,
21
+ * roadmap-issue-projection/AC-46
22
+ *
23
+ * @module
24
+ */
25
+ import { type GhRunner } from './gh.js';
26
+ import { type Plan, type PlanLine } from './types.js';
27
+ export interface ExecReport {
28
+ applied: readonly PlanLine[];
29
+ /** Set when a write failed; everything in `notAttempted` was skipped because of it. */
30
+ failure: {
31
+ line: PlanLine;
32
+ error: string;
33
+ } | null;
34
+ notAttempted: readonly PlanLine[];
35
+ }
36
+ export declare function applyPlan(gh: GhRunner, plan: Plan, discoveryLabel: string): ExecReport;
37
+ /** The `gh` argv for one write outcome. */
38
+ export declare function invocationFor(plan: Plan, line: PlanLine, discoveryLabel: string): string[];
39
+ /** Render an execution report for stdout. */
40
+ export declare function renderExecReport(report: ExecReport): string;
41
+ //# sourceMappingURL=execute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/roadmap/sync/execute.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAuB,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE7D,OAAO,EAAW,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE/D,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC7B,uFAAuF;IACvF,OAAO,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClD,YAAY,EAAE,SAAS,QAAQ,EAAE,CAAC;CACnC;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,GAAG,UAAU,CAyBtF;AAED,2CAA2C;AAC3C,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,CA6C1F;AAyCD,6CAA6C;AAC7C,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAuB3D"}