@rasensio/aidlc 1.20.0 → 1.22.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 +206 -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/paths.d.ts +21 -0
- package/dist/roadmap/paths.d.ts.map +1 -1
- package/dist/roadmap/paths.js +17 -1
- package/dist/roadmap/paths.js.map +1 -1
- package/dist/roadmap/sync/body.d.ts +123 -0
- package/dist/roadmap/sync/body.d.ts.map +1 -0
- package/dist/roadmap/sync/body.js +289 -0
- package/dist/roadmap/sync/body.js.map +1 -0
- package/dist/roadmap/sync/collect.d.ts +54 -0
- package/dist/roadmap/sync/collect.d.ts.map +1 -0
- package/dist/roadmap/sync/collect.js +138 -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 +174 -0
- package/dist/roadmap/sync/execute.js.map +1 -0
- package/dist/roadmap/sync/gh.d.ts +74 -0
- package/dist/roadmap/sync/gh.d.ts.map +1 -0
- package/dist/roadmap/sync/gh.js +110 -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/markdown.d.ts +79 -0
- package/dist/roadmap/sync/markdown.d.ts.map +1 -0
- package/dist/roadmap/sync/markdown.js +165 -0
- package/dist/roadmap/sync/markdown.js.map +1 -0
- package/dist/roadmap/sync/marker.d.ts +47 -0
- package/dist/roadmap/sync/marker.d.ts.map +1 -0
- package/dist/roadmap/sync/marker.js +73 -0
- package/dist/roadmap/sync/marker.js.map +1 -0
- package/dist/roadmap/sync/plan.d.ts +47 -0
- package/dist/roadmap/sync/plan.d.ts.map +1 -0
- package/dist/roadmap/sync/plan.js +290 -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 +112 -0
- package/dist/roadmap/sync/render.js.map +1 -0
- package/dist/roadmap/sync/sanitize.d.ts +56 -0
- package/dist/roadmap/sync/sanitize.d.ts.map +1 -0
- package/dist/roadmap/sync/sanitize.js +140 -0
- package/dist/roadmap/sync/sanitize.js.map +1 -0
- package/dist/roadmap/sync/types.d.ts +139 -0
- package/dist/roadmap/sync/types.d.ts.map +1 -0
- package/dist/roadmap/sync/types.js +50 -0
- package/dist/roadmap/sync/types.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../../src/roadmap/sync/execute.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single subprocess boundary between this feature and the `gh` CLI.
|
|
3
|
+
*
|
|
4
|
+
* Every `gh` invocation in the projection goes through `GhRunner.run(args)`, and
|
|
5
|
+
* `args` is an array. That is structural rather than habitual on purpose: item titles
|
|
6
|
+
* and config values come from tracked files, so in a cloned repo they are the repo
|
|
7
|
+
* author's strings, not the user's. With one seam there is no call site for somebody
|
|
8
|
+
* in a hurry to add a template string or `shell: true` to, and the fake runner used in
|
|
9
|
+
* tests records every argv — which is what lets the token-secrecy property be checked
|
|
10
|
+
* by *value* (set `GH_TOKEN` to a sentinel, assert it appears in no recorded argv)
|
|
11
|
+
* rather than by grepping the source for a variable name. This project has broken
|
|
12
|
+
* prose-scoped greps six separate times.
|
|
13
|
+
*
|
|
14
|
+
* Nothing here reads `GH_TOKEN` or `GITHUB_TOKEN`. `gh` owns the credential; this
|
|
15
|
+
* module owns the argv.
|
|
16
|
+
*
|
|
17
|
+
* Requirements: roadmap-issue-projection/AC-30, roadmap-issue-projection/AC-50
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
export type GhResult = {
|
|
22
|
+
ok: true;
|
|
23
|
+
stdout: string;
|
|
24
|
+
} | {
|
|
25
|
+
ok: false;
|
|
26
|
+
error: string;
|
|
27
|
+
exitCode: number | null;
|
|
28
|
+
};
|
|
29
|
+
export interface GhRunner {
|
|
30
|
+
run(args: readonly string[]): GhResult;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 256 MiB.
|
|
34
|
+
*
|
|
35
|
+
* `execFileSync` defaults to 1 MiB, and discovery asks for every projected issue's
|
|
36
|
+
* body so the marker can be read. Measured: the default throws `ENOBUFS` at roughly
|
|
37
|
+
* 2 MiB of output, which a few hundred issues with ordinary bodies will exceed — two
|
|
38
|
+
* orders of magnitude below the 1000-issue map this feature otherwise supports. The
|
|
39
|
+
* failure is a thrown error rather than a truncated read, so it would be loud; it
|
|
40
|
+
* would also be entirely avoidable, which is why the limit is stated.
|
|
41
|
+
*/
|
|
42
|
+
export declare const GH_MAX_BUFFER: number;
|
|
43
|
+
/** The real runner. Argument array, no shell, explicit buffer. */
|
|
44
|
+
export declare function realGhRunner(): GhRunner;
|
|
45
|
+
/**
|
|
46
|
+
* Check that `gh` is present and authenticated.
|
|
47
|
+
*
|
|
48
|
+
* **Authentication only.** `gh auth status` cannot tell whether the token may write
|
|
49
|
+
* issues on the target repository, so a token that is authenticated but not authorized
|
|
50
|
+
* passes here and fails on the first write — where `applyPlan` names the item and
|
|
51
|
+
* prints `gh`'s own message. Claiming otherwise would put the check in the wrong
|
|
52
|
+
* place and make the first-run failure less legible, not more.
|
|
53
|
+
*/
|
|
54
|
+
export declare function ghPreflight(gh: GhRunner): {
|
|
55
|
+
ok: true;
|
|
56
|
+
} | {
|
|
57
|
+
ok: false;
|
|
58
|
+
error: string;
|
|
59
|
+
};
|
|
60
|
+
/** First non-empty line of a `gh` message, for one-line error reporting. */
|
|
61
|
+
export declare function firstLine(text: string): string;
|
|
62
|
+
/** `['--repo', repo]` when a coordinate was resolved, else `[]`. */
|
|
63
|
+
export declare function repoArgs(repo: string | null): readonly string[];
|
|
64
|
+
/**
|
|
65
|
+
* Ask `gh` which repository the current directory belongs to.
|
|
66
|
+
*
|
|
67
|
+
* Only needed when `roadmap.sync.repo` is unset, and only so bodies can carry permalinks.
|
|
68
|
+
* A failure is **not** fatal: it yields null, and the projection continues with unlinked
|
|
69
|
+
* paths. Refusing to sync because a hyperlink could not be built would trade the feature's
|
|
70
|
+
* whole purpose for one of its conveniences, and the plan header already names the target,
|
|
71
|
+
* so a wrong repository stays visible either way.
|
|
72
|
+
*/
|
|
73
|
+
export declare function resolveNameWithOwner(gh: GhRunner): string | null;
|
|
74
|
+
//# sourceMappingURL=gh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gh.d.ts","sourceRoot":"","sources":["../../../src/roadmap/sync/gh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,MAAM,MAAM,QAAQ,GAChB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAE1D,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,QAAQ,CAAC;CACxC;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,QAAoB,CAAC;AAE/C,kEAAkE;AAClE,wBAAgB,YAAY,IAAI,QAAQ,CAkBvC;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CASrF;AAED,4EAA4E;AAC5E,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM9C;AAED,oEAAoE;AACpE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,MAAM,EAAE,CAE/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAWhE"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single subprocess boundary between this feature and the `gh` CLI.
|
|
3
|
+
*
|
|
4
|
+
* Every `gh` invocation in the projection goes through `GhRunner.run(args)`, and
|
|
5
|
+
* `args` is an array. That is structural rather than habitual on purpose: item titles
|
|
6
|
+
* and config values come from tracked files, so in a cloned repo they are the repo
|
|
7
|
+
* author's strings, not the user's. With one seam there is no call site for somebody
|
|
8
|
+
* in a hurry to add a template string or `shell: true` to, and the fake runner used in
|
|
9
|
+
* tests records every argv — which is what lets the token-secrecy property be checked
|
|
10
|
+
* by *value* (set `GH_TOKEN` to a sentinel, assert it appears in no recorded argv)
|
|
11
|
+
* rather than by grepping the source for a variable name. This project has broken
|
|
12
|
+
* prose-scoped greps six separate times.
|
|
13
|
+
*
|
|
14
|
+
* Nothing here reads `GH_TOKEN` or `GITHUB_TOKEN`. `gh` owns the credential; this
|
|
15
|
+
* module owns the argv.
|
|
16
|
+
*
|
|
17
|
+
* Requirements: roadmap-issue-projection/AC-30, roadmap-issue-projection/AC-50
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import { execFileSync } from 'node:child_process';
|
|
22
|
+
/**
|
|
23
|
+
* 256 MiB.
|
|
24
|
+
*
|
|
25
|
+
* `execFileSync` defaults to 1 MiB, and discovery asks for every projected issue's
|
|
26
|
+
* body so the marker can be read. Measured: the default throws `ENOBUFS` at roughly
|
|
27
|
+
* 2 MiB of output, which a few hundred issues with ordinary bodies will exceed — two
|
|
28
|
+
* orders of magnitude below the 1000-issue map this feature otherwise supports. The
|
|
29
|
+
* failure is a thrown error rather than a truncated read, so it would be loud; it
|
|
30
|
+
* would also be entirely avoidable, which is why the limit is stated.
|
|
31
|
+
*/
|
|
32
|
+
export const GH_MAX_BUFFER = 256 * 1024 * 1024;
|
|
33
|
+
/** The real runner. Argument array, no shell, explicit buffer. */
|
|
34
|
+
export function realGhRunner() {
|
|
35
|
+
return {
|
|
36
|
+
run(args) {
|
|
37
|
+
try {
|
|
38
|
+
const stdout = execFileSync('gh', [...args], {
|
|
39
|
+
encoding: 'utf8',
|
|
40
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
41
|
+
maxBuffer: GH_MAX_BUFFER,
|
|
42
|
+
});
|
|
43
|
+
return { ok: true, stdout };
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
const e = err;
|
|
47
|
+
const stderr = typeof e.stderr === 'string' ? e.stderr : e.stderr?.toString('utf8');
|
|
48
|
+
const message = (stderr ?? e.message ?? 'gh invocation failed').trim();
|
|
49
|
+
return { ok: false, error: message, exitCode: e.status ?? null };
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Check that `gh` is present and authenticated.
|
|
56
|
+
*
|
|
57
|
+
* **Authentication only.** `gh auth status` cannot tell whether the token may write
|
|
58
|
+
* issues on the target repository, so a token that is authenticated but not authorized
|
|
59
|
+
* passes here and fails on the first write — where `applyPlan` names the item and
|
|
60
|
+
* prints `gh`'s own message. Claiming otherwise would put the check in the wrong
|
|
61
|
+
* place and make the first-run failure less legible, not more.
|
|
62
|
+
*/
|
|
63
|
+
export function ghPreflight(gh) {
|
|
64
|
+
const result = gh.run(['auth', 'status']);
|
|
65
|
+
if (result.ok)
|
|
66
|
+
return { ok: true };
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
error: 'gh is not available or not authenticated — install the GitHub CLI and run ' +
|
|
70
|
+
`\`gh auth login\`, then try again.\n gh said: ${firstLine(result.error)}`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** First non-empty line of a `gh` message, for one-line error reporting. */
|
|
74
|
+
export function firstLine(text) {
|
|
75
|
+
for (const line of text.split('\n')) {
|
|
76
|
+
const trimmed = line.trim();
|
|
77
|
+
if (trimmed.length > 0)
|
|
78
|
+
return trimmed;
|
|
79
|
+
}
|
|
80
|
+
return text.trim();
|
|
81
|
+
}
|
|
82
|
+
/** `['--repo', repo]` when a coordinate was resolved, else `[]`. */
|
|
83
|
+
export function repoArgs(repo) {
|
|
84
|
+
return repo === null ? [] : ['--repo', repo];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Ask `gh` which repository the current directory belongs to.
|
|
88
|
+
*
|
|
89
|
+
* Only needed when `roadmap.sync.repo` is unset, and only so bodies can carry permalinks.
|
|
90
|
+
* A failure is **not** fatal: it yields null, and the projection continues with unlinked
|
|
91
|
+
* paths. Refusing to sync because a hyperlink could not be built would trade the feature's
|
|
92
|
+
* whole purpose for one of its conveniences, and the plan header already names the target,
|
|
93
|
+
* so a wrong repository stays visible either way.
|
|
94
|
+
*/
|
|
95
|
+
export function resolveNameWithOwner(gh) {
|
|
96
|
+
const result = gh.run(['repo', 'view', '--json', 'nameWithOwner']);
|
|
97
|
+
if (!result.ok)
|
|
98
|
+
return null;
|
|
99
|
+
try {
|
|
100
|
+
const parsed = JSON.parse(result.stdout);
|
|
101
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
102
|
+
return null;
|
|
103
|
+
const value = parsed.nameWithOwner;
|
|
104
|
+
return typeof value === 'string' && value.length > 0 ? value : null;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=gh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gh.js","sourceRoot":"","sources":["../../../src/roadmap/sync/gh.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot import: a GitHub issue seeds a roadmap item.
|
|
3
|
+
*
|
|
4
|
+
* Import, not sync. Nothing reconciles afterwards, nothing is written back to the issue,
|
|
5
|
+
* and running it twice over the same issue is reported rather than duplicated.
|
|
6
|
+
*
|
|
7
|
+
* The `title` is **always** double-quoted, with no judgement call about whether this one
|
|
8
|
+
* needs it. An unquoted YAML plain scalar may not begin with a reserved indicator
|
|
9
|
+
* character, so the single most natural way to name a code defect — an identifier in
|
|
10
|
+
* backticks — does not parse; and nothing reports it, because an item that will not parse
|
|
11
|
+
* and an item that was never written look identical. Five of this project's first 49 items
|
|
12
|
+
* were lost that way for up to ten days, and GitHub issue titles are precisely the corpus
|
|
13
|
+
* that produces them.
|
|
14
|
+
*
|
|
15
|
+
* Requirements: roadmap-issue-projection/AC-51 … roadmap-issue-projection/AC-60
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import { type GhRunner } from './gh.js';
|
|
20
|
+
/** A GitHub issue, reduced to what identifies it. */
|
|
21
|
+
export interface IssueCoord {
|
|
22
|
+
host: string;
|
|
23
|
+
owner: string;
|
|
24
|
+
repo: string;
|
|
25
|
+
number: number;
|
|
26
|
+
}
|
|
27
|
+
export type ImportResult = {
|
|
28
|
+
kind: 'written';
|
|
29
|
+
path: string;
|
|
30
|
+
} | {
|
|
31
|
+
kind: 'duplicate';
|
|
32
|
+
existing: string;
|
|
33
|
+
coord: IssueCoord;
|
|
34
|
+
} | {
|
|
35
|
+
kind: 'refused';
|
|
36
|
+
error: string;
|
|
37
|
+
};
|
|
38
|
+
/** Slug used when a title yields nothing usable. */
|
|
39
|
+
export declare const FALLBACK_SLUG_PREFIX = "imported-issue";
|
|
40
|
+
/**
|
|
41
|
+
* Parse an issue reference into a comparable tuple.
|
|
42
|
+
*
|
|
43
|
+
* Normalising is the point: `https://github.com/o/r/issues/12`, the same with a trailing
|
|
44
|
+
* slash, with a `#issuecomment-…` fragment, with `www.`, and the
|
|
45
|
+
* `api.github.com/repos/o/r/issues/12` form all denote one issue. Comparing raw strings
|
|
46
|
+
* would report false duplicates in one direction and miss real ones in the other — and a
|
|
47
|
+
* naive substring compare makes `issues/1` match `issues/12`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseIssueUrl(raw: string): IssueCoord | null;
|
|
50
|
+
/** Canonical string form of a coordinate, for map keys. */
|
|
51
|
+
export declare function coordKey(coord: IssueCoord): string;
|
|
52
|
+
/**
|
|
53
|
+
* Every issue already linked by a roadmap item, keyed by coordinate.
|
|
54
|
+
*
|
|
55
|
+
* This reads item **bodies**, which the roadmap skill's frontmatter-only rule otherwise
|
|
56
|
+
* discourages. That rule governs *browse*, which is a list and must stay cheap enough to
|
|
57
|
+
* run over the whole roadmap. Import is neither a list nor cheap-by-contract, and there is
|
|
58
|
+
* nowhere else the local half of a duplicate check could come from — DD-1 means no
|
|
59
|
+
* `remote:` field exists to consult.
|
|
60
|
+
*/
|
|
61
|
+
export declare function linkedCoords(cwd: string): Map<string, string>;
|
|
62
|
+
/**
|
|
63
|
+
* A filename-safe slug from an issue title.
|
|
64
|
+
*
|
|
65
|
+
* Must satisfy `ITEM_FILENAME_RE`'s `[a-z0-9][a-z0-9-]*`, which a title of punctuation or
|
|
66
|
+
* of a non-Latin script will not survive — hence the fallback rather than a refusal. An
|
|
67
|
+
* issue that cannot be imported because of its title would be a strange thing to tell
|
|
68
|
+
* somebody.
|
|
69
|
+
*/
|
|
70
|
+
export declare function slugFromTitle(title: string, number: number): string;
|
|
71
|
+
/** Import one issue into `inbox/`. */
|
|
72
|
+
export declare function importIssue(gh: GhRunner, cwd: string, url: string): ImportResult;
|
|
73
|
+
//# sourceMappingURL=import.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../../src/roadmap/sync/import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAYH,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnD,qDAAqD;AACrD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,oDAAoD;AACpD,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AAKrD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CA2B5D;AAQD,2DAA2D;AAC3D,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAElD;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA8B7D;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAYnE;AAuBD,sCAAsC;AACtC,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CA+ChF"}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot import: a GitHub issue seeds a roadmap item.
|
|
3
|
+
*
|
|
4
|
+
* Import, not sync. Nothing reconciles afterwards, nothing is written back to the issue,
|
|
5
|
+
* and running it twice over the same issue is reported rather than duplicated.
|
|
6
|
+
*
|
|
7
|
+
* The `title` is **always** double-quoted, with no judgement call about whether this one
|
|
8
|
+
* needs it. An unquoted YAML plain scalar may not begin with a reserved indicator
|
|
9
|
+
* character, so the single most natural way to name a code defect — an identifier in
|
|
10
|
+
* backticks — does not parse; and nothing reports it, because an item that will not parse
|
|
11
|
+
* and an item that was never written look identical. Five of this project's first 49 items
|
|
12
|
+
* were lost that way for up to ten days, and GitHub issue titles are precisely the corpus
|
|
13
|
+
* that produces them.
|
|
14
|
+
*
|
|
15
|
+
* Requirements: roadmap-issue-projection/AC-51 … roadmap-issue-projection/AC-60
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
20
|
+
import { join, resolve, sep } from 'node:path';
|
|
21
|
+
import { ITEM_FILENAME_RE, ROADMAP_STATUSES, isoDate, primaryCheckout, statusDir, } from '../paths.js';
|
|
22
|
+
import { firstLine } from './gh.js';
|
|
23
|
+
/** Slug used when a title yields nothing usable. */
|
|
24
|
+
export const FALLBACK_SLUG_PREFIX = 'imported-issue';
|
|
25
|
+
/** Keeps filenames reasonable; `ITEM_FILENAME_RE` imposes no length limit itself. */
|
|
26
|
+
const MAX_SLUG_LENGTH = 48;
|
|
27
|
+
/**
|
|
28
|
+
* Parse an issue reference into a comparable tuple.
|
|
29
|
+
*
|
|
30
|
+
* Normalising is the point: `https://github.com/o/r/issues/12`, the same with a trailing
|
|
31
|
+
* slash, with a `#issuecomment-…` fragment, with `www.`, and the
|
|
32
|
+
* `api.github.com/repos/o/r/issues/12` form all denote one issue. Comparing raw strings
|
|
33
|
+
* would report false duplicates in one direction and miss real ones in the other — and a
|
|
34
|
+
* naive substring compare makes `issues/1` match `issues/12`.
|
|
35
|
+
*/
|
|
36
|
+
export function parseIssueUrl(raw) {
|
|
37
|
+
let url;
|
|
38
|
+
try {
|
|
39
|
+
url = new URL(raw.trim());
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
if (url.protocol !== 'https:' && url.protocol !== 'http:')
|
|
45
|
+
return null;
|
|
46
|
+
const host = url.hostname.replace(/^www\./, '').toLowerCase();
|
|
47
|
+
const segments = url.pathname.split('/').filter((s) => s.length > 0);
|
|
48
|
+
// api.github.com/repos/<owner>/<repo>/issues/<n>
|
|
49
|
+
if (host === 'api.github.com') {
|
|
50
|
+
if (segments.length !== 5)
|
|
51
|
+
return null;
|
|
52
|
+
if (segments[0] !== 'repos' || segments[3] !== 'issues')
|
|
53
|
+
return null;
|
|
54
|
+
const number = toIssueNumber(segments[4]);
|
|
55
|
+
if (number === null)
|
|
56
|
+
return null;
|
|
57
|
+
return { host: 'github.com', owner: segments[1], repo: segments[2], number };
|
|
58
|
+
}
|
|
59
|
+
// <host>/<owner>/<repo>/issues/<n>
|
|
60
|
+
if (segments.length !== 4)
|
|
61
|
+
return null;
|
|
62
|
+
if (segments[2] !== 'issues')
|
|
63
|
+
return null;
|
|
64
|
+
const number = toIssueNumber(segments[3]);
|
|
65
|
+
if (number === null)
|
|
66
|
+
return null;
|
|
67
|
+
return { host, owner: segments[0], repo: segments[1], number };
|
|
68
|
+
}
|
|
69
|
+
function toIssueNumber(raw) {
|
|
70
|
+
if (!/^[1-9][0-9]*$/.test(raw))
|
|
71
|
+
return null;
|
|
72
|
+
const n = Number(raw);
|
|
73
|
+
return Number.isSafeInteger(n) ? n : null;
|
|
74
|
+
}
|
|
75
|
+
/** Canonical string form of a coordinate, for map keys. */
|
|
76
|
+
export function coordKey(coord) {
|
|
77
|
+
return `${coord.host}/${coord.owner}/${coord.repo}#${coord.number}`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Every issue already linked by a roadmap item, keyed by coordinate.
|
|
81
|
+
*
|
|
82
|
+
* This reads item **bodies**, which the roadmap skill's frontmatter-only rule otherwise
|
|
83
|
+
* discourages. That rule governs *browse*, which is a list and must stay cheap enough to
|
|
84
|
+
* run over the whole roadmap. Import is neither a list nor cheap-by-contract, and there is
|
|
85
|
+
* nowhere else the local half of a duplicate check could come from — DD-1 means no
|
|
86
|
+
* `remote:` field exists to consult.
|
|
87
|
+
*/
|
|
88
|
+
export function linkedCoords(cwd) {
|
|
89
|
+
const root = primaryCheckout(cwd);
|
|
90
|
+
const found = new Map();
|
|
91
|
+
for (const status of ROADMAP_STATUSES) {
|
|
92
|
+
const dir = statusDir(root, status);
|
|
93
|
+
if (!existsSync(dir))
|
|
94
|
+
continue;
|
|
95
|
+
let names;
|
|
96
|
+
try {
|
|
97
|
+
names = readdirSync(dir).sort();
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
for (const filename of names) {
|
|
103
|
+
if (!filename.endsWith('.md'))
|
|
104
|
+
continue;
|
|
105
|
+
let raw;
|
|
106
|
+
try {
|
|
107
|
+
raw = readFileSync(join(dir, filename), 'utf8');
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
for (const match of raw.matchAll(/https?:\/\/[^\s)>\]"']+/g)) {
|
|
113
|
+
const coord = parseIssueUrl(match[0]);
|
|
114
|
+
if (coord === null)
|
|
115
|
+
continue;
|
|
116
|
+
const key = coordKey(coord);
|
|
117
|
+
if (!found.has(key))
|
|
118
|
+
found.set(key, `${status}/${filename}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return found;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* A filename-safe slug from an issue title.
|
|
126
|
+
*
|
|
127
|
+
* Must satisfy `ITEM_FILENAME_RE`'s `[a-z0-9][a-z0-9-]*`, which a title of punctuation or
|
|
128
|
+
* of a non-Latin script will not survive — hence the fallback rather than a refusal. An
|
|
129
|
+
* issue that cannot be imported because of its title would be a strange thing to tell
|
|
130
|
+
* somebody.
|
|
131
|
+
*/
|
|
132
|
+
export function slugFromTitle(title, number) {
|
|
133
|
+
const slug = title
|
|
134
|
+
.toLowerCase()
|
|
135
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
136
|
+
.replace(/^-+|-+$/g, '')
|
|
137
|
+
.slice(0, MAX_SLUG_LENGTH)
|
|
138
|
+
.replace(/-+$/g, '');
|
|
139
|
+
if (slug.length === 0 || !/^[a-z0-9]/.test(slug)) {
|
|
140
|
+
return `${FALLBACK_SLUG_PREFIX}-${number}`;
|
|
141
|
+
}
|
|
142
|
+
return slug;
|
|
143
|
+
}
|
|
144
|
+
/** Read the issue. The only `gh` call import makes, and it is a read. */
|
|
145
|
+
function readIssue(gh, url) {
|
|
146
|
+
const result = gh.run(['issue', 'view', url, '--json', 'number,title,url']);
|
|
147
|
+
if (!result.ok)
|
|
148
|
+
return { ok: false, error: firstLine(result.error) };
|
|
149
|
+
try {
|
|
150
|
+
const parsed = JSON.parse(result.stdout);
|
|
151
|
+
if (typeof parsed.number !== 'number' || typeof parsed.title !== 'string' || typeof parsed.url !== 'string') {
|
|
152
|
+
return { ok: false, error: 'gh returned an issue without number, title and url' };
|
|
153
|
+
}
|
|
154
|
+
return { ok: true, issue: { number: parsed.number, title: parsed.title, url: parsed.url } };
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
return { ok: false, error: `gh returned output that is not JSON: ${err.message}` };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/** Import one issue into `inbox/`. */
|
|
161
|
+
export function importIssue(gh, cwd, url) {
|
|
162
|
+
const coord = parseIssueUrl(url);
|
|
163
|
+
if (coord === null) {
|
|
164
|
+
return {
|
|
165
|
+
kind: 'refused',
|
|
166
|
+
error: `${JSON.stringify(url)} is not a GitHub issue URL. Expected ` +
|
|
167
|
+
'https://github.com/<owner>/<repo>/issues/<number>.',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const linked = linkedCoords(cwd);
|
|
171
|
+
const existing = linked.get(coordKey(coord));
|
|
172
|
+
if (existing !== undefined) {
|
|
173
|
+
return { kind: 'duplicate', existing, coord };
|
|
174
|
+
}
|
|
175
|
+
const read = readIssue(gh, url);
|
|
176
|
+
if (!read.ok)
|
|
177
|
+
return { kind: 'refused', error: read.error };
|
|
178
|
+
const root = primaryCheckout(cwd);
|
|
179
|
+
const inbox = statusDir(root, 'inbox');
|
|
180
|
+
const date = isoDate();
|
|
181
|
+
const compact = date.replace(/-/g, '');
|
|
182
|
+
const slug = slugFromTitle(read.issue.title, coord.number);
|
|
183
|
+
const filename = uniqueFilename(root, compact, slug);
|
|
184
|
+
if (filename === null) {
|
|
185
|
+
return {
|
|
186
|
+
kind: 'refused',
|
|
187
|
+
error: `could not find a free filename for ${compact}-${slug}.md after 50 attempts`,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
const target = resolve(inbox, filename);
|
|
191
|
+
// Second boundary. The slug is already constrained, but a containment check immediately
|
|
192
|
+
// before the write is what stops a slug bug from becoming a path traversal — the
|
|
193
|
+
// secure-defaults rule about validating at more than one boundary.
|
|
194
|
+
if (!target.startsWith(inbox + sep)) {
|
|
195
|
+
return { kind: 'refused', error: `refusing to write outside ${inbox}` };
|
|
196
|
+
}
|
|
197
|
+
if (!ITEM_FILENAME_RE.test(filename)) {
|
|
198
|
+
return { kind: 'refused', error: `derived filename ${filename} is not a valid roadmap item name` };
|
|
199
|
+
}
|
|
200
|
+
writeFileSync(target, renderItem(read.issue, coord, compact, slug, date), 'utf8');
|
|
201
|
+
return { kind: 'written', path: target };
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* A filename free in **every** status directory.
|
|
205
|
+
*
|
|
206
|
+
* Not just `inbox/`: a filename appearing in two status directories is an error the
|
|
207
|
+
* roadmap module reports rather than resolves, so creating one would be manufacturing it.
|
|
208
|
+
* The `-2` suffix follows the rule the roadmap skill already states.
|
|
209
|
+
*/
|
|
210
|
+
function uniqueFilename(root, compact, slug) {
|
|
211
|
+
for (let attempt = 1; attempt <= 50; attempt++) {
|
|
212
|
+
const candidate = attempt === 1 ? `${compact}-${slug}.md` : `${compact}-${slug}-${attempt}.md`;
|
|
213
|
+
const taken = ROADMAP_STATUSES.some((status) => existsSync(join(statusDir(root, status), candidate)));
|
|
214
|
+
if (!taken)
|
|
215
|
+
return candidate;
|
|
216
|
+
}
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* The item file.
|
|
221
|
+
*
|
|
222
|
+
* The Executive Summary is written with every label reading `Not yet decided.` rather than
|
|
223
|
+
* inferred from the issue body. The roadmap skill requires the section of every item and
|
|
224
|
+
* warns that a summary drafted before the detail "is a guess wearing a summary's clothes";
|
|
225
|
+
* filling six labels from an issue nobody has triaged would be exactly that. Triage is
|
|
226
|
+
* where they get answered.
|
|
227
|
+
*/
|
|
228
|
+
function renderItem(issue, coord, compact, slug, date) {
|
|
229
|
+
const id = `item-${compact}-${slug}`;
|
|
230
|
+
return [
|
|
231
|
+
'---',
|
|
232
|
+
`id: ${id}`,
|
|
233
|
+
// JSON.stringify, unconditionally. See the module docblock.
|
|
234
|
+
`title: ${JSON.stringify(issue.title)}`,
|
|
235
|
+
`created_at: ${date}`,
|
|
236
|
+
'source: import',
|
|
237
|
+
'promoted_to: null',
|
|
238
|
+
'depends_on: []',
|
|
239
|
+
'history:',
|
|
240
|
+
` - { status: inbox, at: ${date} }`,
|
|
241
|
+
'---',
|
|
242
|
+
'',
|
|
243
|
+
`# Idea: ${issue.title}`,
|
|
244
|
+
'',
|
|
245
|
+
'## Executive Summary',
|
|
246
|
+
'',
|
|
247
|
+
'- **What it is** — Not yet decided.',
|
|
248
|
+
'- **Who benefits** — Not yet decided.',
|
|
249
|
+
'- **Customer value** — Not yet decided.',
|
|
250
|
+
'- **Revenue** — Not yet decided.',
|
|
251
|
+
'- **Cost and risk** — Not yet decided.',
|
|
252
|
+
'- **Recommendation** — Not yet decided.',
|
|
253
|
+
'',
|
|
254
|
+
`Imported from ${issue.url} on ${date}. The summary above is deliberately unfilled:`,
|
|
255
|
+
'six labelled lines guessed from an untriaged issue would read as answered without',
|
|
256
|
+
'being decided. Fill them in at triage.',
|
|
257
|
+
'',
|
|
258
|
+
'## Source',
|
|
259
|
+
'',
|
|
260
|
+
`- **Issue:** ${issue.url}`,
|
|
261
|
+
`- **Repository:** ${coord.owner}/${coord.repo}`,
|
|
262
|
+
`- **Number:** #${coord.number}`,
|
|
263
|
+
'',
|
|
264
|
+
'This item is a one-shot import. Nothing reconciles it with the issue afterwards, and',
|
|
265
|
+
'comments on the issue are not copied here.',
|
|
266
|
+
'',
|
|
267
|
+
].join('\n');
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import.js","sourceRoot":"","sources":["../../../src/roadmap/sync/import.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The label vocabulary the projection uses.
|
|
3
|
+
*
|
|
4
|
+
* Two kinds of label, doing two different jobs:
|
|
5
|
+
*
|
|
6
|
+
* - **The discovery label** (`aidlc` by default) is how the whole issue map is found in
|
|
7
|
+
* one `gh issue list` call. It is identity: an issue without it is invisible to the
|
|
8
|
+
* projection.
|
|
9
|
+
* - **A status label** (`aidlc:backlog`, `aidlc:done`, …) is how a reader tells planned
|
|
10
|
+
* from in-flight without opening anything.
|
|
11
|
+
*
|
|
12
|
+
* The status names are *derived* from `ROADMAP_STATUSES` rather than listed here, so the
|
|
13
|
+
* two vocabularies cannot drift: adding a sixth status becomes a compile-time fact
|
|
14
|
+
* instead of a label nobody remembered to add.
|
|
15
|
+
*
|
|
16
|
+
* `LABEL_COLOR` and `LABEL_DESCRIPTION` exist because `gh label create` exits 1 on a
|
|
17
|
+
* label that already exists, so creation must pass `--force` — and `gh` chooses a
|
|
18
|
+
* *random* colour when none is given, so `--force` without an explicit colour would
|
|
19
|
+
* repaint the label on every single run. Fixed values make the ensure genuinely
|
|
20
|
+
* idempotent.
|
|
21
|
+
*
|
|
22
|
+
* Requirements: roadmap-issue-projection/AC-17, roadmap-issue-projection/AC-43
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
25
|
+
*/
|
|
26
|
+
import { type RoadmapStatus } from '../paths.js';
|
|
27
|
+
/** Default discovery label. Overridable via `roadmap.sync.label`. */
|
|
28
|
+
export declare const DEFAULT_DISCOVERY_LABEL = "aidlc";
|
|
29
|
+
/** GitHub's own label-name limit. */
|
|
30
|
+
export declare const MAX_LABEL_LENGTH = 50;
|
|
31
|
+
/** Prefix marking a label this projection owns. */
|
|
32
|
+
export declare const STATUS_LABEL_PREFIX = "aidlc:";
|
|
33
|
+
/** The label carrying an item's status. */
|
|
34
|
+
export declare function statusLabel(status: RoadmapStatus): string;
|
|
35
|
+
/** Every status label, derived. */
|
|
36
|
+
export declare const ALL_STATUS_LABELS: readonly string[];
|
|
37
|
+
/**
|
|
38
|
+
* True when a label name is one this projection owns.
|
|
39
|
+
*
|
|
40
|
+
* Used to decide what `update-labels` may remove. Anything failing this test is a
|
|
41
|
+
* human's label and is never touched — which is why the update uses `--add-label` /
|
|
42
|
+
* `--remove-label` rather than a wholesale `--label` replacement.
|
|
43
|
+
*/
|
|
44
|
+
export declare function isStatusLabel(name: string): boolean;
|
|
45
|
+
/** Fixed colours, so `--force` is idempotent rather than a repaint. */
|
|
46
|
+
export declare const LABEL_COLOR: Readonly<Record<string, string>>;
|
|
47
|
+
/** Fallback colour for a custom discovery label. */
|
|
48
|
+
export declare const FALLBACK_LABEL_COLOR = "5319e7";
|
|
49
|
+
/** Fixed descriptions, for the same reason as the colours. */
|
|
50
|
+
export declare const LABEL_DESCRIPTION: Readonly<Record<string, string>>;
|
|
51
|
+
/** Fallback description for the discovery label, whatever it is named. */
|
|
52
|
+
export declare function discoveryLabelDescription(): string;
|
|
53
|
+
/** Colour for a label name, falling back for a custom discovery label. */
|
|
54
|
+
export declare function colorFor(name: string): string;
|
|
55
|
+
/** Description for a label name, falling back for a custom discovery label. */
|
|
56
|
+
export declare function descriptionFor(name: string): string;
|
|
57
|
+
//# sourceMappingURL=labels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../../src/roadmap/sync/labels.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEnE,qEAAqE;AACrE,eAAO,MAAM,uBAAuB,UAAU,CAAC;AAE/C,qCAAqC;AACrC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,mDAAmD;AACnD,eAAO,MAAM,mBAAmB,WAAW,CAAC;AAE5C,2CAA2C;AAC3C,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAEzD;AAED,mCAAmC;AACnC,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAAsC,CAAC;AAEtF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,uEAAuE;AACvE,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOxD,CAAC;AAEF,oDAAoD;AACpD,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAE7C,8DAA8D;AAC9D,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAM9D,CAAC;AAEF,0EAA0E;AAC1E,wBAAgB,yBAAyB,IAAI,MAAM,CAElD;AAED,0EAA0E;AAC1E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|