@open-tomato/rafa 0.36.0 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/cli.js +1325 -545
- package/dist/effort/store/index.js +1 -1
- package/dist/{index-qvbeqrx3.js → index-1mxv55ec.js} +174 -40
- package/dist/{index-2n2nedrk.js → index-35ze56rz.js} +6 -3
- package/dist/{index-ddzzmcaz.js → index-b16va6he.js} +866 -237
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2236,7 +2236,7 @@ function restoreRunningCommand(previous) {
|
|
|
2236
2236
|
var running = null;
|
|
2237
2237
|
|
|
2238
2238
|
// package.json
|
|
2239
|
-
var name = "@open-tomato/rafa", version = "0.
|
|
2239
|
+
var name = "@open-tomato/rafa", version = "0.37.0";
|
|
2240
2240
|
var init_package = () => {};
|
|
2241
2241
|
|
|
2242
2242
|
// src/cli/version.ts
|
|
@@ -10361,6 +10361,64 @@ var init_claude2 = __esm(() => {
|
|
|
10361
10361
|
};
|
|
10362
10362
|
});
|
|
10363
10363
|
|
|
10364
|
+
// src/adapters/tracker/github-edit.ts
|
|
10365
|
+
function viewedEditable(payload, labelNames) {
|
|
10366
|
+
if (!isMapping(payload))
|
|
10367
|
+
return `${describeValue(payload)}, expected a mapping`;
|
|
10368
|
+
const { title: title2, body, state, author } = payload;
|
|
10369
|
+
if (typeof title2 !== "string")
|
|
10370
|
+
return `title ${describeValue(title2)}, expected a string`;
|
|
10371
|
+
if (typeof body !== "string")
|
|
10372
|
+
return `body ${describeValue(body)}, expected a string`;
|
|
10373
|
+
if (state !== "OPEN" && state !== "CLOSED")
|
|
10374
|
+
return `state ${describeValue(state)}, expected "OPEN" or "CLOSED"`;
|
|
10375
|
+
const labels = labelNames(payload["labels"]);
|
|
10376
|
+
if (labels === null)
|
|
10377
|
+
return "labels that are not a list of named labels";
|
|
10378
|
+
const login = isMapping(author) ? author["login"] : undefined;
|
|
10379
|
+
if (typeof login !== "string")
|
|
10380
|
+
return `author ${describeValue(author)}, expected a mapping holding a string login`;
|
|
10381
|
+
return { title: title2, body, open: state === "OPEN", labels, author: login };
|
|
10382
|
+
}
|
|
10383
|
+
function editProblem(change) {
|
|
10384
|
+
if (!isMapping(change))
|
|
10385
|
+
return `the change is ${describeValue(change)}, expected a mapping`;
|
|
10386
|
+
const { body, title: title2 } = change;
|
|
10387
|
+
if (body === undefined && title2 === undefined)
|
|
10388
|
+
return "the change names neither a body nor a title";
|
|
10389
|
+
if (body !== undefined && typeof body !== "string")
|
|
10390
|
+
return `body is ${describeValue(body)}, expected a string`;
|
|
10391
|
+
return title2 !== undefined && typeof title2 !== "string" ? `title is ${describeValue(title2)}, expected a string` : null;
|
|
10392
|
+
}
|
|
10393
|
+
function optionalFlag(name2, value) {
|
|
10394
|
+
return value === undefined ? [] : [name2, value];
|
|
10395
|
+
}
|
|
10396
|
+
function createGithubEditMembers(readers) {
|
|
10397
|
+
const { run, issueNumberOf, parseJson, labelNames } = readers;
|
|
10398
|
+
const editable = async (ref) => {
|
|
10399
|
+
const number = issueNumberOf(ref);
|
|
10400
|
+
const command = `gh issue view ${number}`;
|
|
10401
|
+
const stdout = await run(["issue", "view", number, ...optionalFlag("--repo", ref.repo), "--json", EDITABLE_FIELDS], command);
|
|
10402
|
+
const viewed = viewedEditable(parseJson(stdout, command), labelNames);
|
|
10403
|
+
if (typeof viewed === "string")
|
|
10404
|
+
throw new Error(`${PREFIX2}: ${command} answered ${viewed}`);
|
|
10405
|
+
return { ref, ...viewed };
|
|
10406
|
+
};
|
|
10407
|
+
const edit = async (ref, change) => {
|
|
10408
|
+
const number = issueNumberOf(ref);
|
|
10409
|
+
const problem = editProblem(change);
|
|
10410
|
+
if (problem !== null)
|
|
10411
|
+
throw new TypeError(`${PREFIX2}: refused an edit of issue #${number}: ${problem}`);
|
|
10412
|
+
const bodyFlag = change.body === undefined ? [] : ["--body-file", "-"];
|
|
10413
|
+
await run(["issue", "edit", number, ...optionalFlag("--repo", ref.repo), ...optionalFlag("--title", change.title), ...bodyFlag], `gh issue edit ${number}`, change.body);
|
|
10414
|
+
};
|
|
10415
|
+
return Object.freeze({ editable, edit });
|
|
10416
|
+
}
|
|
10417
|
+
var PREFIX2 = "github tracker", EDITABLE_FIELDS = "title,body,state,labels,author";
|
|
10418
|
+
var init_github_edit = __esm(() => {
|
|
10419
|
+
init_config_sections();
|
|
10420
|
+
});
|
|
10421
|
+
|
|
10364
10422
|
// src/adapters/tracker/issue-values.ts
|
|
10365
10423
|
var TYPE_MEMBERS, PRIORITY_MEMBERS, STATE_MEMBERS, ISSUE_TYPES, ISSUE_PRIORITIES, ISSUE_STATES;
|
|
10366
10424
|
var init_issue_values = __esm(() => {
|
|
@@ -10397,7 +10455,7 @@ var init_issue_values = __esm(() => {
|
|
|
10397
10455
|
// src/adapters/tracker/github.ts
|
|
10398
10456
|
function createGhRunner(options) {
|
|
10399
10457
|
const { cwd, command = "gh", env, timeoutMs } = options;
|
|
10400
|
-
return async (args) => {
|
|
10458
|
+
return async (args, stdin) => {
|
|
10401
10459
|
const executable = env === undefined ? command : Bun.which(command, { PATH: env.PATH ?? "", cwd });
|
|
10402
10460
|
if (executable === null) {
|
|
10403
10461
|
return { ok: false, stdout: "", stderr: notOnPath(command, cwd, env?.PATH) };
|
|
@@ -10406,7 +10464,7 @@ function createGhRunner(options) {
|
|
|
10406
10464
|
const proc = Bun.spawn([executable, ...args], {
|
|
10407
10465
|
cwd,
|
|
10408
10466
|
...env === undefined ? {} : { env: { ...env } },
|
|
10409
|
-
stdin: "ignore",
|
|
10467
|
+
stdin: stdin === undefined ? "ignore" : new TextEncoder().encode(stdin),
|
|
10410
10468
|
stdout: "pipe",
|
|
10411
10469
|
stderr: "pipe"
|
|
10412
10470
|
});
|
|
@@ -10460,7 +10518,7 @@ function isRepoName(value) {
|
|
|
10460
10518
|
function isLabelPart(value) {
|
|
10461
10519
|
return typeof value === "string" && !value.includes(",");
|
|
10462
10520
|
}
|
|
10463
|
-
function
|
|
10521
|
+
function optionalFlag2(name2, value) {
|
|
10464
10522
|
return value === undefined ? [] : [name2, value];
|
|
10465
10523
|
}
|
|
10466
10524
|
function detailOf(result) {
|
|
@@ -10484,13 +10542,13 @@ function labelsFor(draft) {
|
|
|
10484
10542
|
}
|
|
10485
10543
|
function issueNumberOfRef(ref) {
|
|
10486
10544
|
if (ref.kind !== "github") {
|
|
10487
|
-
throw new Error(`${
|
|
10545
|
+
throw new Error(`${PREFIX3}: refused a ref of kind ${describeValue(ref.kind)}; this tracker reads github refs only`);
|
|
10488
10546
|
}
|
|
10489
10547
|
if (!isIssueNumber3(ref.externalId)) {
|
|
10490
|
-
throw new Error(`${
|
|
10548
|
+
throw new Error(`${PREFIX3}: externalId ${describeValue(ref.externalId)} is not a GitHub issue number,` + " expected a positive whole number with no leading zero");
|
|
10491
10549
|
}
|
|
10492
10550
|
if (ref.repo !== undefined && !isRepoName(ref.repo)) {
|
|
10493
|
-
throw new Error(`${
|
|
10551
|
+
throw new Error(`${PREFIX3}: repo ${describeValue(ref.repo)} is not a repository, expected owner/name`);
|
|
10494
10552
|
}
|
|
10495
10553
|
return ref.externalId;
|
|
10496
10554
|
}
|
|
@@ -10498,7 +10556,7 @@ function parseJson(stdout, command) {
|
|
|
10498
10556
|
try {
|
|
10499
10557
|
return JSON.parse(stdout);
|
|
10500
10558
|
} catch (error) {
|
|
10501
|
-
throw new Error(`${
|
|
10559
|
+
throw new Error(`${PREFIX3}: ${command} wrote output that is not JSON: ${messageOf(error)}`, {
|
|
10502
10560
|
cause: error
|
|
10503
10561
|
});
|
|
10504
10562
|
}
|
|
@@ -10532,19 +10590,19 @@ function viewedIssue(stdout, number) {
|
|
|
10532
10590
|
const payload = parseJson(stdout, command);
|
|
10533
10591
|
const problem = viewProblem(payload, number);
|
|
10534
10592
|
if (problem !== null)
|
|
10535
|
-
throw new Error(`${
|
|
10593
|
+
throw new Error(`${PREFIX3}: ${command} answered ${problem}`);
|
|
10536
10594
|
const checked = payload;
|
|
10537
10595
|
return { ...checked, labels: labelNames(checked.labels) ?? [] };
|
|
10538
10596
|
}
|
|
10539
10597
|
function listedRows(stdout) {
|
|
10540
10598
|
const payload = parseJson(stdout, LIST_COMMAND);
|
|
10541
10599
|
if (!Array.isArray(payload)) {
|
|
10542
|
-
throw new Error(`${
|
|
10600
|
+
throw new Error(`${PREFIX3}: ${LIST_COMMAND} answered ${describeValue(payload)}, expected a list`);
|
|
10543
10601
|
}
|
|
10544
10602
|
return payload;
|
|
10545
10603
|
}
|
|
10546
10604
|
function rowRefusal(index, problem) {
|
|
10547
|
-
return new Error(`${
|
|
10605
|
+
return new Error(`${PREFIX3}: ${LIST_COMMAND} answered row ${index} ${problem}`);
|
|
10548
10606
|
}
|
|
10549
10607
|
function listedRow(row2, index) {
|
|
10550
10608
|
if (!isMapping(row2))
|
|
@@ -10617,15 +10675,15 @@ function readBackState(state) {
|
|
|
10617
10675
|
function stateQueryRefusal(state) {
|
|
10618
10676
|
const bucket = REST_STATES[state];
|
|
10619
10677
|
const siblings = ISSUE_STATES.filter((other) => other !== state && REST_STATES[other] === bucket);
|
|
10620
|
-
return `${
|
|
10678
|
+
return `${PREFIX3}: find cannot narrow by state ${describeValue(state)}: GitHub holds an issue open or` + ` closed, and ${state} shares ${bucket} with ${siblings.join(", ")}, so a result would include` + " those too. Search without a state, then read each issue with get.";
|
|
10621
10679
|
}
|
|
10622
10680
|
function createGithubTracker(options) {
|
|
10623
10681
|
const { gh } = options;
|
|
10624
10682
|
let knownLabels = new Set;
|
|
10625
|
-
async function run(args, command) {
|
|
10626
|
-
const result = await gh(args);
|
|
10683
|
+
async function run(args, command, stdin) {
|
|
10684
|
+
const result = await gh(args, stdin);
|
|
10627
10685
|
if (!result.ok)
|
|
10628
|
-
throw new Error(`${
|
|
10686
|
+
throw new Error(`${PREFIX3}: ${command} failed: ${detailOf(result)}`);
|
|
10629
10687
|
return result.stdout;
|
|
10630
10688
|
}
|
|
10631
10689
|
async function ensureLabels(names) {
|
|
@@ -10658,7 +10716,7 @@ function createGithubTracker(options) {
|
|
|
10658
10716
|
create: async (draft) => {
|
|
10659
10717
|
const problem = draftProblem(draft);
|
|
10660
10718
|
if (problem !== null)
|
|
10661
|
-
throw new TypeError(`${
|
|
10719
|
+
throw new TypeError(`${PREFIX3}: refused to file an invalid draft: ${problem}`);
|
|
10662
10720
|
const labels = labelsFor(draft);
|
|
10663
10721
|
await ensureLabels(labels);
|
|
10664
10722
|
const stdout = await run([
|
|
@@ -10674,20 +10732,20 @@ function createGithubTracker(options) {
|
|
|
10674
10732
|
`).at(-1) ?? "";
|
|
10675
10733
|
const number = CREATED_ISSUE_URL.exec(url)?.[1];
|
|
10676
10734
|
if (number === undefined) {
|
|
10677
|
-
throw new Error(`${
|
|
10735
|
+
throw new Error(`${PREFIX3}: gh issue create exited 0 and printed no issue URL, so the issue may exist` + ` unrecorded; it wrote ${describeValue(stdout)}`);
|
|
10678
10736
|
}
|
|
10679
10737
|
return { opt: draft.opt, kind: "github", externalId: number, url, module: draft.module };
|
|
10680
10738
|
},
|
|
10681
10739
|
get: async (ref) => {
|
|
10682
10740
|
const number = issueNumberOfRef(ref);
|
|
10683
|
-
const stdout = await run(["issue", "view", number, ...
|
|
10741
|
+
const stdout = await run(["issue", "view", number, ...optionalFlag2("--repo", ref.repo), "--json", VIEW_FIELDS], `gh issue view ${number}`);
|
|
10684
10742
|
return issueOf2(ref, viewedIssue(stdout, number));
|
|
10685
10743
|
},
|
|
10686
10744
|
find: async (query) => {
|
|
10687
10745
|
if (query.state !== undefined)
|
|
10688
10746
|
throw new Error(stateQueryRefusal(query.state));
|
|
10689
10747
|
if (query.module !== undefined && !isLabelPart(query.module)) {
|
|
10690
|
-
throw new TypeError(`${
|
|
10748
|
+
throw new TypeError(`${PREFIX3}: find refused module ${describeValue(query.module)}, expected a string holding no comma`);
|
|
10691
10749
|
}
|
|
10692
10750
|
const moduleLabel = query.module === undefined ? undefined : `${GITHUB_LABELS.modulePrefix}${query.module}`;
|
|
10693
10751
|
const typeLabel = query.type === undefined ? undefined : `${GITHUB_LABELS.typePrefix}${query.type}`;
|
|
@@ -10700,15 +10758,15 @@ function createGithubTracker(options) {
|
|
|
10700
10758
|
LIST_FIELDS,
|
|
10701
10759
|
"--limit",
|
|
10702
10760
|
String(query.limit ?? DEFAULT_FIND_LIMIT),
|
|
10703
|
-
...
|
|
10704
|
-
...
|
|
10705
|
-
...
|
|
10761
|
+
...optionalFlag2("--label", moduleLabel),
|
|
10762
|
+
...optionalFlag2("--label", typeLabel),
|
|
10763
|
+
...optionalFlag2("--search", query.text)
|
|
10706
10764
|
], LIST_COMMAND);
|
|
10707
10765
|
return listedIssues(stdout).map(refOfRow);
|
|
10708
10766
|
},
|
|
10709
10767
|
openIssues: async (type) => {
|
|
10710
10768
|
if (!isOneOf2(ISSUE_TYPES, type)) {
|
|
10711
|
-
throw new TypeError(`${
|
|
10769
|
+
throw new TypeError(`${PREFIX3}: openIssues refused type ${describeValue(type)}, expected one of: ${ISSUE_TYPES.join(", ")}`);
|
|
10712
10770
|
}
|
|
10713
10771
|
const stdout = await run([
|
|
10714
10772
|
"issue",
|
|
@@ -10727,21 +10785,21 @@ function createGithubTracker(options) {
|
|
|
10727
10785
|
comment: async (ref, body) => {
|
|
10728
10786
|
const number = issueNumberOfRef(ref);
|
|
10729
10787
|
if (typeof body !== "string") {
|
|
10730
|
-
throw new TypeError(`${
|
|
10788
|
+
throw new TypeError(`${PREFIX3}: refused a comment body ${describeValue(body)}, expected a string`);
|
|
10731
10789
|
}
|
|
10732
|
-
await run(["issue", "comment", number, ...
|
|
10790
|
+
await run(["issue", "comment", number, ...optionalFlag2("--repo", ref.repo), "--body", body], `gh issue comment ${number}`);
|
|
10733
10791
|
},
|
|
10734
10792
|
transition: async (ref, state) => {
|
|
10735
10793
|
const number = issueNumberOfRef(ref);
|
|
10736
10794
|
if (!isOneOf2(ISSUE_STATES, state)) {
|
|
10737
|
-
throw new TypeError(`${
|
|
10795
|
+
throw new TypeError(`${PREFIX3}: refused state ${describeValue(state)}, expected one of: ${ISSUE_STATES.join(", ")}`);
|
|
10738
10796
|
}
|
|
10739
10797
|
if (REST_STATES[state] === "closed") {
|
|
10740
10798
|
const path = `repos/${ref.repo ?? "{owner}/{repo}"}/issues/${number}`;
|
|
10741
10799
|
const reason = state === "cancelled" ? "not_planned" : "completed";
|
|
10742
10800
|
await run(["api", path, "-X", "PATCH", "-f", "state=closed", "-f", `state_reason=${reason}`], `gh api PATCH ${path}`);
|
|
10743
10801
|
} else {
|
|
10744
|
-
await run(["issue", "reopen", number, ...
|
|
10802
|
+
await run(["issue", "reopen", number, ...optionalFlag2("--repo", ref.repo)], `gh issue reopen ${number}`);
|
|
10745
10803
|
}
|
|
10746
10804
|
const readBack = readBackState(state);
|
|
10747
10805
|
if (readBack === state)
|
|
@@ -10749,13 +10807,15 @@ function createGithubTracker(options) {
|
|
|
10749
10807
|
return {
|
|
10750
10808
|
warning: `issue #${number} is now ${REST_STATES[state]}, but GitHub Issues without a board` + ` holds no ${state} state, so get reads it back as ${readBack}`
|
|
10751
10809
|
};
|
|
10752
|
-
}
|
|
10810
|
+
},
|
|
10811
|
+
...createGithubEditMembers({ run, issueNumberOf: issueNumberOfRef, parseJson, labelNames })
|
|
10753
10812
|
};
|
|
10754
10813
|
return Object.freeze(tracker);
|
|
10755
10814
|
}
|
|
10756
|
-
var
|
|
10815
|
+
var PREFIX3 = "github tracker", GITHUB_LABELS, VIEW_FIELDS = "number,title,body,state,stateReason,labels,url", LIST_COMMAND = "gh issue list", LIST_FIELDS = "number,url,labels", OPEN_LIST_FIELDS = "number,url,labels,title,body", OPEN_ISSUES_LIMIT = 1000, DEFAULT_FIND_LIMIT = 30, CANCELLED_REASONS, ISSUE_NUMBER, REPO_PART, CREATED_ISSUE_URL, REST_STATES, TIMED_OUT, DRAFT_CHECKS;
|
|
10757
10816
|
var init_github = __esm(() => {
|
|
10758
10817
|
init_config_sections();
|
|
10818
|
+
init_github_edit();
|
|
10759
10819
|
init_issue_values();
|
|
10760
10820
|
GITHUB_LABELS = Object.freeze({
|
|
10761
10821
|
modulePrefix: "module:",
|
|
@@ -10882,7 +10942,7 @@ function renderLocalIssue(record) {
|
|
|
10882
10942
|
};
|
|
10883
10943
|
const problem = frontmatterProblem(frontmatter) ?? (typeof draft.body === "string" ? null : `body is ${describeValue(draft.body)}, expected a string`);
|
|
10884
10944
|
if (problem !== null) {
|
|
10885
|
-
throw new TypeError(`${
|
|
10945
|
+
throw new TypeError(`${PREFIX4}: refused to write an invalid issue: ${problem}`);
|
|
10886
10946
|
}
|
|
10887
10947
|
return `---
|
|
10888
10948
|
${Bun.YAML.stringify(frontmatter, null, 2)}
|
|
@@ -10893,18 +10953,18 @@ function parseLocalIssue(contents, sourcePath) {
|
|
|
10893
10953
|
const at = sourcePath === undefined ? "" : ` at ${sourcePath}`;
|
|
10894
10954
|
const match = FRONTMATTER.exec(contents);
|
|
10895
10955
|
if (match === null) {
|
|
10896
|
-
throw new Error(`${
|
|
10956
|
+
throw new Error(`${PREFIX4}: the issue${at} has no YAML frontmatter block`);
|
|
10897
10957
|
}
|
|
10898
10958
|
const [, block2 = "", body = ""] = match;
|
|
10899
10959
|
let meta;
|
|
10900
10960
|
try {
|
|
10901
10961
|
meta = Bun.YAML.parse(block2);
|
|
10902
10962
|
} catch (error) {
|
|
10903
|
-
throw new Error(`${
|
|
10963
|
+
throw new Error(`${PREFIX4}: invalid issue${at}: ${messageOf(error)}`, { cause: error });
|
|
10904
10964
|
}
|
|
10905
10965
|
const problem = frontmatterProblem(meta);
|
|
10906
10966
|
if (problem !== null) {
|
|
10907
|
-
throw new Error(`${
|
|
10967
|
+
throw new Error(`${PREFIX4}: invalid issue${at}: ${problem}`);
|
|
10908
10968
|
}
|
|
10909
10969
|
const fields = meta;
|
|
10910
10970
|
return {
|
|
@@ -10936,7 +10996,7 @@ async function listLocalIssues(issuesDir, warn = warnThroughActiveOutput2, reade
|
|
|
10936
10996
|
try {
|
|
10937
10997
|
contents = await readFile3(path, "utf8");
|
|
10938
10998
|
} catch (error) {
|
|
10939
|
-
throw new Error(`${
|
|
10999
|
+
throw new Error(`${PREFIX4}: could not read ${path}: ${messageOf(error)}`, { cause: error });
|
|
10940
11000
|
}
|
|
10941
11001
|
return { number, path, record: parseLocalIssue(contents, path) };
|
|
10942
11002
|
}));
|
|
@@ -10965,11 +11025,11 @@ function refFor(number, opt) {
|
|
|
10965
11025
|
}
|
|
10966
11026
|
function issueNumberOfRef2(ref) {
|
|
10967
11027
|
if (ref.kind !== "local") {
|
|
10968
|
-
throw new Error(`${
|
|
11028
|
+
throw new Error(`${PREFIX4}: refused a ref of kind ${describeValue(ref.kind)}; this tracker reads local refs only`);
|
|
10969
11029
|
}
|
|
10970
11030
|
const number = typeof ref.externalId === "string" ? parseIssueNumber(ref.externalId) : null;
|
|
10971
11031
|
if (number === null) {
|
|
10972
|
-
throw new Error(`${
|
|
11032
|
+
throw new Error(`${PREFIX4}: externalId ${describeValue(ref.externalId)} is not a local issue number,` + " expected a positive whole number with no leading zero");
|
|
10973
11033
|
}
|
|
10974
11034
|
return number;
|
|
10975
11035
|
}
|
|
@@ -10984,7 +11044,7 @@ function createLocalTracker(options) {
|
|
|
10984
11044
|
try {
|
|
10985
11045
|
contents = await readFile3(path, "utf8");
|
|
10986
11046
|
} catch (cause) {
|
|
10987
|
-
throw new Error(`${
|
|
11047
|
+
throw new Error(`${PREFIX4}: no issue ${number} under ${issuesDir}`, { cause });
|
|
10988
11048
|
}
|
|
10989
11049
|
return { number, record: parseLocalIssue(contents, path) };
|
|
10990
11050
|
}
|
|
@@ -11019,7 +11079,7 @@ function createLocalTracker(options) {
|
|
|
11019
11079
|
throw error;
|
|
11020
11080
|
}
|
|
11021
11081
|
}
|
|
11022
|
-
throw new Error(`${
|
|
11082
|
+
throw new Error(`${PREFIX4}: no issue number is left under ${issuesDir}`);
|
|
11023
11083
|
},
|
|
11024
11084
|
get: async (ref) => {
|
|
11025
11085
|
const { record } = await read(ref);
|
|
@@ -11045,11 +11105,34 @@ function createLocalTracker(options) {
|
|
|
11045
11105
|
const { number, record } = await read(ref);
|
|
11046
11106
|
await rewrite(number, { ...record, state });
|
|
11047
11107
|
return {};
|
|
11108
|
+
},
|
|
11109
|
+
editable: async (ref) => {
|
|
11110
|
+
const { number, record } = await read(ref);
|
|
11111
|
+
return {
|
|
11112
|
+
ref: refFor(number, record.draft.opt),
|
|
11113
|
+
title: record.draft.title,
|
|
11114
|
+
body: record.draft.body,
|
|
11115
|
+
open: !CLOSED_STATES.has(record.state),
|
|
11116
|
+
labels: [],
|
|
11117
|
+
author: ""
|
|
11118
|
+
};
|
|
11119
|
+
},
|
|
11120
|
+
edit: async (ref, change) => {
|
|
11121
|
+
if (change.body === undefined && change.title === undefined) {
|
|
11122
|
+
throw new TypeError(`${PREFIX4}: refused an edit naming neither a body nor a title`);
|
|
11123
|
+
}
|
|
11124
|
+
const { number, record } = await read(ref);
|
|
11125
|
+
const draft = {
|
|
11126
|
+
...record.draft,
|
|
11127
|
+
...change.body === undefined ? {} : { body: change.body },
|
|
11128
|
+
...change.title === undefined ? {} : { title: change.title }
|
|
11129
|
+
};
|
|
11130
|
+
await rewrite(number, { ...record, draft });
|
|
11048
11131
|
}
|
|
11049
11132
|
};
|
|
11050
11133
|
return Object.freeze(tracker);
|
|
11051
11134
|
}
|
|
11052
|
-
var
|
|
11135
|
+
var PREFIX4 = "local tracker", FRONTMATTER, ISSUE_NUMBER2, CLOSED_STATES, ISSUE_EXTENSION = ".md", FIELD_CHECKS;
|
|
11053
11136
|
var init_local2 = __esm(() => {
|
|
11054
11137
|
init_config_sections();
|
|
11055
11138
|
init_active();
|
|
@@ -13319,7 +13402,60 @@ function requireTrustedAuthor(item, reading) {
|
|
|
13319
13402
|
return;
|
|
13320
13403
|
throw new CommandExit(TRUST_REFUSAL_EXIT, trustRefusalMessage(item, reading));
|
|
13321
13404
|
}
|
|
13322
|
-
|
|
13405
|
+
function noLogin(detail) {
|
|
13406
|
+
return { login: null, detail };
|
|
13407
|
+
}
|
|
13408
|
+
function createGhEditorLogin(options) {
|
|
13409
|
+
const { gh } = options;
|
|
13410
|
+
return async () => {
|
|
13411
|
+
const result = await gh(["api", "user"]);
|
|
13412
|
+
if (!result.ok)
|
|
13413
|
+
return noLogin(detailOf2(result, USER_COMMAND));
|
|
13414
|
+
let payload;
|
|
13415
|
+
try {
|
|
13416
|
+
payload = JSON.parse(result.stdout);
|
|
13417
|
+
} catch (error) {
|
|
13418
|
+
return noLogin(`${USER_COMMAND} wrote output that is not JSON: ${messageOf(error)}`);
|
|
13419
|
+
}
|
|
13420
|
+
if (!isMapping(payload)) {
|
|
13421
|
+
return noLogin(`${USER_COMMAND} answered ${describeValue(payload)}, expected a mapping`);
|
|
13422
|
+
}
|
|
13423
|
+
const login = payload["login"];
|
|
13424
|
+
return typeof login === "string" && isGitHubLogin(login) ? { login, detail: "" } : noLogin(`${USER_COMMAND} answered ${describeValue(login)} as its login, which is not a GitHub login`);
|
|
13425
|
+
};
|
|
13426
|
+
}
|
|
13427
|
+
async function readEditorTrust(trust, editor) {
|
|
13428
|
+
const read = await editor();
|
|
13429
|
+
if (read.login === null) {
|
|
13430
|
+
return { login: null, trusted: false, refusal: "ownership-unknown", reading: null, detail: read.detail };
|
|
13431
|
+
}
|
|
13432
|
+
const reading = await readBoardTrust(trust, read.login);
|
|
13433
|
+
return {
|
|
13434
|
+
login: read.login,
|
|
13435
|
+
trusted: reading.trusted,
|
|
13436
|
+
refusal: editorRefusalOf(reading),
|
|
13437
|
+
reading,
|
|
13438
|
+
detail: ""
|
|
13439
|
+
};
|
|
13440
|
+
}
|
|
13441
|
+
function editorRefusalOf(reading) {
|
|
13442
|
+
if (reading.trusted)
|
|
13443
|
+
return null;
|
|
13444
|
+
return reading.refusal === "lookup-failed" ? "ownership-unknown" : "ownership";
|
|
13445
|
+
}
|
|
13446
|
+
function editorRefusalMessage(item, reading) {
|
|
13447
|
+
const what = `${item.kind} #${String(item.number)}`;
|
|
13448
|
+
if (reading.reading !== null) {
|
|
13449
|
+
const because = trustRefusalClause(item.repo, reading.reading);
|
|
13450
|
+
return `${what} cannot be edited by ${reading.reading.login}, ${because}; a member must make the edit`;
|
|
13451
|
+
}
|
|
13452
|
+
if (reading.trusted) {
|
|
13453
|
+
throw new TypeError("board trust: a trusted editor has no refusal to name");
|
|
13454
|
+
}
|
|
13455
|
+
const detail = reading.detail === "" ? UNREPORTED : reading.detail;
|
|
13456
|
+
return `${what} cannot be edited: the account running the edit could not be read (${detail}); ` + "log gh in with `gh auth login` and run it again";
|
|
13457
|
+
}
|
|
13458
|
+
var REPO_PATH = "{owner}/{repo}", TRUSTED_PERMISSIONS, TRUST_REFUSAL_EXIT = 2, REMEDY, UNREPORTED = "the lookup wrote nothing", USER_COMMAND = "gh api user";
|
|
13323
13459
|
var init_trust = __esm(() => {
|
|
13324
13460
|
init_command();
|
|
13325
13461
|
init_config_sections();
|
|
@@ -16070,7 +16206,7 @@ function optionalText2(value) {
|
|
|
16070
16206
|
function requiredText2(value) {
|
|
16071
16207
|
return value === null ? { reason: "missing-field", problem: "is missing" } : optionalText2(value);
|
|
16072
16208
|
}
|
|
16073
|
-
function
|
|
16209
|
+
function optionalFlag3(value) {
|
|
16074
16210
|
return value === null || typeof value === "boolean" ? null : { reason: "unstorable-field", problem: `is ${describeValue7(value)}, not a boolean` };
|
|
16075
16211
|
}
|
|
16076
16212
|
function scopeOf2(bug) {
|
|
@@ -16163,7 +16299,7 @@ var init_triage = __esm(() => {
|
|
|
16163
16299
|
};
|
|
16164
16300
|
OUT_OF_SCOPE_BUGS = {
|
|
16165
16301
|
key: "out_of_scope_bugs",
|
|
16166
|
-
checks: [["what", requiredText2], ["artifact", optionalText2], ["security",
|
|
16302
|
+
checks: [["what", requiredText2], ["artifact", optionalText2], ["security", optionalFlag3]],
|
|
16167
16303
|
insert: `
|
|
16168
16304
|
INSERT INTO out_of_scope_bugs (
|
|
16169
16305
|
id, session_id, plan_stub, task_line,
|
|
@@ -18462,6 +18598,9 @@ function notesFileName(issue4) {
|
|
|
18462
18598
|
function notesPath(specsDir, issue4) {
|
|
18463
18599
|
return path.join(specsDir, notesFileName(issue4));
|
|
18464
18600
|
}
|
|
18601
|
+
function branchName(issue4, title2) {
|
|
18602
|
+
return `${BRANCH_PREFIX}/${planStub(issue4, title2)}`;
|
|
18603
|
+
}
|
|
18465
18604
|
function pullRequestTitle(issue4, title2) {
|
|
18466
18605
|
const id = boardId(issue4);
|
|
18467
18606
|
const spoken = title2.replace(LEADING_ID, "").trim();
|
|
@@ -18544,7 +18683,7 @@ function movePreviousCopy(options) {
|
|
|
18544
18683
|
mkdirSync9(absoluteDirectory, { recursive: true });
|
|
18545
18684
|
name2 = linkUnderFreeName(source, absoluteDirectory, savedName, timestamp);
|
|
18546
18685
|
} catch (error) {
|
|
18547
|
-
throw new Error(`${
|
|
18686
|
+
throw new Error(`${PREFIX5}: ${path2} could not be moved to ${directory2}: ${messageOf(error)}`, { cause: error });
|
|
18548
18687
|
}
|
|
18549
18688
|
const moved = {
|
|
18550
18689
|
path: join32(directory2, name2),
|
|
@@ -18553,7 +18692,7 @@ function movePreviousCopy(options) {
|
|
|
18553
18692
|
try {
|
|
18554
18693
|
unlinkSync(source);
|
|
18555
18694
|
} catch (error) {
|
|
18556
|
-
throw new Error(`${
|
|
18695
|
+
throw new Error(`${PREFIX5}: ${path2} was copied to ${moved.path} but could not be removed: ${messageOf(error)}`, { cause: error });
|
|
18557
18696
|
}
|
|
18558
18697
|
return moved;
|
|
18559
18698
|
}
|
|
@@ -18567,10 +18706,10 @@ function countPreviousCopies(repoRoot, specsDir) {
|
|
|
18567
18706
|
} catch (error) {
|
|
18568
18707
|
if (isMissing(error))
|
|
18569
18708
|
return 0;
|
|
18570
|
-
throw new Error(`${
|
|
18709
|
+
throw new Error(`${PREFIX5}: ${directory2} could not be read: ${messageOf(error)}`, { cause: error });
|
|
18571
18710
|
}
|
|
18572
18711
|
}
|
|
18573
|
-
var
|
|
18712
|
+
var PREFIX5 = "board previous copy", PREVIOUS_DIR_NAME = "previous", PREVIOUS_COPY_WARN_ABOVE = 50, COPY_EXTENSION = ".md", FIRST_SUFFIX = 2;
|
|
18574
18713
|
var init_previous_copy = __esm(() => {
|
|
18575
18714
|
init_config_sections();
|
|
18576
18715
|
});
|
|
@@ -18584,7 +18723,7 @@ function detailOf3(result, command) {
|
|
|
18584
18723
|
}
|
|
18585
18724
|
function issueNumber2(value) {
|
|
18586
18725
|
if (!Number.isSafeInteger(value) || value < 1) {
|
|
18587
|
-
throw new TypeError(`${
|
|
18726
|
+
throw new TypeError(`${PREFIX6}: the read refused issue number ${describeValue(value)}, expected a positive whole number`);
|
|
18588
18727
|
}
|
|
18589
18728
|
return String(value);
|
|
18590
18729
|
}
|
|
@@ -18619,11 +18758,11 @@ function readViewedIssue(stdout, number, command) {
|
|
|
18619
18758
|
try {
|
|
18620
18759
|
payload = JSON.parse(stdout);
|
|
18621
18760
|
} catch (error) {
|
|
18622
|
-
throw new Error(`${
|
|
18761
|
+
throw new Error(`${PREFIX6}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
|
|
18623
18762
|
}
|
|
18624
18763
|
const problem = viewProblem2(payload, number);
|
|
18625
18764
|
if (problem !== null)
|
|
18626
|
-
throw new Error(`${
|
|
18765
|
+
throw new Error(`${PREFIX6}: ${command} answered ${problem}`);
|
|
18627
18766
|
const checked = payload;
|
|
18628
18767
|
return {
|
|
18629
18768
|
number,
|
|
@@ -18641,7 +18780,7 @@ function createGhSpecIssueReader(options) {
|
|
|
18641
18780
|
const command = `gh issue view ${number} --json ${ISSUE_VIEW_FIELDS}`;
|
|
18642
18781
|
const result = await gh(["issue", "view", number, "--json", ISSUE_VIEW_FIELDS]);
|
|
18643
18782
|
if (!result.ok)
|
|
18644
|
-
throw new Error(`${
|
|
18783
|
+
throw new Error(`${PREFIX6}: ${detailOf3(result, command)}`);
|
|
18645
18784
|
return readViewedIssue(result.stdout, issue4, command);
|
|
18646
18785
|
};
|
|
18647
18786
|
}
|
|
@@ -18805,7 +18944,7 @@ function writeSpecSnapshot(options) {
|
|
|
18805
18944
|
mkdirSync10(dirname19(absolute), { recursive: true });
|
|
18806
18945
|
writeFileSync9(absolute, text2);
|
|
18807
18946
|
} catch (error) {
|
|
18808
|
-
throw new Error(`${
|
|
18947
|
+
throw new Error(`${PREFIX6}: the snapshot ${path2} could not be written: ${messageOf(error)}`, { cause: error });
|
|
18809
18948
|
}
|
|
18810
18949
|
return { ...written, action, previous };
|
|
18811
18950
|
}
|
|
@@ -18819,7 +18958,7 @@ function rewriteAction(existing, body, notes, notesFile, refresh) {
|
|
|
18819
18958
|
return "notes-rebuilt";
|
|
18820
18959
|
return refresh ? "refreshed" : null;
|
|
18821
18960
|
}
|
|
18822
|
-
var
|
|
18961
|
+
var PREFIX6 = "board issue", ISSUE_VIEW_FIELDS = "number,title,body,state,labels,author", SPEC_LABEL = "type:spec", ISSUE_REFUSAL_EXIT = 2, LOCAL_NOTES_HEADING = "## Local notes", NOTES_SEPARATOR, HEADING, FENCE2;
|
|
18823
18962
|
var init_issue = __esm(() => {
|
|
18824
18963
|
init_command();
|
|
18825
18964
|
init_config_sections();
|
|
@@ -19168,7 +19307,7 @@ var init_none = __esm(() => {
|
|
|
19168
19307
|
|
|
19169
19308
|
// src/pr/gh-closing-issues.ts
|
|
19170
19309
|
function refuse3(command, problem) {
|
|
19171
|
-
throw new Error(`${
|
|
19310
|
+
throw new Error(`${PREFIX7}: ${command} answered ${problem}`);
|
|
19172
19311
|
}
|
|
19173
19312
|
function readMapping(value, command, where) {
|
|
19174
19313
|
if (!isMapping(value))
|
|
@@ -19209,7 +19348,7 @@ function readClosingIssues(value, command, where) {
|
|
|
19209
19348
|
refuse3(command, `${where} is ${describeValue(value)}, expected a list`);
|
|
19210
19349
|
return value.map((reference2, index) => readClosingIssue(reference2, command, `${where}[${index}]`));
|
|
19211
19350
|
}
|
|
19212
|
-
var CLOSING_ISSUES_FIELD = "closingIssuesReferences",
|
|
19351
|
+
var CLOSING_ISSUES_FIELD = "closingIssuesReferences", PREFIX7 = "gh pull requests";
|
|
19213
19352
|
var init_gh_closing_issues = __esm(() => {
|
|
19214
19353
|
init_config_sections();
|
|
19215
19354
|
});
|
|
@@ -19222,16 +19361,16 @@ function detailOf4(result, command) {
|
|
|
19222
19361
|
return result.ok ? `${command} exited 0 and wrote nothing` : `${command} exited non-zero and wrote nothing`;
|
|
19223
19362
|
}
|
|
19224
19363
|
function failure2(command, result) {
|
|
19225
|
-
return new Error(`${
|
|
19364
|
+
return new Error(`${PREFIX8}: ${command} failed: ${detailOf4(result, command)}`);
|
|
19226
19365
|
}
|
|
19227
19366
|
function refuse4(command, problem) {
|
|
19228
|
-
throw new Error(`${
|
|
19367
|
+
throw new Error(`${PREFIX8}: ${command} answered ${problem}`);
|
|
19229
19368
|
}
|
|
19230
19369
|
function parseJson2(stdout, command) {
|
|
19231
19370
|
try {
|
|
19232
19371
|
return JSON.parse(stdout);
|
|
19233
19372
|
} catch (error) {
|
|
19234
|
-
throw new Error(`${
|
|
19373
|
+
throw new Error(`${PREFIX8}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
|
|
19235
19374
|
}
|
|
19236
19375
|
}
|
|
19237
19376
|
function readString3(value, command, where) {
|
|
@@ -19371,7 +19510,7 @@ function readWorkflowCount(stdout) {
|
|
|
19371
19510
|
}
|
|
19372
19511
|
function pullNumber(value, member) {
|
|
19373
19512
|
if (!Number.isSafeInteger(value) || value < 1) {
|
|
19374
|
-
throw new TypeError(`${
|
|
19513
|
+
throw new TypeError(`${PREFIX8}: ${member} refused pull request number ${describeValue(value)},` + " expected a positive whole number");
|
|
19375
19514
|
}
|
|
19376
19515
|
return String(value);
|
|
19377
19516
|
}
|
|
@@ -19379,13 +19518,13 @@ function textArgument(value, member, what, whole) {
|
|
|
19379
19518
|
const bad = typeof value !== "string" || value === "" || whole && !(WHOLE_NUMBER.test(value) && Number.isSafeInteger(Number(value)));
|
|
19380
19519
|
if (bad) {
|
|
19381
19520
|
const expected2 = whole ? "a positive whole number with no leading zero" : "a non-empty string";
|
|
19382
|
-
throw new TypeError(`${
|
|
19521
|
+
throw new TypeError(`${PREFIX8}: ${member} refused ${what} ${describeValue(value)}, expected ${expected2}`);
|
|
19383
19522
|
}
|
|
19384
19523
|
return value;
|
|
19385
19524
|
}
|
|
19386
19525
|
function bodyText(value, member) {
|
|
19387
19526
|
if (typeof value !== "string") {
|
|
19388
|
-
throw new TypeError(`${
|
|
19527
|
+
throw new TypeError(`${PREFIX8}: ${member} refused a body ${describeValue(value)}, expected a string`);
|
|
19389
19528
|
}
|
|
19390
19529
|
return value;
|
|
19391
19530
|
}
|
|
@@ -19483,7 +19622,7 @@ function createGhPullRequests(options) {
|
|
|
19483
19622
|
merge: async (number, method) => {
|
|
19484
19623
|
const target = pullNumber(number, "merge");
|
|
19485
19624
|
if (!isMergeMethod(method)) {
|
|
19486
|
-
throw new TypeError(`${
|
|
19625
|
+
throw new TypeError(`${PREFIX8}: merge refused method ${describeValue(method)},` + ` expected one of: ${MERGE_METHODS.join(", ")}`);
|
|
19487
19626
|
}
|
|
19488
19627
|
const command = `gh pr merge ${target} --${method}`;
|
|
19489
19628
|
const result = await gh(["pr", "merge", target, `--${method}`]);
|
|
@@ -19565,7 +19704,7 @@ function ghPullRequestsIn(cwd) {
|
|
|
19565
19704
|
function ghAuthOkIn(cwd) {
|
|
19566
19705
|
return ghAuthOk(createGhRunner({ cwd }));
|
|
19567
19706
|
}
|
|
19568
|
-
var
|
|
19707
|
+
var PREFIX8 = "gh pull requests", REPO_PATH2 = "{owner}/{repo}", SUMMARY_FIELDS = "author,baseRefName,headRefName,isCrossRepository,number,state,title,updatedAt,url", DETAIL_FIELDS, CHECK_FIELDS = "name,state,link", MERGED_FIELDS = "headRefName,headRefOid,mergedAt,number", FILES_FIELDS = "changedFiles,files", REVIEW_FIELDS = "reviews", WORKFLOWS_PATH, LIST_LIMIT = 30, MERGED_LIMIT = 100, FIND_LIMIT = 1, MISSING_PULL = "Could not resolve to a PullRequest", CREATED_URL, NO_CHECKS = "no checks reported on the", LOG_DROPPED = "log not found", WHOLE_NUMBER, STATES, MERGEABILITY;
|
|
19569
19708
|
var init_gh = __esm(() => {
|
|
19570
19709
|
init_github();
|
|
19571
19710
|
init_config_sections();
|
|
@@ -20144,24 +20283,24 @@ function parseRows(stdout, command) {
|
|
|
20144
20283
|
try {
|
|
20145
20284
|
payload = JSON.parse(stdout);
|
|
20146
20285
|
} catch (error) {
|
|
20147
|
-
throw new Error(`${
|
|
20286
|
+
throw new Error(`${PREFIX9}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
|
|
20148
20287
|
}
|
|
20149
20288
|
if (!Array.isArray(payload)) {
|
|
20150
|
-
throw new Error(`${
|
|
20289
|
+
throw new Error(`${PREFIX9}: ${command} answered ${describeValue(payload)}, expected a list`);
|
|
20151
20290
|
}
|
|
20152
20291
|
return payload;
|
|
20153
20292
|
}
|
|
20154
20293
|
function rowNumber(row2, key, command, where) {
|
|
20155
20294
|
const value = isMapping(row2) ? row2[key] : null;
|
|
20156
20295
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) {
|
|
20157
|
-
throw new Error(`${
|
|
20296
|
+
throw new Error(`${PREFIX9}: ${command} answered ${where}.${key} as ${describeValue(value)}, expected a positive whole number`);
|
|
20158
20297
|
}
|
|
20159
20298
|
return value;
|
|
20160
20299
|
}
|
|
20161
20300
|
function rowText(row2, key, command, where) {
|
|
20162
20301
|
const value = isMapping(row2) ? row2[key] : null;
|
|
20163
20302
|
if (typeof value !== "string") {
|
|
20164
|
-
throw new Error(`${
|
|
20303
|
+
throw new Error(`${PREFIX9}: ${command} answered ${where}.${key} as ${describeValue(value)}, expected a string`);
|
|
20165
20304
|
}
|
|
20166
20305
|
return value;
|
|
20167
20306
|
}
|
|
@@ -20173,7 +20312,7 @@ function createGhRoadmapSearch(options) {
|
|
|
20173
20312
|
return async () => {
|
|
20174
20313
|
const result = await gh(args);
|
|
20175
20314
|
if (!result.ok)
|
|
20176
|
-
throw new Error(`${
|
|
20315
|
+
throw new Error(`${PREFIX9}: ${detailOf5(result, command)}`);
|
|
20177
20316
|
return Object.freeze(parseRows(result.stdout, command).map((row2, index) => ({
|
|
20178
20317
|
number: rowNumber(row2, "number", command, `issue ${String(index)}`),
|
|
20179
20318
|
title: rowText(row2, "title", command, `issue ${String(index)}`)
|
|
@@ -20210,7 +20349,7 @@ function createGhOpenPullRequests(options) {
|
|
|
20210
20349
|
return async () => {
|
|
20211
20350
|
const result = await gh(args);
|
|
20212
20351
|
if (!result.ok)
|
|
20213
|
-
throw new Error(`${
|
|
20352
|
+
throw new Error(`${PREFIX9}: ${detailOf5(result, command)}`);
|
|
20214
20353
|
return Object.freeze(parseRows(result.stdout, command).map((row2, index) => ({
|
|
20215
20354
|
number: rowNumber(row2, "number", command, `pull request ${String(index)}`),
|
|
20216
20355
|
headRefName: rowText(row2, "headRefName", command, `pull request ${String(index)}`),
|
|
@@ -20332,7 +20471,7 @@ function exhaustedMessage(roadmap, skipped2) {
|
|
|
20332
20471
|
const id = `issue #${String(roadmap)}`;
|
|
20333
20472
|
return skipped2.length === 0 ? `the roadmap, ${id}, carries no "- [ ] #<n>" line; add the next spec to its task list` : `every line of the roadmap, ${id}, is done or taken (${String(skipped2.length)} of them);` + " open the next spec issue and add it to the task list";
|
|
20334
20473
|
}
|
|
20335
|
-
var
|
|
20474
|
+
var PREFIX9 = "board roadmap", ROADMAP_TITLE = "Roadmap", ROADMAP_SETTING = "roadmap.issue", ROADMAP_REFUSAL_EXIT = 2, DEFAULT_REMOTE2 = "origin", OPEN_PULL_REQUEST_LIMIT = 100, PR_LIST_FIELDS = "number,headRefName,body", ISSUE_LIST_FIELDS = "number,title", TASK_LINE, FENCE3, WHY_SEPARATOR, CLOSING;
|
|
20336
20475
|
var init_roadmap = __esm(() => {
|
|
20337
20476
|
init_command();
|
|
20338
20477
|
init_config_schema();
|
|
@@ -20426,24 +20565,24 @@ function parseRows2(stdout, command) {
|
|
|
20426
20565
|
try {
|
|
20427
20566
|
payload = JSON.parse(stdout);
|
|
20428
20567
|
} catch (error) {
|
|
20429
|
-
throw new Error(`${
|
|
20568
|
+
throw new Error(`${PREFIX10}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
|
|
20430
20569
|
}
|
|
20431
20570
|
if (!Array.isArray(payload)) {
|
|
20432
|
-
throw new Error(`${
|
|
20571
|
+
throw new Error(`${PREFIX10}: ${command} answered ${describeValue(payload)}, expected a list`);
|
|
20433
20572
|
}
|
|
20434
20573
|
return payload;
|
|
20435
20574
|
}
|
|
20436
20575
|
function rowText2(row2, key, command, where) {
|
|
20437
20576
|
const value = isMapping(row2) ? row2[key] : null;
|
|
20438
20577
|
if (typeof value !== "string") {
|
|
20439
|
-
throw new Error(`${
|
|
20578
|
+
throw new Error(`${PREFIX10}: ${command} answered ${where}.${key} as ${describeValue(value)}, expected a string`);
|
|
20440
20579
|
}
|
|
20441
20580
|
return value;
|
|
20442
20581
|
}
|
|
20443
20582
|
function rowNumber2(row2, key, command, where) {
|
|
20444
20583
|
const value = isMapping(row2) ? row2[key] : null;
|
|
20445
20584
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) {
|
|
20446
|
-
throw new Error(`${
|
|
20585
|
+
throw new Error(`${PREFIX10}: ${command} answered ${where}.${key} as ${describeValue(value)}, expected a positive whole number`);
|
|
20447
20586
|
}
|
|
20448
20587
|
return value;
|
|
20449
20588
|
}
|
|
@@ -20453,7 +20592,7 @@ async function listBoardLabels(gh) {
|
|
|
20453
20592
|
const command = `gh label list --limit ${limit} --json name`;
|
|
20454
20593
|
const result = await gh(args);
|
|
20455
20594
|
if (!result.ok)
|
|
20456
|
-
throw new Error(`${
|
|
20595
|
+
throw new Error(`${PREFIX10}: ${detailOf6(result, command)}`);
|
|
20457
20596
|
return Object.freeze(parseRows2(result.stdout, command).map((row2, index) => rowText2(row2, "name", command, `label ${String(index)}`)));
|
|
20458
20597
|
}
|
|
20459
20598
|
function holdsLabel(held, name2) {
|
|
@@ -20505,7 +20644,7 @@ function specTemplateSource(moduleDir = MODULE_DIR) {
|
|
|
20505
20644
|
function readSpecTemplate(moduleDir = MODULE_DIR) {
|
|
20506
20645
|
const source = specTemplateSource(moduleDir);
|
|
20507
20646
|
if (!existsSync29(source)) {
|
|
20508
|
-
throw new Error(`${
|
|
20647
|
+
throw new Error(`${PREFIX10}: the spec issue template is missing: no file at ${source}`);
|
|
20509
20648
|
}
|
|
20510
20649
|
return readFileSync26(source, "utf8");
|
|
20511
20650
|
}
|
|
@@ -20598,7 +20737,7 @@ function roadmapRefused(why) {
|
|
|
20598
20737
|
function rowLabels(row2, command, where) {
|
|
20599
20738
|
const value = isMapping(row2) ? row2["labels"] : null;
|
|
20600
20739
|
if (!Array.isArray(value)) {
|
|
20601
|
-
throw new Error(`${
|
|
20740
|
+
throw new Error(`${PREFIX10}: ${command} answered ${where}.labels as ${describeValue(value)}, expected a list`);
|
|
20602
20741
|
}
|
|
20603
20742
|
return value.map((label, index) => rowText2(label, "name", command, `${where}.labels ${String(index)}`));
|
|
20604
20743
|
}
|
|
@@ -20608,7 +20747,7 @@ async function searchRoadmapIssues(gh) {
|
|
|
20608
20747
|
const command = `gh issue list --state open --search "${search}" --json number,title,labels`;
|
|
20609
20748
|
const result = await gh(args);
|
|
20610
20749
|
if (!result.ok)
|
|
20611
|
-
throw new Error(`${
|
|
20750
|
+
throw new Error(`${PREFIX10}: ${detailOf6(result, command)}`);
|
|
20612
20751
|
const wanted = ROADMAP_TITLE.toLowerCase();
|
|
20613
20752
|
return Object.freeze(parseRows2(result.stdout, command).map((row2, index) => ({
|
|
20614
20753
|
number: rowNumber2(row2, "number", command, `issue ${String(index)}`),
|
|
@@ -20620,12 +20759,12 @@ async function createRoadmapIssue(gh) {
|
|
|
20620
20759
|
const command = `gh issue create --title ${ROADMAP_TITLE} --label ${ROADMAP_LABEL}`;
|
|
20621
20760
|
const result = await gh(["issue", "create", "--title", ROADMAP_TITLE, "--label", ROADMAP_LABEL, "--body", roadmapIssueBody()]);
|
|
20622
20761
|
if (!result.ok)
|
|
20623
|
-
throw new Error(`${
|
|
20762
|
+
throw new Error(`${PREFIX10}: ${detailOf6(result, command)}`);
|
|
20624
20763
|
const url = result.stdout.trim().split(`
|
|
20625
20764
|
`).at(-1) ?? "";
|
|
20626
20765
|
const number = CREATED_ISSUE_URL2.exec(url)?.[1];
|
|
20627
20766
|
if (number === undefined) {
|
|
20628
|
-
throw new Error(`${
|
|
20767
|
+
throw new Error(`${PREFIX10}: ${command} exited 0 and printed no issue URL, so the issue may exist` + ` unrecorded; it wrote ${describeValue(result.stdout)}`);
|
|
20629
20768
|
}
|
|
20630
20769
|
return Number.parseInt(number, 10);
|
|
20631
20770
|
}
|
|
@@ -20704,7 +20843,7 @@ async function setUpBoard(options) {
|
|
|
20704
20843
|
problems: Object.freeze([...roadmap.problems])
|
|
20705
20844
|
});
|
|
20706
20845
|
}
|
|
20707
|
-
var
|
|
20846
|
+
var PREFIX10 = "board setup", MODULE_DIR, ROADMAP_LABEL, BOARD_LABELS, LABEL_LIST_LIMIT = 100, SPEC_TEMPLATE_PATH, TEMPLATES_DIRNAME = "templates", SPEC_TEMPLATE_FILE = "spec.md", CREATED_ISSUE_URL2, ISSUE_PART_NAME;
|
|
20708
20847
|
var init_setup = __esm(() => {
|
|
20709
20848
|
init_github();
|
|
20710
20849
|
init_stale();
|
|
@@ -20792,47 +20931,47 @@ function detailOf7(result, command) {
|
|
|
20792
20931
|
return written === "" ? `${command} failed and wrote nothing` : `${command} failed: ${written}`;
|
|
20793
20932
|
}
|
|
20794
20933
|
function failure3(command, result) {
|
|
20795
|
-
return new Error(`${
|
|
20934
|
+
return new Error(`${PREFIX11}: ${detailOf7(result, command)}`);
|
|
20796
20935
|
}
|
|
20797
20936
|
function issueNumber3(value, member) {
|
|
20798
20937
|
if (!Number.isSafeInteger(value) || value < 1) {
|
|
20799
|
-
throw new TypeError(`${
|
|
20938
|
+
throw new TypeError(`${PREFIX11}: ${member} refused issue number ${describeValue(value)}, expected a positive whole number`);
|
|
20800
20939
|
}
|
|
20801
20940
|
return String(value);
|
|
20802
20941
|
}
|
|
20803
20942
|
function commentId(value) {
|
|
20804
20943
|
if (typeof value !== "string" || !COMMENT_ID.test(value)) {
|
|
20805
|
-
throw new TypeError(`${
|
|
20944
|
+
throw new TypeError(`${PREFIX11}: editComment refused comment id ${describeValue(value)},` + " expected a positive whole number with no leading zero");
|
|
20806
20945
|
}
|
|
20807
20946
|
return value;
|
|
20808
20947
|
}
|
|
20809
20948
|
function commentBody2(value, member) {
|
|
20810
20949
|
if (typeof value !== "string") {
|
|
20811
|
-
throw new TypeError(`${
|
|
20950
|
+
throw new TypeError(`${PREFIX11}: ${member} refused a body ${describeValue(value)}, expected a string`);
|
|
20812
20951
|
}
|
|
20813
20952
|
return value;
|
|
20814
20953
|
}
|
|
20815
20954
|
function closeReason(value) {
|
|
20816
20955
|
if (!CLOSE_REASONS.includes(value)) {
|
|
20817
|
-
throw new TypeError(`${
|
|
20956
|
+
throw new TypeError(`${PREFIX11}: closeIssue refused reason ${describeValue(value)}, expected one of ${CLOSE_REASONS.join(", ")}`);
|
|
20818
20957
|
}
|
|
20819
20958
|
return value;
|
|
20820
20959
|
}
|
|
20821
20960
|
function closeComment(value, member = "closeIssue") {
|
|
20822
20961
|
if (commentBody2(value, member).trim() === "") {
|
|
20823
|
-
throw new TypeError(`${
|
|
20962
|
+
throw new TypeError(`${PREFIX11}: ${member} refused an empty comment, every close leaves one`);
|
|
20824
20963
|
}
|
|
20825
20964
|
return value;
|
|
20826
20965
|
}
|
|
20827
20966
|
function labelName(value, member, what) {
|
|
20828
20967
|
if (typeof value !== "string" || value === "" || value.startsWith("-")) {
|
|
20829
|
-
throw new TypeError(`${
|
|
20968
|
+
throw new TypeError(`${PREFIX11}: ${member} refused ${what} ${describeValue(value)},` + " expected a non-empty name that does not open with a hyphen");
|
|
20830
20969
|
}
|
|
20831
20970
|
return value;
|
|
20832
20971
|
}
|
|
20833
20972
|
function issueTitle(value) {
|
|
20834
20973
|
if (typeof value !== "string" || value.trim() === "" || /[\r\n]/u.test(value)) {
|
|
20835
|
-
throw new TypeError(`${
|
|
20974
|
+
throw new TypeError(`${PREFIX11}: createIssue refused the title ${describeValue(value)}, expected one line holding some text`);
|
|
20836
20975
|
}
|
|
20837
20976
|
return value;
|
|
20838
20977
|
}
|
|
@@ -20841,7 +20980,7 @@ function createdIssue(stdout) {
|
|
|
20841
20980
|
`).at(-1)?.trim() ?? "";
|
|
20842
20981
|
const number = CREATED_ISSUE_URL2.exec(url)?.[1];
|
|
20843
20982
|
if (number === undefined) {
|
|
20844
|
-
throw new Error(`${
|
|
20983
|
+
throw new Error(`${PREFIX11}: gh issue create exited 0 and printed no issue URL, so the issue may exist` + ` unrecorded; it wrote ${describeValue(stdout)}`);
|
|
20845
20984
|
}
|
|
20846
20985
|
return Object.freeze({ number: Number(number), url });
|
|
20847
20986
|
}
|
|
@@ -20849,20 +20988,20 @@ function parseJson3(stdout, command) {
|
|
|
20849
20988
|
try {
|
|
20850
20989
|
return JSON.parse(stdout);
|
|
20851
20990
|
} catch (error) {
|
|
20852
|
-
throw new Error(`${
|
|
20991
|
+
throw new Error(`${PREFIX11}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
|
|
20853
20992
|
}
|
|
20854
20993
|
}
|
|
20855
20994
|
function readComment2(value, command, where) {
|
|
20856
20995
|
if (!isMapping(value)) {
|
|
20857
|
-
throw new Error(`${
|
|
20996
|
+
throw new Error(`${PREFIX11}: ${command} answered ${where} as ${describeValue(value)}, expected a mapping`);
|
|
20858
20997
|
}
|
|
20859
20998
|
const id = value["id"];
|
|
20860
20999
|
if (typeof id !== "number" || !Number.isSafeInteger(id) || id < 1) {
|
|
20861
|
-
throw new Error(`${
|
|
21000
|
+
throw new Error(`${PREFIX11}: ${command} answered ${where}.id as ${describeValue(id)}, expected a positive whole number`);
|
|
20862
21001
|
}
|
|
20863
21002
|
const body = value["body"];
|
|
20864
21003
|
if (typeof body !== "string") {
|
|
20865
|
-
throw new Error(`${
|
|
21004
|
+
throw new Error(`${PREFIX11}: ${command} answered ${where}.body as ${describeValue(body)}, expected a string`);
|
|
20866
21005
|
}
|
|
20867
21006
|
const user = value["user"];
|
|
20868
21007
|
const login = isMapping(user) ? user["login"] : null;
|
|
@@ -20887,7 +21026,7 @@ function createGhIssueBoard(options) {
|
|
|
20887
21026
|
const command = `gh api ${path2}`;
|
|
20888
21027
|
const rows2 = parseJson3(await succeed(["api", path2], command), command);
|
|
20889
21028
|
if (!Array.isArray(rows2)) {
|
|
20890
|
-
throw new Error(`${
|
|
21029
|
+
throw new Error(`${PREFIX11}: ${command} answered ${describeValue(rows2)}, expected a list of comments`);
|
|
20891
21030
|
}
|
|
20892
21031
|
return rows2.map((row2, index) => readComment2(row2, command, `comment ${String(index)}`));
|
|
20893
21032
|
},
|
|
@@ -20947,7 +21086,7 @@ function createGhIssueBoard(options) {
|
|
|
20947
21086
|
};
|
|
20948
21087
|
return Object.freeze(board);
|
|
20949
21088
|
}
|
|
20950
|
-
var
|
|
21089
|
+
var PREFIX11 = "board issue", REPO_PATH3 = "{owner}/{repo}", COMMENT_ID, CLOSE_REASONS;
|
|
20951
21090
|
var init_issue_board = __esm(() => {
|
|
20952
21091
|
init_config_sections();
|
|
20953
21092
|
init_setup();
|
|
@@ -20987,14 +21126,14 @@ function warn(warning) {
|
|
|
20987
21126
|
return Object.freeze({ outcome: "warning", warning });
|
|
20988
21127
|
}
|
|
20989
21128
|
function noBoard(issue4, stage) {
|
|
20990
|
-
return warn(`${
|
|
21129
|
+
return warn(`${PREFIX12}: #${String(issue4)} was not ${stage}: the board is not gh; ${CLAIM_STANDS}`);
|
|
20991
21130
|
}
|
|
20992
21131
|
async function attempt(issue4, stage, write) {
|
|
20993
21132
|
try {
|
|
20994
21133
|
await write();
|
|
20995
21134
|
return WRITTEN;
|
|
20996
21135
|
} catch (error) {
|
|
20997
|
-
return warn(`${
|
|
21136
|
+
return warn(`${PREFIX12}: #${String(issue4)} was not ${stage}: ${messageOf(error)}; ${CLAIM_STANDS}`);
|
|
20998
21137
|
}
|
|
20999
21138
|
}
|
|
21000
21139
|
async function labelClaimed(board, issue4) {
|
|
@@ -21024,7 +21163,7 @@ async function clearStage(board, issue4, why) {
|
|
|
21024
21163
|
async function unlabelReleased(board, issue4) {
|
|
21025
21164
|
return clearStage(board, issue4, "release");
|
|
21026
21165
|
}
|
|
21027
|
-
var
|
|
21166
|
+
var PREFIX12 = "claim labels", CLAIM_STANDS = "the claim stands in git", STAGE_LABELS, WRITTEN;
|
|
21028
21167
|
var init_labels = __esm(() => {
|
|
21029
21168
|
init_config_sections();
|
|
21030
21169
|
init_stale();
|
|
@@ -21421,13 +21560,13 @@ function parseBoardListing(stdout, command, mode = "labels") {
|
|
|
21421
21560
|
try {
|
|
21422
21561
|
payload = JSON.parse(stdout);
|
|
21423
21562
|
} catch (error) {
|
|
21424
|
-
throw new Error(`${
|
|
21563
|
+
throw new Error(`${PREFIX13}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
|
|
21425
21564
|
}
|
|
21426
21565
|
if (!Array.isArray(payload)) {
|
|
21427
|
-
throw new Error(`${
|
|
21566
|
+
throw new Error(`${PREFIX13}: ${command} answered ${describeValue(payload)}, expected a list`);
|
|
21428
21567
|
}
|
|
21429
21568
|
const issues = payload.map((row2, index) => {
|
|
21430
|
-
const refusal3 = `${
|
|
21569
|
+
const refusal3 = `${PREFIX13}: ${command} answered row ${index}`;
|
|
21431
21570
|
const problem = rowProblem(row2);
|
|
21432
21571
|
if (problem !== null)
|
|
21433
21572
|
throw new Error(`${refusal3} with ${problem}`);
|
|
@@ -21447,18 +21586,18 @@ function keepListing(listing) {
|
|
|
21447
21586
|
function createGhBoardListing(options) {
|
|
21448
21587
|
const { gh, limit = BOARD_LISTING_LIMIT, mode = "labels" } = options;
|
|
21449
21588
|
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
21450
|
-
throw new TypeError(`${
|
|
21589
|
+
throw new TypeError(`${PREFIX13}: limit ${describeValue(limit)}, expected a positive whole number`);
|
|
21451
21590
|
}
|
|
21452
21591
|
const args = listingArgs(limit, mode);
|
|
21453
21592
|
const command = boardListingCommand(limit, mode);
|
|
21454
21593
|
return async () => {
|
|
21455
21594
|
const result = await gh(args);
|
|
21456
21595
|
if (!result.ok)
|
|
21457
|
-
throw new Error(`${
|
|
21596
|
+
throw new Error(`${PREFIX13}: ${detailOf8(result, command)}`);
|
|
21458
21597
|
return parseBoardListing(result.stdout, command, mode);
|
|
21459
21598
|
};
|
|
21460
21599
|
}
|
|
21461
|
-
var
|
|
21600
|
+
var PREFIX13 = "board listing", BOARD_LIST_FIELDS = "number,title,body,state,stateReason,labels", nativeBoardListFields, BOARD_LISTING_LIMIT = 1000, NativeFieldProblem, ISSUE_URL;
|
|
21462
21601
|
var init_roadmap_board = __esm(() => {
|
|
21463
21602
|
init_github();
|
|
21464
21603
|
init_config_sections();
|
|
@@ -22039,7 +22178,7 @@ function epicOnListing(number, listing, relations) {
|
|
|
22039
22178
|
const epic = readEpics(relations === undefined ? input : { ...input, relations }).epics.find((read) => read.number === number);
|
|
22040
22179
|
const row2 = listing.find((issue4) => issue4.number === number);
|
|
22041
22180
|
if (epic === undefined || row2 === undefined) {
|
|
22042
|
-
throw new Error(`${
|
|
22181
|
+
throw new Error(`${PREFIX14}: epic #${String(number)} is not on the board listing, so its members cannot be read;` + " the listing reads the newest issues only, and an epic it leaves out is not walked as if it had none");
|
|
22043
22182
|
}
|
|
22044
22183
|
return { epic, row: row2 };
|
|
22045
22184
|
}
|
|
@@ -22160,7 +22299,7 @@ function dryEpicSentence(epic) {
|
|
|
22160
22299
|
function rowOnListing(number, listing, what) {
|
|
22161
22300
|
const row2 = listing.find((issue4) => issue4.number === number);
|
|
22162
22301
|
if (row2 === undefined) {
|
|
22163
|
-
throw new Error(`${
|
|
22302
|
+
throw new Error(`${PREFIX14}: ${what} #${String(number)} is not on the board listing, so the next ${NOW_HORIZON_LABEL} epic` + " cannot be read; the listing reads the newest issues only, and a line it leaves out is not passed as if it were none");
|
|
22164
22303
|
}
|
|
22165
22304
|
return row2;
|
|
22166
22305
|
}
|
|
@@ -22201,7 +22340,7 @@ async function nextNowEpic(request) {
|
|
|
22201
22340
|
}
|
|
22202
22341
|
return null;
|
|
22203
22342
|
}
|
|
22204
|
-
var
|
|
22343
|
+
var PREFIX14 = "board epic walk", NOW_HORIZON_LABEL, NO_CLAIMS, UNREAD_DAY, LINE_BREAK;
|
|
22205
22344
|
var init_epic_walk = __esm(() => {
|
|
22206
22345
|
init_github();
|
|
22207
22346
|
init_epic_problems();
|
|
@@ -22301,11 +22440,11 @@ function driftSentence(finding) {
|
|
|
22301
22440
|
}
|
|
22302
22441
|
function driftLines(report) {
|
|
22303
22442
|
return Object.freeze([
|
|
22304
|
-
...report.findings.map((finding) => `${
|
|
22305
|
-
...report.notices.map((notice) => `${
|
|
22443
|
+
...report.findings.map((finding) => `${PREFIX15}: ${driftSentence(finding)}`),
|
|
22444
|
+
...report.notices.map((notice) => `${PREFIX15}: ${notice}`)
|
|
22306
22445
|
]);
|
|
22307
22446
|
}
|
|
22308
|
-
var
|
|
22447
|
+
var PREFIX15 = "claim drift";
|
|
22309
22448
|
var init_drift = __esm(() => {
|
|
22310
22449
|
init_epic_walk();
|
|
22311
22450
|
init_roadmap_claims();
|
|
@@ -23923,7 +24062,7 @@ function createGhBoardLister(options) {
|
|
|
23923
24062
|
return async () => {
|
|
23924
24063
|
const result = await gh(args);
|
|
23925
24064
|
if (!result.ok)
|
|
23926
|
-
throw new Error(`${
|
|
24065
|
+
throw new Error(`${PREFIX16}: ${detailOf9(result, command)}`);
|
|
23927
24066
|
return parseBoardListing(result.stdout, command, mode);
|
|
23928
24067
|
};
|
|
23929
24068
|
}
|
|
@@ -23951,7 +24090,7 @@ function unlabelledRoadmapMessage(numbers) {
|
|
|
23951
24090
|
const which = numbers.length === 1 ? `open issue ${named} is titled ${ROADMAP_TITLE} but lacks` : `open issues ${named} are titled ${ROADMAP_TITLE} but lack`;
|
|
23952
24091
|
return `${which} the ${ROADMAP_LABEL} label, so no reader takes it as a board while labelled boards exist;` + " add the label to make it one, or retitle or close it";
|
|
23953
24092
|
}
|
|
23954
|
-
var
|
|
24093
|
+
var PREFIX16 = "board listing", BOARDS_LIST_ARGS, BOARDS_LIST_COMMAND;
|
|
23955
24094
|
var init_boards = __esm(() => {
|
|
23956
24095
|
init_roadmap_board();
|
|
23957
24096
|
init_roadmap();
|
|
@@ -24006,17 +24145,17 @@ function bodyOf2(stdout, command) {
|
|
|
24006
24145
|
try {
|
|
24007
24146
|
payload = JSON.parse(stdout);
|
|
24008
24147
|
} catch (error) {
|
|
24009
|
-
throw new Error(`${
|
|
24148
|
+
throw new Error(`${PREFIX17}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
|
|
24010
24149
|
}
|
|
24011
24150
|
const body = isMapping(payload) ? payload["body"] : null;
|
|
24012
24151
|
if (typeof body !== "string") {
|
|
24013
|
-
throw new Error(`${
|
|
24152
|
+
throw new Error(`${PREFIX17}: ${command} answered body as ${describeValue(body)}, expected a string`);
|
|
24014
24153
|
}
|
|
24015
24154
|
return body;
|
|
24016
24155
|
}
|
|
24017
24156
|
function issueSegment(value, member) {
|
|
24018
24157
|
if (!Number.isSafeInteger(value) || value < 1) {
|
|
24019
|
-
throw new TypeError(`${
|
|
24158
|
+
throw new TypeError(`${PREFIX17}: ${member} refused issue number ${describeValue(value)}, expected a positive whole number`);
|
|
24020
24159
|
}
|
|
24021
24160
|
return String(value);
|
|
24022
24161
|
}
|
|
@@ -24028,7 +24167,7 @@ function createGhRoadmapBody(options) {
|
|
|
24028
24167
|
const path2 = pathOf(issue4, "read");
|
|
24029
24168
|
const result = await gh(["api", path2]);
|
|
24030
24169
|
if (!result.ok)
|
|
24031
|
-
throw new Error(`${
|
|
24170
|
+
throw new Error(`${PREFIX17}: ${detailOf10(result, `gh api ${path2}`)}`);
|
|
24032
24171
|
return bodyOf2(result.stdout, `gh api ${path2}`);
|
|
24033
24172
|
},
|
|
24034
24173
|
write: async (issue4, body) => {
|
|
@@ -24036,13 +24175,13 @@ function createGhRoadmapBody(options) {
|
|
|
24036
24175
|
const result = await gh(["api", path2, "-X", "PATCH", "-f", `body=${body}`]);
|
|
24037
24176
|
const command = `gh api ${path2} -X PATCH -f body=<body>`;
|
|
24038
24177
|
if (!result.ok)
|
|
24039
|
-
throw new Error(`${
|
|
24178
|
+
throw new Error(`${PREFIX17}: ${detailOf10(result, command)}`);
|
|
24040
24179
|
return bodyOf2(result.stdout, command);
|
|
24041
24180
|
}
|
|
24042
24181
|
});
|
|
24043
24182
|
}
|
|
24044
24183
|
function conflictProblem(issue4) {
|
|
24045
|
-
return `${
|
|
24184
|
+
return `${PREFIX17}: issue #${String(issue4)} answered a body other than the one that was written,` + " so somebody edited it in between";
|
|
24046
24185
|
}
|
|
24047
24186
|
async function attemptTick(roadmap, issues, board, attempt2) {
|
|
24048
24187
|
let edit;
|
|
@@ -24102,7 +24241,7 @@ function tickSentence(result) {
|
|
|
24102
24241
|
return `${named(result.already)} is ticked on ${roadmap} already.`;
|
|
24103
24242
|
return `${roadmap} carries no line for ${named(result.absent)}, so nothing was ticked.`;
|
|
24104
24243
|
}
|
|
24105
|
-
var
|
|
24244
|
+
var PREFIX17 = "board roadmap", REPO_PATH4 = "{owner}/{repo}", TICK_ATTEMPTS = 2, UNTICKED, TICKED = "[x]", LINE_BREAK2;
|
|
24106
24245
|
var init_roadmap_tick = __esm(() => {
|
|
24107
24246
|
init_config_sections();
|
|
24108
24247
|
init_roadmap();
|
|
@@ -24124,7 +24263,7 @@ function joinParts(parts) {
|
|
|
24124
24263
|
}
|
|
24125
24264
|
function checkedIssue(issue4, member) {
|
|
24126
24265
|
if (!Number.isSafeInteger(issue4) || issue4 < 1) {
|
|
24127
|
-
throw new TypeError(`${
|
|
24266
|
+
throw new TypeError(`${PREFIX18}: ${member} refused issue number ${describeValue(issue4)}, expected a positive whole number`);
|
|
24128
24267
|
}
|
|
24129
24268
|
return issue4;
|
|
24130
24269
|
}
|
|
@@ -24157,7 +24296,7 @@ function lastTextIndex(parts) {
|
|
|
24157
24296
|
function appendLine(body, issue4, why = "") {
|
|
24158
24297
|
checkedIssue(issue4, "appendLine");
|
|
24159
24298
|
if (LINE_BREAK3.test(why)) {
|
|
24160
|
-
throw new TypeError(`${
|
|
24299
|
+
throw new TypeError(`${PREFIX18}: appendLine refused a why spanning several lines: ${describeValue(why)}`);
|
|
24161
24300
|
}
|
|
24162
24301
|
if (lineIndicesOf(body, issue4).length > 0)
|
|
24163
24302
|
return body;
|
|
@@ -24182,7 +24321,7 @@ function tickLine(body, issue4) {
|
|
|
24182
24321
|
return tickRoadmapLines(body, [checkedIssue(issue4, "tickLine")]).body;
|
|
24183
24322
|
}
|
|
24184
24323
|
function unconfirmedProblem(issue4) {
|
|
24185
|
-
return `${
|
|
24324
|
+
return `${PREFIX18}: issue #${String(issue4)} read back without the edit that was written,` + " so somebody edited it in between";
|
|
24186
24325
|
}
|
|
24187
24326
|
async function attemptEdit(issue4, edit, board, attempt2) {
|
|
24188
24327
|
const answered = { issue: issue4, status: "nothing-to-edit", attempts: attempt2 - 1, problem: "" };
|
|
@@ -24217,7 +24356,7 @@ async function editChecklists(options) {
|
|
|
24217
24356
|
}
|
|
24218
24357
|
return Object.freeze(results);
|
|
24219
24358
|
}
|
|
24220
|
-
var
|
|
24359
|
+
var PREFIX18 = "board epic checklist", BULLET, DEFAULT_BULLET = "- ", LINE_BREAK3, DEFAULT_BREAK = `
|
|
24221
24360
|
`;
|
|
24222
24361
|
var init_epic_checklist = __esm(() => {
|
|
24223
24362
|
init_config_sections();
|
|
@@ -24255,24 +24394,24 @@ async function findEpic(slug, options, output) {
|
|
|
24255
24394
|
const result = await options.gh(args);
|
|
24256
24395
|
if (!result.ok) {
|
|
24257
24396
|
const written = result.stderr.trim() || result.stdout.trim() || "nothing";
|
|
24258
|
-
output.warn(`${
|
|
24397
|
+
output.warn(`${PREFIX19}: ${command} failed (${written}); ${id} is planned without its epic`);
|
|
24259
24398
|
return null;
|
|
24260
24399
|
}
|
|
24261
24400
|
let epics;
|
|
24262
24401
|
try {
|
|
24263
24402
|
epics = parseBoardListing(result.stdout, command);
|
|
24264
24403
|
} catch (error) {
|
|
24265
|
-
output.warn(`${
|
|
24404
|
+
output.warn(`${PREFIX19}: ${messageOf(error)}; ${id} is planned without its epic`);
|
|
24266
24405
|
return null;
|
|
24267
24406
|
}
|
|
24268
24407
|
const [epic, ...others] = epics;
|
|
24269
24408
|
if (epic === undefined) {
|
|
24270
|
-
output.warn(`${
|
|
24409
|
+
output.warn(`${PREFIX19}: ${id} carries "${label}" but no "${EPIC_TYPE_LABEL}" issue does; it is planned without an epic`);
|
|
24271
24410
|
return null;
|
|
24272
24411
|
}
|
|
24273
24412
|
if (others.length > 0) {
|
|
24274
24413
|
const found = numbersOf(epics.map((each) => each.number));
|
|
24275
|
-
output.warn(`${
|
|
24414
|
+
output.warn(`${PREFIX19}: ${id} carries "${label}" and ${String(epics.length)} epics carry it (${found}); it is planned without an epic`);
|
|
24276
24415
|
return null;
|
|
24277
24416
|
}
|
|
24278
24417
|
return Object.freeze({ number: epic.number, title: epic.title, slug, criteria: readEpicBody(epic.body).criteria });
|
|
@@ -24284,7 +24423,7 @@ function nativeEpicOn(listing, options, relations, output) {
|
|
|
24284
24423
|
const id = `issue #${String(options.issue)}`;
|
|
24285
24424
|
const row2 = listing.find((each) => each.number === options.issue);
|
|
24286
24425
|
if (row2 === undefined) {
|
|
24287
|
-
output.warn(`${
|
|
24426
|
+
output.warn(`${PREFIX19}: the board listing holds no ${id}; it is planned without its epic`);
|
|
24288
24427
|
return null;
|
|
24289
24428
|
}
|
|
24290
24429
|
const epicOf2 = relations.read(listing).epicOf(row2);
|
|
@@ -24292,7 +24431,7 @@ function nativeEpicOn(listing, options, relations, output) {
|
|
|
24292
24431
|
return null;
|
|
24293
24432
|
if (epicOf2.kind === "unresolved") {
|
|
24294
24433
|
const marks = epicOf2.marks.map((each) => each.mark).join(", ");
|
|
24295
|
-
output.warn(`${
|
|
24434
|
+
output.warn(`${PREFIX19}: ${id}'s parent ${marks} is no epic on the board; it is planned without an epic`);
|
|
24296
24435
|
return null;
|
|
24297
24436
|
}
|
|
24298
24437
|
const epic = listing.find((each) => each.number === epicOf2.epic);
|
|
@@ -24305,7 +24444,7 @@ async function readNativeEpicContext(options, relations) {
|
|
|
24305
24444
|
try {
|
|
24306
24445
|
return nativeEpicOn(await nativeListing(options), options, relations, output);
|
|
24307
24446
|
} catch (error) {
|
|
24308
|
-
output.warn(`${
|
|
24447
|
+
output.warn(`${PREFIX19}: ${messageOf(error)}; issue #${String(options.issue)} is planned without its epic`);
|
|
24309
24448
|
return null;
|
|
24310
24449
|
}
|
|
24311
24450
|
}
|
|
@@ -24320,12 +24459,12 @@ async function readEpicContext(options) {
|
|
|
24320
24459
|
const output = options.output ?? activeOutput();
|
|
24321
24460
|
if (others.length > 0) {
|
|
24322
24461
|
const labels = slugs.map((each) => `"${EPIC_LABEL_PREFIX}${each}"`).join(", ");
|
|
24323
|
-
output.warn(`${
|
|
24462
|
+
output.warn(`${PREFIX19}: issue #${String(options.issue)} carries ${String(slugs.length)} epic labels (${labels}); it is planned without an epic`);
|
|
24324
24463
|
return null;
|
|
24325
24464
|
}
|
|
24326
24465
|
return findEpic(slug, options, output);
|
|
24327
24466
|
}
|
|
24328
|
-
var EPIC_TYPE_LABEL = "type:epic", EPIC_CONTEXT_LIMIT = 20,
|
|
24467
|
+
var EPIC_TYPE_LABEL = "type:epic", EPIC_CONTEXT_LIMIT = 20, PREFIX19 = "epic context";
|
|
24329
24468
|
var init_epic_context = __esm(() => {
|
|
24330
24469
|
init_active();
|
|
24331
24470
|
init_config_sections();
|
|
@@ -24514,32 +24653,32 @@ function detailOf11(result, command) {
|
|
|
24514
24653
|
async function rowsOf3(gh, args, command) {
|
|
24515
24654
|
const result = await gh(args);
|
|
24516
24655
|
if (!result.ok)
|
|
24517
|
-
throw new Error(`${
|
|
24656
|
+
throw new Error(`${PREFIX20}: ${detailOf11(result, command)}`);
|
|
24518
24657
|
let parsed;
|
|
24519
24658
|
try {
|
|
24520
24659
|
parsed = JSON.parse(result.stdout);
|
|
24521
24660
|
} catch (error) {
|
|
24522
|
-
throw new Error(`${
|
|
24661
|
+
throw new Error(`${PREFIX20}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
|
|
24523
24662
|
}
|
|
24524
24663
|
if (!Array.isArray(parsed)) {
|
|
24525
|
-
throw new Error(`${
|
|
24664
|
+
throw new Error(`${PREFIX20}: ${command} answered ${describeValue(parsed)}, expected a list of issues`);
|
|
24526
24665
|
}
|
|
24527
24666
|
return parsed;
|
|
24528
24667
|
}
|
|
24529
24668
|
function rowNumber3(row2, command, where) {
|
|
24530
24669
|
if (!isMapping(row2)) {
|
|
24531
|
-
throw new Error(`${
|
|
24670
|
+
throw new Error(`${PREFIX20}: ${command} answered ${where} as ${describeValue(row2)}, expected a mapping`);
|
|
24532
24671
|
}
|
|
24533
24672
|
const number = row2["number"];
|
|
24534
24673
|
if (typeof number !== "number" || !Number.isSafeInteger(number) || number < 1) {
|
|
24535
|
-
throw new Error(`${
|
|
24674
|
+
throw new Error(`${PREFIX20}: ${command} answered ${where}.number as ${describeValue(number)}, expected a positive whole number`);
|
|
24536
24675
|
}
|
|
24537
24676
|
return number;
|
|
24538
24677
|
}
|
|
24539
24678
|
function rowBody(row2, command, where) {
|
|
24540
24679
|
const body = isMapping(row2) ? row2["body"] : null;
|
|
24541
24680
|
if (typeof body !== "string") {
|
|
24542
|
-
throw new Error(`${
|
|
24681
|
+
throw new Error(`${PREFIX20}: ${command} answered ${where}.body as ${describeValue(body)}, expected a string`);
|
|
24543
24682
|
}
|
|
24544
24683
|
return body;
|
|
24545
24684
|
}
|
|
@@ -24604,7 +24743,7 @@ function renderBlockedIssues(report) {
|
|
|
24604
24743
|
const unchecked = report.unchecked === null ? [] : [` ${report.unchecked}`];
|
|
24605
24744
|
return [BLOCKED_HEADING, ...body, ...unchecked];
|
|
24606
24745
|
}
|
|
24607
|
-
var BLOCKED_HEADING = "Blocked issues:", BLOCKED_LIST_LIMIT = 100, KNOWN_LIST_LIMIT = 500,
|
|
24746
|
+
var BLOCKED_HEADING = "Blocked issues:", BLOCKED_LIST_LIMIT = 100, KNOWN_LIST_LIMIT = 500, PREFIX20 = "board blocked", BLOCKED_ARGS, BLOCKED_COMMAND, KNOWN_ARGS, KNOWN_COMMAND;
|
|
24608
24747
|
var init_doctor_blocked = __esm(() => {
|
|
24609
24748
|
init_blocked();
|
|
24610
24749
|
init_config_sections();
|
|
@@ -24675,11 +24814,11 @@ async function resolveTracker(options) {
|
|
|
24675
24814
|
}
|
|
24676
24815
|
attempts = [...attempts, Object.freeze({ kind, ok: false, reason: outcome.reason })];
|
|
24677
24816
|
failures = [...failures, `${kind}: ${outcome.reason}`];
|
|
24678
|
-
log(`${
|
|
24817
|
+
log(`${PREFIX21}: ${kind} unavailable: ${outcome.reason}`);
|
|
24679
24818
|
}
|
|
24680
|
-
throw new Error(`${
|
|
24819
|
+
throw new Error(`${PREFIX21}: no tracker available; tried ${failures.join(FAILURE_SEPARATOR)}`);
|
|
24681
24820
|
}
|
|
24682
|
-
var
|
|
24821
|
+
var PREFIX21 = "tracker chain", FAILURE_SEPARATOR = "; ";
|
|
24683
24822
|
var init_resolve2 = __esm(() => {
|
|
24684
24823
|
init_config_sections();
|
|
24685
24824
|
init_active();
|
|
@@ -24825,32 +24964,32 @@ function detailOf12(result, command) {
|
|
|
24825
24964
|
async function rowsOf4(gh, args, command) {
|
|
24826
24965
|
const result = await gh(args);
|
|
24827
24966
|
if (!result.ok)
|
|
24828
|
-
throw new Error(`${
|
|
24967
|
+
throw new Error(`${PREFIX22}: ${detailOf12(result, command)}`);
|
|
24829
24968
|
let parsed;
|
|
24830
24969
|
try {
|
|
24831
24970
|
parsed = JSON.parse(result.stdout);
|
|
24832
24971
|
} catch (error) {
|
|
24833
|
-
throw new Error(`${
|
|
24972
|
+
throw new Error(`${PREFIX22}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
|
|
24834
24973
|
}
|
|
24835
24974
|
if (!Array.isArray(parsed)) {
|
|
24836
|
-
throw new Error(`${
|
|
24975
|
+
throw new Error(`${PREFIX22}: ${command} answered ${describeValue(parsed)}, expected a list of issues`);
|
|
24837
24976
|
}
|
|
24838
24977
|
return parsed;
|
|
24839
24978
|
}
|
|
24840
24979
|
function rowNumber4(row2, command, where) {
|
|
24841
24980
|
if (!isMapping(row2)) {
|
|
24842
|
-
throw new Error(`${
|
|
24981
|
+
throw new Error(`${PREFIX22}: ${command} answered ${where} as ${describeValue(row2)}, expected a mapping`);
|
|
24843
24982
|
}
|
|
24844
24983
|
const number = row2["number"];
|
|
24845
24984
|
if (typeof number !== "number" || !Number.isSafeInteger(number) || number < 1) {
|
|
24846
|
-
throw new Error(`${
|
|
24985
|
+
throw new Error(`${PREFIX22}: ${command} answered ${where}.number as ${describeValue(number)}, expected a positive whole number`);
|
|
24847
24986
|
}
|
|
24848
24987
|
return number;
|
|
24849
24988
|
}
|
|
24850
24989
|
function rowBody2(row2, command, where) {
|
|
24851
24990
|
const body = isMapping(row2) ? row2["body"] : null;
|
|
24852
24991
|
if (typeof body !== "string") {
|
|
24853
|
-
throw new Error(`${
|
|
24992
|
+
throw new Error(`${PREFIX22}: ${command} answered ${where}.body as ${describeValue(body)}, expected a string`);
|
|
24854
24993
|
}
|
|
24855
24994
|
return body;
|
|
24856
24995
|
}
|
|
@@ -25129,7 +25268,7 @@ function createIssueUnblockCommand(seams = DEFAULT_UNBLOCK_SEAMS) {
|
|
|
25129
25268
|
};
|
|
25130
25269
|
return Object.freeze(command);
|
|
25131
25270
|
}
|
|
25132
|
-
var UNBLOCK_USAGE = "rafa issue unblock [<n>] [--all]", ALL_FLAG = "all", ISSUE_NUMBER3, YES_ANSWERS2,
|
|
25271
|
+
var UNBLOCK_USAGE = "rafa issue unblock [<n>] [--all]", ALL_FLAG = "all", ISSUE_NUMBER3, YES_ANSWERS2, PREFIX22 = "board unblock", BLOCKED_ARGS2, BLOCKED_COMMAND2, STATE_ARGS, STATE_COMMAND, DEFAULT_UNBLOCK_SEAMS, WARNED, unblock_default;
|
|
25133
25272
|
var init_unblock = __esm(() => {
|
|
25134
25273
|
init_github();
|
|
25135
25274
|
init_blocked();
|
|
@@ -25314,14 +25453,14 @@ function ref(issue4) {
|
|
|
25314
25453
|
}
|
|
25315
25454
|
function issueNumber4(value, member) {
|
|
25316
25455
|
if (!Number.isSafeInteger(value) || value < 1) {
|
|
25317
|
-
throw new TypeError(`${
|
|
25456
|
+
throw new TypeError(`${PREFIX23}: ${member} refused issue number ${describeValue(value)}, expected a positive whole number`);
|
|
25318
25457
|
}
|
|
25319
25458
|
return value;
|
|
25320
25459
|
}
|
|
25321
25460
|
function rowOf3(listing, issue4, member) {
|
|
25322
25461
|
const row2 = listing.find((candidate) => candidate.number === issue4);
|
|
25323
25462
|
if (row2 === undefined) {
|
|
25324
|
-
throw new Error(`${
|
|
25463
|
+
throw new Error(`${PREFIX23}: ${member} refused ${ref(issue4)}, which is not on the board listing, so nothing was changed`);
|
|
25325
25464
|
}
|
|
25326
25465
|
return row2;
|
|
25327
25466
|
}
|
|
@@ -25331,7 +25470,7 @@ function detailOf13(result) {
|
|
|
25331
25470
|
async function sendRelationship(gh, args, what) {
|
|
25332
25471
|
const result = await gh(args);
|
|
25333
25472
|
if (!result.ok)
|
|
25334
|
-
throw new Error(`${
|
|
25473
|
+
throw new Error(`${PREFIX23}: ${what} was refused, so nothing was changed: ${detailOf13(result)}`);
|
|
25335
25474
|
}
|
|
25336
25475
|
function labelEditArgs(issue4, removed, added) {
|
|
25337
25476
|
return [
|
|
@@ -25361,7 +25500,7 @@ function ownersOf(listing, slug) {
|
|
|
25361
25500
|
function memberRow(listing, issue4, member) {
|
|
25362
25501
|
const row2 = rowOf3(listing, issueNumber4(issue4, member), member);
|
|
25363
25502
|
if (row2.type === "epic") {
|
|
25364
|
-
throw new Error(`${
|
|
25503
|
+
throw new Error(`${PREFIX23}: ${member} refused ${ref(issue4)}, which is an epic, and an epic belongs to no epic; nothing was changed`);
|
|
25365
25504
|
}
|
|
25366
25505
|
return row2;
|
|
25367
25506
|
}
|
|
@@ -25369,7 +25508,7 @@ function targetSlug(listing, parent) {
|
|
|
25369
25508
|
const row2 = rowOf3(listing, issueNumber4(parent, "setParent"), "setParent");
|
|
25370
25509
|
const slug = epicSlugsOf(row2.labels)[0];
|
|
25371
25510
|
if (row2.type !== "epic" || slug === undefined) {
|
|
25372
|
-
throw new Error(`${
|
|
25511
|
+
throw new Error(`${PREFIX23}: setParent refused epic ${ref(parent)}, which is not an epic carrying an ${EPIC_LABEL_PREFIX}` + " label, so it has no label to give; nothing was changed");
|
|
25373
25512
|
}
|
|
25374
25513
|
return slug;
|
|
25375
25514
|
}
|
|
@@ -25423,7 +25562,7 @@ function waitingRow(listing, change, member) {
|
|
|
25423
25562
|
const row2 = rowOf3(listing, issueNumber4(change.issue, member), member);
|
|
25424
25563
|
issueNumber4(change.blocker.number, member);
|
|
25425
25564
|
if (change.blocker.repository === null && change.blocker.number === row2.number) {
|
|
25426
|
-
throw new Error(`${
|
|
25565
|
+
throw new Error(`${PREFIX23}: ${member} refused to make ${ref(row2.number)} wait on itself; nothing was changed`);
|
|
25427
25566
|
}
|
|
25428
25567
|
return row2;
|
|
25429
25568
|
}
|
|
@@ -25455,7 +25594,7 @@ async function removeLabelsBlocker(seams, listing, change) {
|
|
|
25455
25594
|
await sendRelationship(seams.gh, args, what);
|
|
25456
25595
|
return [written(row2.number, what, "written")];
|
|
25457
25596
|
}
|
|
25458
|
-
var
|
|
25597
|
+
var PREFIX23 = "board relations labels", NO_CLAIMS2, UNREAD_DAY2;
|
|
25459
25598
|
var init_labels_writes = __esm(() => {
|
|
25460
25599
|
init_config_sections();
|
|
25461
25600
|
init_blocked();
|
|
@@ -25495,7 +25634,7 @@ function epicOf3(issue4, owners) {
|
|
|
25495
25634
|
}
|
|
25496
25635
|
function membersOf(epic, listing, epics) {
|
|
25497
25636
|
if (epic.type !== "epic") {
|
|
25498
|
-
throw new TypeError(`${
|
|
25637
|
+
throw new TypeError(`${PREFIX24}: membersOf refused #${String(epic.number)}, which is not typed epic, so it has no members`);
|
|
25499
25638
|
}
|
|
25500
25639
|
const read = epics.find((candidate) => candidate.number === epic.number) ?? epicsOf([...listing, epic]).find((candidate) => candidate.number === epic.number);
|
|
25501
25640
|
const members = read?.members ?? [];
|
|
@@ -25606,7 +25745,7 @@ function createLabelsRelations(options) {
|
|
|
25606
25745
|
};
|
|
25607
25746
|
return Object.freeze(relations);
|
|
25608
25747
|
}
|
|
25609
|
-
var
|
|
25748
|
+
var PREFIX24 = "board relations labels", NO_CLAIMS3, UNREAD_DAY3, FOREIGN_TOKEN, LABELS_READS;
|
|
25610
25749
|
var init_labels2 = __esm(() => {
|
|
25611
25750
|
init_merge_tick();
|
|
25612
25751
|
init_merge_unblock();
|
|
@@ -25874,11 +26013,11 @@ function summaryState(summary, members, claims) {
|
|
|
25874
26013
|
}
|
|
25875
26014
|
function withSubIssuesSummary(epic, row2, claims, today) {
|
|
25876
26015
|
if (row2.number !== epic.number) {
|
|
25877
|
-
throw new TypeError(`${
|
|
26016
|
+
throw new TypeError(`${PREFIX25}: row #${String(row2.number)} is not epic #${String(epic.number)}'s row`);
|
|
25878
26017
|
}
|
|
25879
26018
|
const summary = row2.subIssuesSummary;
|
|
25880
26019
|
if (summary === undefined) {
|
|
25881
|
-
throw new TypeError(`${
|
|
26020
|
+
throw new TypeError(`${PREFIX25}: epic #${String(epic.number)} was read without subIssuesSummary; ` + "board.relationships is native, so the listing must be read with the native fields");
|
|
25882
26021
|
}
|
|
25883
26022
|
const progress = Object.freeze({
|
|
25884
26023
|
done: summary.completed,
|
|
@@ -25895,7 +26034,7 @@ function withSubIssuesSummary(epic, row2, claims, today) {
|
|
|
25895
26034
|
disagreement: disagreementOf(epic.number, state, epic.stored)
|
|
25896
26035
|
});
|
|
25897
26036
|
}
|
|
25898
|
-
var
|
|
26037
|
+
var PREFIX25 = "board epic summary";
|
|
25899
26038
|
var init_epic_summary = __esm(() => {
|
|
25900
26039
|
init_epics();
|
|
25901
26040
|
});
|
|
@@ -26438,7 +26577,7 @@ function ref4(issue4) {
|
|
|
26438
26577
|
}
|
|
26439
26578
|
function issueNumber5(value, member) {
|
|
26440
26579
|
if (!Number.isSafeInteger(value) || value < 1) {
|
|
26441
|
-
throw new TypeError(`${
|
|
26580
|
+
throw new TypeError(`${PREFIX26}: ${member} refused issue number ${describeValue(value)}, expected a positive whole number`);
|
|
26442
26581
|
}
|
|
26443
26582
|
return value;
|
|
26444
26583
|
}
|
|
@@ -26449,17 +26588,17 @@ function rowOf5(listing, issue4, member) {
|
|
|
26449
26588
|
const number = issueNumber5(issue4, member);
|
|
26450
26589
|
const row2 = listing.find((candidate) => candidate.number === number);
|
|
26451
26590
|
if (row2 === undefined) {
|
|
26452
|
-
throw new Error(`${
|
|
26591
|
+
throw new Error(`${PREFIX26}: ${member} refused ${ref4(issue4)}, which is not on the board listing, so nothing was changed`);
|
|
26453
26592
|
}
|
|
26454
26593
|
if (!Object.hasOwn(row2, "parent") || !Object.hasOwn(row2, "blockedBy")) {
|
|
26455
|
-
throw new TypeError(`${
|
|
26594
|
+
throw new TypeError(`${PREFIX26}: ${member} refused ${ref4(issue4)}, which was read without parent and blockedBy; ` + "board.relationships is native, so the listing must be read with the native fields");
|
|
26456
26595
|
}
|
|
26457
26596
|
return { row: row2, fields: { parent: row2.parent ?? null, blockedBy: row2.blockedBy ?? { nodes: [] } } };
|
|
26458
26597
|
}
|
|
26459
26598
|
function memberRow2(listing, issue4, member) {
|
|
26460
26599
|
const found = rowOf5(listing, issue4, member);
|
|
26461
26600
|
if (found.row.type === "epic") {
|
|
26462
|
-
throw new Error(`${
|
|
26601
|
+
throw new Error(`${PREFIX26}: ${member} refused ${ref4(issue4)}, which is an epic, and an epic belongs to no epic; nothing was changed`);
|
|
26463
26602
|
}
|
|
26464
26603
|
return found;
|
|
26465
26604
|
}
|
|
@@ -26467,7 +26606,7 @@ function targetEpic(listing, parent) {
|
|
|
26467
26606
|
const number = issueNumber5(parent, "setParent");
|
|
26468
26607
|
const row2 = listing.find((candidate) => candidate.number === number);
|
|
26469
26608
|
if (row2?.type !== "epic") {
|
|
26470
|
-
throw new Error(`${
|
|
26609
|
+
throw new Error(`${PREFIX26}: setParent refused epic ${ref4(parent)}, which is not an issue typed epic on the board listing;` + " nothing was changed");
|
|
26471
26610
|
}
|
|
26472
26611
|
return row2.number;
|
|
26473
26612
|
}
|
|
@@ -26477,7 +26616,7 @@ function normalBlocker(blocker, board, member) {
|
|
|
26477
26616
|
if (repository === null || isBoard(repository, board))
|
|
26478
26617
|
return { number, repository: null };
|
|
26479
26618
|
if (!REPOSITORY.test(repository)) {
|
|
26480
|
-
throw new TypeError(`${
|
|
26619
|
+
throw new TypeError(`${PREFIX26}: ${member} refused blocker repository "${repository}", which is not owner/name`);
|
|
26481
26620
|
}
|
|
26482
26621
|
return { number, repository };
|
|
26483
26622
|
}
|
|
@@ -26499,7 +26638,7 @@ function written2(issue4, what, status) {
|
|
|
26499
26638
|
async function send(gh, issue4, flags, what) {
|
|
26500
26639
|
const result = await gh(["issue", "edit", String(issue4), ...flags]);
|
|
26501
26640
|
if (!result.ok)
|
|
26502
|
-
throw new Error(`${
|
|
26641
|
+
throw new Error(`${PREFIX26}: ${what} was refused, so nothing was changed: ${detailOf14(result)}`);
|
|
26503
26642
|
return written2(issue4, what, "written");
|
|
26504
26643
|
}
|
|
26505
26644
|
async function setNativeParent(seams, listing, change) {
|
|
@@ -26523,7 +26662,7 @@ function blockerWrite(seams, listing, change, member) {
|
|
|
26523
26662
|
const { row: row2, fields } = rowOf5(listing, change.issue, member);
|
|
26524
26663
|
const blocker = normalBlocker(change.blocker, seams.repository, member);
|
|
26525
26664
|
if (blocker.repository === null && blocker.number === row2.number) {
|
|
26526
|
-
throw new Error(`${
|
|
26665
|
+
throw new Error(`${PREFIX26}: ${member} refused to make ${ref4(row2.number)} wait on itself; nothing was changed`);
|
|
26527
26666
|
}
|
|
26528
26667
|
return { row: row2, fields, blocker };
|
|
26529
26668
|
}
|
|
@@ -26543,7 +26682,7 @@ async function removeNativeBlocker(seams, listing, change) {
|
|
|
26543
26682
|
}
|
|
26544
26683
|
return send(seams.gh, row2.number, ["--remove-blocked-by", blockerArg(blocker)], what);
|
|
26545
26684
|
}
|
|
26546
|
-
var
|
|
26685
|
+
var PREFIX26 = "board relations native", REPOSITORY, GITHUB_HOST2 = "https://github.com";
|
|
26547
26686
|
var init_native_writes = __esm(() => {
|
|
26548
26687
|
init_config_sections();
|
|
26549
26688
|
REPOSITORY = /^[^/\s]+\/[^/\s]+$/u;
|
|
@@ -26553,7 +26692,7 @@ var init_native_writes = __esm(() => {
|
|
|
26553
26692
|
function nativeFieldsOf(row2) {
|
|
26554
26693
|
const missing2 = NATIVE_KEYS.filter((key) => !Object.hasOwn(row2, key));
|
|
26555
26694
|
if (missing2.length > 0) {
|
|
26556
|
-
throw new TypeError(`${
|
|
26695
|
+
throw new TypeError(`${PREFIX27}: issue #${String(row2.number)} was read without ${missing2.join(", ")}; ` + "board.relationships is native, so the listing must be read with the native fields");
|
|
26557
26696
|
}
|
|
26558
26697
|
return { parent: row2.parent ?? null, blockedBy: row2.blockedBy ?? { nodes: [] }, subIssues: row2.subIssues ?? { nodes: [] } };
|
|
26559
26698
|
}
|
|
@@ -26587,7 +26726,7 @@ function isChildOf(row2, epic, board) {
|
|
|
26587
26726
|
}
|
|
26588
26727
|
function membersOf3(epic, listing, board) {
|
|
26589
26728
|
if (epic.type !== "epic") {
|
|
26590
|
-
throw new TypeError(`${
|
|
26729
|
+
throw new TypeError(`${PREFIX27}: membersOf refused #${String(epic.number)}, which is not typed epic, so it has no members`);
|
|
26591
26730
|
}
|
|
26592
26731
|
const { subIssues } = nativeFieldsOf(epic);
|
|
26593
26732
|
const children = listing.filter((row2) => row2.type !== "epic" && isChildOf(row2, epic.number, board));
|
|
@@ -26630,7 +26769,7 @@ function afterNativeMerge() {
|
|
|
26630
26769
|
function createNativeRelations(options) {
|
|
26631
26770
|
const { repository } = options;
|
|
26632
26771
|
if (!REPOSITORY2.test(repository)) {
|
|
26633
|
-
throw new TypeError(`${
|
|
26772
|
+
throw new TypeError(`${PREFIX27}: the board's repository "${repository}" is not owner/name`);
|
|
26634
26773
|
}
|
|
26635
26774
|
const seams = { gh: options.gh, repository };
|
|
26636
26775
|
const relations = {
|
|
@@ -26645,7 +26784,7 @@ function createNativeRelations(options) {
|
|
|
26645
26784
|
};
|
|
26646
26785
|
return Object.freeze(relations);
|
|
26647
26786
|
}
|
|
26648
|
-
var
|
|
26787
|
+
var PREFIX27 = "board relations native", NATIVE_KEYS, REPOSITORY2;
|
|
26649
26788
|
var init_native = __esm(() => {
|
|
26650
26789
|
init_roadmap_board();
|
|
26651
26790
|
init_freed();
|
|
@@ -26966,7 +27105,7 @@ function readSavedCopy(absolute, path2) {
|
|
|
26966
27105
|
return null;
|
|
26967
27106
|
return { text: readFileSync31(absolute, "utf8"), savedAt: stat.mtime };
|
|
26968
27107
|
} catch (error) {
|
|
26969
|
-
throw new Error(`${
|
|
27108
|
+
throw new Error(`${PREFIX28}: the saved copy ${path2} could not be read: ${messageOf(error)}`, { cause: error });
|
|
26970
27109
|
}
|
|
26971
27110
|
}
|
|
26972
27111
|
function printChange(change, output) {
|
|
@@ -27008,7 +27147,7 @@ async function settleSpecSnapshot(options) {
|
|
|
27008
27147
|
throw new CommandExit(ISSUE_REFUSAL_EXIT, snapshotDiffersMessage(path2, issue4.number));
|
|
27009
27148
|
return write(true);
|
|
27010
27149
|
}
|
|
27011
|
-
var
|
|
27150
|
+
var PREFIX28 = "board snapshot settle", DATE_LENGTH = 10;
|
|
27012
27151
|
var init_snapshot_settle = __esm(() => {
|
|
27013
27152
|
init_command();
|
|
27014
27153
|
init_config_sections();
|
|
@@ -27243,7 +27382,7 @@ async function walkPlaceEpic(number, listing, readings, relations) {
|
|
|
27243
27382
|
const read = readEpics({ issues: rows2, claims: new Set, today: new Date(0), relations }).epics.find((candidate) => candidate.number === number);
|
|
27244
27383
|
const row2 = rows2.find((issue4) => issue4.number === number);
|
|
27245
27384
|
if (read === undefined || row2 === undefined) {
|
|
27246
|
-
throw new Error(`${
|
|
27385
|
+
throw new Error(`${PREFIX29}: epic #${String(number)}, the current place, is not on the board listing, so its members cannot be read`);
|
|
27247
27386
|
}
|
|
27248
27387
|
const { checklist, labelOnly, lines } = epicLines(read, row2);
|
|
27249
27388
|
const epic = Object.freeze({
|
|
@@ -27380,7 +27519,7 @@ async function settleBlockedPick(options) {
|
|
|
27380
27519
|
}
|
|
27381
27520
|
return { issue: plannable.line.issue };
|
|
27382
27521
|
}
|
|
27383
|
-
var
|
|
27522
|
+
var PREFIX29 = "board spec source roadmap";
|
|
27384
27523
|
var init_spec_source_roadmap = __esm(() => {
|
|
27385
27524
|
init_hop_record();
|
|
27386
27525
|
init_position();
|
|
@@ -27479,7 +27618,7 @@ function dryRunLine(what) {
|
|
|
27479
27618
|
}
|
|
27480
27619
|
function requireRoadmapSeams(seams) {
|
|
27481
27620
|
if (seams === undefined) {
|
|
27482
|
-
throw new TypeError(`${
|
|
27621
|
+
throw new TypeError(`${PREFIX30}: ${NEXT_FLAG} was resolved with no roadmap seams`);
|
|
27483
27622
|
}
|
|
27484
27623
|
return seams;
|
|
27485
27624
|
}
|
|
@@ -27570,7 +27709,7 @@ async function resolveSpecSource(options) {
|
|
|
27570
27709
|
})
|
|
27571
27710
|
});
|
|
27572
27711
|
}
|
|
27573
|
-
var
|
|
27712
|
+
var PREFIX30 = "board spec source", SOURCE_FLAGS, SOURCE_REFUSAL_EXIT = 1, ROADMAP_REFUSAL_EXIT2 = 2;
|
|
27574
27713
|
var init_spec_source = __esm(() => {
|
|
27575
27714
|
init_active();
|
|
27576
27715
|
init_ahead();
|
|
@@ -33103,7 +33242,7 @@ async function walkEpic(epic, listing, readings, picker, relations) {
|
|
|
33103
33242
|
const read = readEpics({ issues: rows2, claims: new Set, today: new Date(0), relations }).epics.find((candidate) => candidate.number === epic);
|
|
33104
33243
|
const row2 = rows2.find((issue4) => issue4.number === epic);
|
|
33105
33244
|
if (read === undefined || row2 === undefined) {
|
|
33106
|
-
throw new Error(`${
|
|
33245
|
+
throw new Error(`${PREFIX31}: epic #${String(epic)}, the current place, is not on the board listing, so its members cannot be read`);
|
|
33107
33246
|
}
|
|
33108
33247
|
const pick = await picker(epicLines(read, row2).lines, readings, epic);
|
|
33109
33248
|
return {
|
|
@@ -33245,7 +33384,7 @@ function pickerFor(followed, seams) {
|
|
|
33245
33384
|
}
|
|
33246
33385
|
return native ? nativeHopPick(followed, seams) : waitingPick(seams.blocking);
|
|
33247
33386
|
}
|
|
33248
|
-
var
|
|
33387
|
+
var PREFIX31 = "rafa next", plainPick = async (lines, readings) => {
|
|
33249
33388
|
const pick = await pickNextRoadmapLine(lines, readings);
|
|
33250
33389
|
return { line: pick.line, passed: pick.skipped.length, waiting: [] };
|
|
33251
33390
|
}, STOP, PASS2, NOTHING_TAKEN;
|
|
@@ -34952,7 +35091,7 @@ function ghNextBoard(options) {
|
|
|
34952
35091
|
}
|
|
34953
35092
|
function nextProject(context) {
|
|
34954
35093
|
if (context.project === null)
|
|
34955
|
-
throw new Error(`${
|
|
35094
|
+
throw new Error(`${PREFIX32} runs inside a project, and was handed none`);
|
|
34956
35095
|
return context.project;
|
|
34957
35096
|
}
|
|
34958
35097
|
function nextConfig(project, warn2) {
|
|
@@ -34962,7 +35101,7 @@ function nextConfig(project, warn2) {
|
|
|
34962
35101
|
if (!(error instanceof ConfigError))
|
|
34963
35102
|
throw error;
|
|
34964
35103
|
throw new CommandExit(1, [
|
|
34965
|
-
`\u274C ${
|
|
35104
|
+
`\u274C ${PREFIX32}: the config cannot be used:`,
|
|
34966
35105
|
...error.problems.map((problem) => ` ${problem}`)
|
|
34967
35106
|
].join(`
|
|
34968
35107
|
`));
|
|
@@ -35009,7 +35148,7 @@ function openNextSources(context, seams = DEFAULT_NEXT_SOURCE_SEAMS, options = {
|
|
|
35009
35148
|
roots: Object.freeze({ root: project.root, home: project.home })
|
|
35010
35149
|
});
|
|
35011
35150
|
}
|
|
35012
|
-
var
|
|
35151
|
+
var PREFIX32 = "rafa next", DEFAULT_BASE_BRANCH = "main", DEFAULT_NEXT_SOURCE_SEAMS;
|
|
35013
35152
|
var init_sources = __esm(() => {
|
|
35014
35153
|
init_github();
|
|
35015
35154
|
init_boards();
|
|
@@ -36955,7 +37094,7 @@ async function readNextState(sources) {
|
|
|
36955
37094
|
const found = await firstAnswer(world, rows2.filter((row2) => AHEAD_OF_TREE.has(row2.id))) ?? readTreeModified(world) ?? await firstAnswer(world, rows2.filter((row2) => !AHEAD_OF_TREE.has(row2.id)));
|
|
36956
37095
|
if (found !== null)
|
|
36957
37096
|
return answer3(found, world.problems());
|
|
36958
|
-
throw new Error(`${
|
|
37097
|
+
throw new Error(`${PREFIX33}: no row of the table answered, and the last row answers for every reading`);
|
|
36959
37098
|
}
|
|
36960
37099
|
async function readHomeAfterLoop(sources) {
|
|
36961
37100
|
if (sources.roadmap === undefined)
|
|
@@ -36964,7 +37103,7 @@ async function readHomeAfterLoop(sources) {
|
|
|
36964
37103
|
const found = homeAfterLoop(reading2);
|
|
36965
37104
|
return found === null ? null : answer3(found, reading2.problems);
|
|
36966
37105
|
}
|
|
36967
|
-
var
|
|
37106
|
+
var PREFIX33 = "rafa next", NEXT_PRECONDITIONS, ROWS, NEXT_STATES, HOP_ROWS_AHEAD_OF, ROADMAP_ROWS, NEXT_ROADMAP_STATES, AHEAD_OF_TREE;
|
|
36968
37107
|
var init_state = __esm(() => {
|
|
36969
37108
|
init_blocked_line();
|
|
36970
37109
|
init_blocked();
|
|
@@ -37204,7 +37343,7 @@ function passedWords(action, options) {
|
|
|
37204
37343
|
}
|
|
37205
37344
|
function needed(state, value, what) {
|
|
37206
37345
|
if (value === null) {
|
|
37207
|
-
throw new Error(`${
|
|
37346
|
+
throw new Error(`${PREFIX34}: state "${state.id}" proposes "${state.action}" and names no ${what}`);
|
|
37208
37347
|
}
|
|
37209
37348
|
return String(value);
|
|
37210
37349
|
}
|
|
@@ -37221,7 +37360,7 @@ function offeredCommandActions(mode) {
|
|
|
37221
37360
|
return OFFERED_COMMAND_ACTIONS[mode];
|
|
37222
37361
|
}
|
|
37223
37362
|
function notOffered(state, mode) {
|
|
37224
|
-
return new Error(`${
|
|
37363
|
+
return new Error(`${PREFIX34}: state "${state.id}" proposes "${state.action}", which is offered in labels mode only` + ` and board.relationships is ${mode}: the tracker clears a blocker when it closes`);
|
|
37225
37364
|
}
|
|
37226
37365
|
function runsCommand(action) {
|
|
37227
37366
|
return NEXT_COMMAND_ACTIONS.includes(action);
|
|
@@ -37251,13 +37390,13 @@ function actionContext(caller, command, argv) {
|
|
|
37251
37390
|
async function runRegistered(caller, name2, argv, step) {
|
|
37252
37391
|
const command = caller.registry.find(name2.subject, name2.action);
|
|
37253
37392
|
if (command === undefined) {
|
|
37254
|
-
throw new CommandExit(1, `\u274C ${
|
|
37393
|
+
throw new CommandExit(1, `\u274C ${PREFIX34}: the "${step}" step runs "rafa ${commandSpelling(name2)}", which is registered by nothing`);
|
|
37255
37394
|
}
|
|
37256
37395
|
await command.run(actionContext(caller, command, argv));
|
|
37257
37396
|
}
|
|
37258
37397
|
function hopWorld(caller, state) {
|
|
37259
37398
|
if (caller.project === null) {
|
|
37260
|
-
throw new Error(`${
|
|
37399
|
+
throw new Error(`${PREFIX34}: the action "${state.action}" of state "${state.id}" runs inside a project, and was handed none`);
|
|
37261
37400
|
}
|
|
37262
37401
|
return {
|
|
37263
37402
|
root: caller.project.root,
|
|
@@ -37272,7 +37411,7 @@ function hopWorld(caller, state) {
|
|
|
37272
37411
|
};
|
|
37273
37412
|
}
|
|
37274
37413
|
function noStep(state) {
|
|
37275
|
-
return new Error(`${
|
|
37414
|
+
return new Error(`${PREFIX34}: state "${state.id}" proposes "${state.action}" and carries no ${state.action} step`);
|
|
37276
37415
|
}
|
|
37277
37416
|
async function runHopStep(caller, state) {
|
|
37278
37417
|
const step = state.hop;
|
|
@@ -37291,11 +37430,11 @@ async function runAction(caller, state, options = {}) {
|
|
|
37291
37430
|
}
|
|
37292
37431
|
const invocation = actionInvocation(state, options);
|
|
37293
37432
|
if (invocation === null) {
|
|
37294
|
-
throw new Error(`${
|
|
37433
|
+
throw new Error(`${PREFIX34}: the action "${state.action}" of state "${state.id}" runs no registered command`);
|
|
37295
37434
|
}
|
|
37296
37435
|
await runRegistered(caller, ACTION_COMMANDS[invocation.action], invocation.argv, invocation.action);
|
|
37297
37436
|
}
|
|
37298
|
-
var
|
|
37437
|
+
var PREFIX34 = "rafa next", NEXT_IN_PROCESS_ACTIONS, SWITCH_COMMAND, ROADMAP_WORD = "--roadmap", ROADMAP_PASSED_ACTIONS, CLAIM_AHEAD_WORD = "--claim-ahead", ACTION_COMMANDS, NEXT_COMMAND_ACTIONS, LABELS_ONLY_ACTIONS, OFFERED_COMMAND_ACTIONS;
|
|
37299
37438
|
var init_actions = __esm(() => {
|
|
37300
37439
|
init_command();
|
|
37301
37440
|
init_hint();
|
|
@@ -39021,7 +39160,7 @@ function moveBlockers(readings, issue4) {
|
|
|
39021
39160
|
}
|
|
39022
39161
|
function planRelationsMove(listing2, from, to) {
|
|
39023
39162
|
if (from.mode === to.mode) {
|
|
39024
|
-
throw new TypeError(`${
|
|
39163
|
+
throw new TypeError(`${PREFIX35}: refused to move a board from ${from.mode} to ${to.mode}; the two modes must differ`);
|
|
39025
39164
|
}
|
|
39026
39165
|
const readings = { from: from.read(listing2), to: to.read(listing2), fromMode: from.mode, toMode: to.mode };
|
|
39027
39166
|
const members = epicsOf2(listing2).reduce((draft, epic) => joined(draft, to.mode === "native" ? toNativeMembers(readings, epic) : toLabelsMembers(readings, epic)), EMPTY2);
|
|
@@ -39157,7 +39296,7 @@ async function writeRelationsMove(seams, plan) {
|
|
|
39157
39296
|
const marks = await sendInOrder(plan.marks, (mark) => removeMark(seams.gh, bodies, mark));
|
|
39158
39297
|
return result(writes, true, marks);
|
|
39159
39298
|
}
|
|
39160
|
-
var
|
|
39299
|
+
var PREFIX35 = "board relations move", EMPTY2;
|
|
39161
39300
|
var init_move = __esm(() => {
|
|
39162
39301
|
init_blocked();
|
|
39163
39302
|
init_epic_checklist();
|
|
@@ -51302,6 +51441,643 @@ var init_create = __esm(() => {
|
|
|
51302
51441
|
create_default = createIssueCreateCommand();
|
|
51303
51442
|
});
|
|
51304
51443
|
|
|
51444
|
+
// src/board/issue-edit-body.ts
|
|
51445
|
+
function trimmedText(text2, what) {
|
|
51446
|
+
const trimmed = text2.replace(TRAILING_WHITESPACE, "");
|
|
51447
|
+
if (trimmed.trim() === "")
|
|
51448
|
+
throw new RangeError(`${what} holds nothing but whitespace`);
|
|
51449
|
+
return trimmed;
|
|
51450
|
+
}
|
|
51451
|
+
function renderUpdateHeading(now, reason) {
|
|
51452
|
+
const normalised = normaliseReason(reason);
|
|
51453
|
+
if (normalised === "")
|
|
51454
|
+
throw new RangeError("the reason holds nothing but whitespace");
|
|
51455
|
+
return `**Updated ${localDay(now)}, ${normalised}:**`;
|
|
51456
|
+
}
|
|
51457
|
+
function renderUpdateBlock(now, reason, text2) {
|
|
51458
|
+
return `${renderUpdateHeading(now, reason)}
|
|
51459
|
+
|
|
51460
|
+
${trimmedText(text2, "the added text")}`;
|
|
51461
|
+
}
|
|
51462
|
+
function separatorAfter(body) {
|
|
51463
|
+
if (body === "" || body.endsWith(`
|
|
51464
|
+
|
|
51465
|
+
`))
|
|
51466
|
+
return "";
|
|
51467
|
+
return body.endsWith(`
|
|
51468
|
+
`) ? `
|
|
51469
|
+
` : `
|
|
51470
|
+
|
|
51471
|
+
`;
|
|
51472
|
+
}
|
|
51473
|
+
function appendedBody(body, block2) {
|
|
51474
|
+
return `${body}${separatorAfter(body)}${block2}`;
|
|
51475
|
+
}
|
|
51476
|
+
function replacedBody(text2) {
|
|
51477
|
+
return trimmedText(text2, "the replacing text");
|
|
51478
|
+
}
|
|
51479
|
+
function carriesUpdateBlock(body, block2) {
|
|
51480
|
+
const trimmed = body.replace(TRAILING_WHITESPACE, "");
|
|
51481
|
+
if (!trimmed.endsWith(block2))
|
|
51482
|
+
return false;
|
|
51483
|
+
const before = trimmed.slice(0, trimmed.length - block2.length);
|
|
51484
|
+
return before === "" || before.endsWith(`
|
|
51485
|
+
`);
|
|
51486
|
+
}
|
|
51487
|
+
function originalPartHolds(before, after, block2) {
|
|
51488
|
+
if (!after.startsWith(before))
|
|
51489
|
+
return false;
|
|
51490
|
+
const added = after.slice(before.length).replace(TRAILING_WHITESPACE, "");
|
|
51491
|
+
return added === `${separatorAfter(before)}${block2}`;
|
|
51492
|
+
}
|
|
51493
|
+
var TRAILING_WHITESPACE;
|
|
51494
|
+
var init_issue_edit_body = __esm(() => {
|
|
51495
|
+
init_epic_trail();
|
|
51496
|
+
init_epics();
|
|
51497
|
+
TRAILING_WHITESPACE = /\s+$/u;
|
|
51498
|
+
});
|
|
51499
|
+
|
|
51500
|
+
// src/board/issue-edit-state.ts
|
|
51501
|
+
import { readdirSync as readdirSync20, statSync as statSync28 } from "fs";
|
|
51502
|
+
import { join as join81, resolve as resolve36 } from "path";
|
|
51503
|
+
function isClaimed(labels) {
|
|
51504
|
+
return labels.includes(CLAIMED_LABEL) || labels.includes(IN_DEVELOPMENT_LABEL);
|
|
51505
|
+
}
|
|
51506
|
+
function refused4(refusal13, branch = null) {
|
|
51507
|
+
return { pass: false, refusal: refusal13, branch };
|
|
51508
|
+
}
|
|
51509
|
+
function readEditState(input) {
|
|
51510
|
+
if (!input.open)
|
|
51511
|
+
return refused4("closed");
|
|
51512
|
+
if (isClaimed(input.labels)) {
|
|
51513
|
+
const branch = branchName(input.issue, input.title);
|
|
51514
|
+
return input.kind === "append" && input.whileInDevelopment ? { pass: true, staleCopy: true, branch } : refused4("in-development", branch);
|
|
51515
|
+
}
|
|
51516
|
+
const planned = input.savedCopies.length > 0;
|
|
51517
|
+
if (input.kind === "append")
|
|
51518
|
+
return { pass: true, staleCopy: planned, branch: null };
|
|
51519
|
+
if (input.labels.includes(SPEC_READY_LABEL))
|
|
51520
|
+
return refused4("spec-ready");
|
|
51521
|
+
if (planned)
|
|
51522
|
+
return refused4("planned");
|
|
51523
|
+
return { pass: true, staleCopy: false, branch: null };
|
|
51524
|
+
}
|
|
51525
|
+
function refreshCommand(issue4) {
|
|
51526
|
+
return `rafa plan create --issue=${String(issue4)} --refresh`;
|
|
51527
|
+
}
|
|
51528
|
+
function staleCopyMessage(issue4, branch) {
|
|
51529
|
+
const n = String(issue4);
|
|
51530
|
+
const refresh = refreshCommand(issue4);
|
|
51531
|
+
if (branch === null) {
|
|
51532
|
+
return `Issue #${n} has a saved copy this edit makes stale: ${refresh} rebuilds it.`;
|
|
51533
|
+
}
|
|
51534
|
+
return `Issue #${n} is under way on ${branch}: the loop plans from the copy it already has, ` + `and ${refresh} rebuilds that copy.`;
|
|
51535
|
+
}
|
|
51536
|
+
function editName(kind) {
|
|
51537
|
+
if (kind === "append")
|
|
51538
|
+
return "An append to";
|
|
51539
|
+
return kind === "replace" ? "A replace of the body of" : "A title change on";
|
|
51540
|
+
}
|
|
51541
|
+
function appendLine2(issue4, extra) {
|
|
51542
|
+
return `rafa issue edit ${String(issue4)} --append-file=<file> --reason=<text>${extra}`;
|
|
51543
|
+
}
|
|
51544
|
+
function editStateRefusalMessage(input, reading2) {
|
|
51545
|
+
if (reading2.pass)
|
|
51546
|
+
throw new TypeError("issue edit state: a passing reading has no refusal to name");
|
|
51547
|
+
const what = `${editName(input.kind)} issue #${String(input.issue)}`;
|
|
51548
|
+
switch (reading2.refusal) {
|
|
51549
|
+
case "closed":
|
|
51550
|
+
return `${what} is refused: the issue is closed, and rafa edits open issues only.`;
|
|
51551
|
+
case "in-development": {
|
|
51552
|
+
const where = `a loop holds it on ${reading2.branch ?? branchName(input.issue, input.title)}`;
|
|
51553
|
+
return input.kind === "append" ? `${what} is refused: ${where}; add --while-in-development for an amendment the loop must not miss.` : `${what} is refused: ${where}, and a spec under way changes by append: ${appendLine2(input.issue, " --while-in-development")}`;
|
|
51554
|
+
}
|
|
51555
|
+
case "spec-ready":
|
|
51556
|
+
return `${what} is refused: it carries ${SPEC_READY_LABEL}, and a ready spec changes by append: ${appendLine2(input.issue, "")}`;
|
|
51557
|
+
case "planned":
|
|
51558
|
+
return `${what} is refused: it has a saved copy under specs.dir, and a planned spec changes by append: ${appendLine2(input.issue, "")}`;
|
|
51559
|
+
}
|
|
51560
|
+
}
|
|
51561
|
+
function isSavedCopyName(name2, issue4) {
|
|
51562
|
+
const prefix = `${boardId(issue4)}-`;
|
|
51563
|
+
return name2.startsWith(prefix) && name2.endsWith(SPEC_EXTENSION) && name2.length > prefix.length + SPEC_EXTENSION.length && name2 !== notesFileName(issue4);
|
|
51564
|
+
}
|
|
51565
|
+
function findSavedCopies(root, specsDir, issue4) {
|
|
51566
|
+
const dir = resolve36(root, specsDir);
|
|
51567
|
+
let names2;
|
|
51568
|
+
try {
|
|
51569
|
+
names2 = readdirSync20(dir);
|
|
51570
|
+
} catch (error) {
|
|
51571
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
51572
|
+
return [];
|
|
51573
|
+
throw error;
|
|
51574
|
+
}
|
|
51575
|
+
return names2.filter((name2) => isSavedCopyName(name2, issue4)).filter((name2) => statSync28(join81(dir, name2)).isFile()).sort().map((name2) => join81(specsDir, name2));
|
|
51576
|
+
}
|
|
51577
|
+
var init_issue_edit_state = __esm(() => {
|
|
51578
|
+
init_stale();
|
|
51579
|
+
init_naming();
|
|
51580
|
+
init_readiness();
|
|
51581
|
+
});
|
|
51582
|
+
|
|
51583
|
+
// src/board/issue-edit-text.ts
|
|
51584
|
+
function addedTextSource(issue4) {
|
|
51585
|
+
return `the text added to issue #${String(issue4)}`;
|
|
51586
|
+
}
|
|
51587
|
+
function editedBodySource(issue4) {
|
|
51588
|
+
return `issue #${String(issue4)} as edited`;
|
|
51589
|
+
}
|
|
51590
|
+
function completenessApplies(labels, before) {
|
|
51591
|
+
return hasSpecLabel(labels) && findReadinessGaps(before).length === 0;
|
|
51592
|
+
}
|
|
51593
|
+
function requireEditText(input) {
|
|
51594
|
+
requireNoLeak(addedTextSource(input.issue), input.added);
|
|
51595
|
+
if (!completenessApplies(input.labels, input.before))
|
|
51596
|
+
return;
|
|
51597
|
+
requireCompleteSpec(editedBodySource(input.issue), input.after);
|
|
51598
|
+
}
|
|
51599
|
+
var init_issue_edit_text = __esm(() => {
|
|
51600
|
+
init_issue();
|
|
51601
|
+
init_leak();
|
|
51602
|
+
init_readiness();
|
|
51603
|
+
});
|
|
51604
|
+
|
|
51605
|
+
// src/commands/issue/edit-run.ts
|
|
51606
|
+
import { existsSync as existsSync54, mkdirSync as mkdirSync21, writeFileSync as writeFileSync22 } from "fs";
|
|
51607
|
+
import { join as join82 } from "path";
|
|
51608
|
+
function editExitCode(outcome2) {
|
|
51609
|
+
return outcome2 === "conflict" ? EDIT_CONFLICT_EXIT : 0;
|
|
51610
|
+
}
|
|
51611
|
+
function renderReading(reading2) {
|
|
51612
|
+
return `${reading2.gate}: ${reading2.line}`;
|
|
51613
|
+
}
|
|
51614
|
+
function readSwitch3(flags, name2) {
|
|
51615
|
+
const value = flags[name2];
|
|
51616
|
+
if (value === undefined)
|
|
51617
|
+
return false;
|
|
51618
|
+
if (typeof value === "boolean")
|
|
51619
|
+
return value;
|
|
51620
|
+
if (value === "true" || value === "false")
|
|
51621
|
+
return value === "true";
|
|
51622
|
+
throw lineRefusal(`--${name2} takes no value, and read "${value}" as one`, EDIT_USAGE);
|
|
51623
|
+
}
|
|
51624
|
+
function readEditIssue(args) {
|
|
51625
|
+
if (args.length > 1) {
|
|
51626
|
+
throw lineRefusal(`Expected one issue number, got ${String(args.length)}: ${args.join(" ")}`, EDIT_USAGE);
|
|
51627
|
+
}
|
|
51628
|
+
const word = args[0];
|
|
51629
|
+
if (word === undefined)
|
|
51630
|
+
throw lineRefusal("Name the issue number to edit", EDIT_USAGE);
|
|
51631
|
+
if (!ISSUE_NUMBER13.test(word)) {
|
|
51632
|
+
throw lineRefusal(`"${word}" is no issue number, which is a whole number from 1`, EDIT_USAGE);
|
|
51633
|
+
}
|
|
51634
|
+
return Number(word);
|
|
51635
|
+
}
|
|
51636
|
+
function notTogether(first, second, why) {
|
|
51637
|
+
return lineRefusal(`--${first} and --${second} cannot be used together: ${why}`, EDIT_USAGE);
|
|
51638
|
+
}
|
|
51639
|
+
function readEditFlags(flags) {
|
|
51640
|
+
return {
|
|
51641
|
+
appendFile: readNonBlankFlag(flags, FLAG2.appendFile, EDIT_USAGE),
|
|
51642
|
+
append: readNonBlankFlag(flags, FLAG2.append, EDIT_USAGE),
|
|
51643
|
+
reason: readNonBlankFlag(flags, FLAG2.reason, EDIT_USAGE),
|
|
51644
|
+
replaceFile: readNonBlankFlag(flags, FLAG2.replaceFile, EDIT_USAGE),
|
|
51645
|
+
title: readNonBlankFlag(flags, FLAG2.title, EDIT_USAGE),
|
|
51646
|
+
whileInDevelopment: readSwitch3(flags, FLAG2.whileInDevelopment),
|
|
51647
|
+
dryRun: readSwitch3(flags, FLAG2.dryRun)
|
|
51648
|
+
};
|
|
51649
|
+
}
|
|
51650
|
+
function appendLine3(issue4, read) {
|
|
51651
|
+
if (read.appendFile !== undefined && read.append !== undefined) {
|
|
51652
|
+
throw notTogether(FLAG2.appendFile, FLAG2.append, "name the added text one way");
|
|
51653
|
+
}
|
|
51654
|
+
if (read.title !== undefined)
|
|
51655
|
+
throw notTogether(FLAG2.title, FLAG2.append, "a title changes under the gates of a replace");
|
|
51656
|
+
if (read.reason === undefined) {
|
|
51657
|
+
throw lineRefusal(`--${FLAG2.reason} is required with an append: --${FLAG2.reason}=<text>`, EDIT_USAGE);
|
|
51658
|
+
}
|
|
51659
|
+
const source = read.appendFile === undefined ? { from: "line", text: read.append ?? "" } : { from: "file", flag: FLAG2.appendFile, path: read.appendFile };
|
|
51660
|
+
return { ...lineOf3(issue4, read, "append", source), reason: read.reason, whileInDevelopment: read.whileInDevelopment };
|
|
51661
|
+
}
|
|
51662
|
+
function lineOf3(issue4, read, kind, source) {
|
|
51663
|
+
return { issue: issue4, kind, source, reason: null, title: read.title ?? null, whileInDevelopment: false, dryRun: read.dryRun };
|
|
51664
|
+
}
|
|
51665
|
+
function readEditLine(args, flags) {
|
|
51666
|
+
const issue4 = readEditIssue(args);
|
|
51667
|
+
const read = readEditFlags(flags);
|
|
51668
|
+
const appending = read.appendFile !== undefined || read.append !== undefined;
|
|
51669
|
+
if (appending && read.replaceFile !== undefined) {
|
|
51670
|
+
const appendFlag = read.appendFile === undefined ? FLAG2.append : FLAG2.appendFile;
|
|
51671
|
+
throw notTogether(appendFlag, FLAG2.replaceFile, "an edit either appends or replaces");
|
|
51672
|
+
}
|
|
51673
|
+
if (appending)
|
|
51674
|
+
return appendLine3(issue4, read);
|
|
51675
|
+
if (read.reason !== undefined) {
|
|
51676
|
+
throw lineRefusal(`--${FLAG2.reason} goes with an append only: a replace and a title change take none`, EDIT_USAGE);
|
|
51677
|
+
}
|
|
51678
|
+
if (read.whileInDevelopment) {
|
|
51679
|
+
throw lineRefusal(`--${FLAG2.whileInDevelopment} goes with an append only: a spec under way is never replaced or retitled`, EDIT_USAGE);
|
|
51680
|
+
}
|
|
51681
|
+
if (read.replaceFile !== undefined) {
|
|
51682
|
+
return lineOf3(issue4, read, "replace", { from: "file", flag: FLAG2.replaceFile, path: read.replaceFile });
|
|
51683
|
+
}
|
|
51684
|
+
if (read.title !== undefined)
|
|
51685
|
+
return lineOf3(issue4, read, "title", null);
|
|
51686
|
+
throw lineRefusal(`Name the edit: --${FLAG2.appendFile}, --${FLAG2.append}, --${FLAG2.replaceFile} or --${FLAG2.title}`, EDIT_USAGE);
|
|
51687
|
+
}
|
|
51688
|
+
async function readEditText(source, stdin) {
|
|
51689
|
+
if (source.from === "line")
|
|
51690
|
+
return source.text;
|
|
51691
|
+
const where = source.path === STDIN_PATH2 ? "standard input" : `"${source.path}"`;
|
|
51692
|
+
let text2;
|
|
51693
|
+
try {
|
|
51694
|
+
text2 = source.path === STDIN_PATH2 ? await stdin() : await Bun.file(source.path).text();
|
|
51695
|
+
} catch (error) {
|
|
51696
|
+
throw lineRefusal(`--${source.flag} cannot read ${where}: ${messageOf(error)}`, EDIT_USAGE);
|
|
51697
|
+
}
|
|
51698
|
+
if (text2.trim() === "")
|
|
51699
|
+
throw lineRefusal(`--${source.flag} read nothing but whitespace from ${where}`, EDIT_USAGE);
|
|
51700
|
+
return text2;
|
|
51701
|
+
}
|
|
51702
|
+
async function readEditRequest(line, stdin) {
|
|
51703
|
+
const { source, ...rest } = line;
|
|
51704
|
+
if (source === null)
|
|
51705
|
+
return { ...rest, text: null };
|
|
51706
|
+
return { ...rest, text: await readEditText(source, stdin) };
|
|
51707
|
+
}
|
|
51708
|
+
function requireEditingTracker(tracker) {
|
|
51709
|
+
if (holdsEditing(tracker))
|
|
51710
|
+
return tracker;
|
|
51711
|
+
throw new CommandExit(1, `\u274C The ${tracker.kind} tracker cannot edit an issue: it reads and writes no issue body.`);
|
|
51712
|
+
}
|
|
51713
|
+
function holdsEditing(tracker) {
|
|
51714
|
+
return tracker.editable !== undefined && tracker.edit !== undefined;
|
|
51715
|
+
}
|
|
51716
|
+
function planEdit(request, found, now) {
|
|
51717
|
+
const titled = request.title === null ? {} : { title: request.title };
|
|
51718
|
+
if (request.kind === "append") {
|
|
51719
|
+
const block2 = renderUpdateBlock(now, request.reason ?? "", request.text ?? "");
|
|
51720
|
+
const already = carriesUpdateBlock(found.body, block2);
|
|
51721
|
+
const after = already ? found.body : appendedBody(found.body, block2);
|
|
51722
|
+
return { added: request.text ?? "", shown: block2, block: block2, after, already, change: { body: after } };
|
|
51723
|
+
}
|
|
51724
|
+
if (request.kind === "replace") {
|
|
51725
|
+
const body = replacedBody(request.text ?? "");
|
|
51726
|
+
const added = [request.title, body].filter((part) => part !== null).join(`
|
|
51727
|
+
|
|
51728
|
+
`);
|
|
51729
|
+
return { added, shown: added, block: null, after: body, already: false, change: { body, ...titled } };
|
|
51730
|
+
}
|
|
51731
|
+
const title2 = request.title ?? "";
|
|
51732
|
+
return { added: title2, shown: title2, block: null, after: found.body, already: false, change: { title: title2 } };
|
|
51733
|
+
}
|
|
51734
|
+
function trustedLine(reading2, repo) {
|
|
51735
|
+
return reading2.source === "allow-list" ? `${reading2.login}, listed in board.trustedAuthors` : `${reading2.login}, who has write access to ${repo}`;
|
|
51736
|
+
}
|
|
51737
|
+
function gatesFor(request) {
|
|
51738
|
+
const readings = [];
|
|
51739
|
+
return {
|
|
51740
|
+
readings,
|
|
51741
|
+
pass: (gate, line) => {
|
|
51742
|
+
readings.push({ gate, line });
|
|
51743
|
+
},
|
|
51744
|
+
refuse: (refusal13, sentence) => {
|
|
51745
|
+
throw new EditRefusal(refusal13, sentence, [...readings], request.dryRun);
|
|
51746
|
+
}
|
|
51747
|
+
};
|
|
51748
|
+
}
|
|
51749
|
+
async function weighOwnership(options, found, gates) {
|
|
51750
|
+
const { request, tracker } = options;
|
|
51751
|
+
if (tracker.kind === ACCOUNTLESS_KIND) {
|
|
51752
|
+
gates.pass("editor", LOCAL_OWNERSHIP);
|
|
51753
|
+
gates.pass("author", LOCAL_OWNERSHIP);
|
|
51754
|
+
return;
|
|
51755
|
+
}
|
|
51756
|
+
const trust = options.trust();
|
|
51757
|
+
const item = { kind: "issue", number: request.issue, repo: trust.repo };
|
|
51758
|
+
const editor = await readEditorTrust(trust, options.editor);
|
|
51759
|
+
if (!editor.trusted || editor.reading === null) {
|
|
51760
|
+
gates.refuse(editor.refusal ?? "ownership-unknown", editorRefusalMessage(item, editor));
|
|
51761
|
+
}
|
|
51762
|
+
gates.pass("editor", trustedLine(editor.reading, trust.repo));
|
|
51763
|
+
const author = await readBoardTrust(trust, found.author);
|
|
51764
|
+
if (!author.trusted) {
|
|
51765
|
+
const refusal13 = author.refusal === "lookup-failed" ? "ownership-unknown" : "ownership";
|
|
51766
|
+
gates.refuse(refusal13, trustRefusalMessage(item, author));
|
|
51767
|
+
}
|
|
51768
|
+
gates.pass("author", `#${String(request.issue)} was opened by ${trustedLine(author, trust.repo)}`);
|
|
51769
|
+
}
|
|
51770
|
+
function weighText(request, found, planned, gates) {
|
|
51771
|
+
try {
|
|
51772
|
+
requireEditText({
|
|
51773
|
+
issue: request.issue,
|
|
51774
|
+
labels: found.labels,
|
|
51775
|
+
before: found.body,
|
|
51776
|
+
added: planned.added,
|
|
51777
|
+
after: planned.after
|
|
51778
|
+
});
|
|
51779
|
+
} catch (error) {
|
|
51780
|
+
if (error instanceof CommandExit)
|
|
51781
|
+
gates.refuse("text", error.message);
|
|
51782
|
+
throw error;
|
|
51783
|
+
}
|
|
51784
|
+
const complete = completenessApplies(found.labels, found.body) ? ", and the edited body still fills the spec template" : "";
|
|
51785
|
+
gates.pass("text", `the added text names no machine path or credential${complete}`);
|
|
51786
|
+
}
|
|
51787
|
+
function stateLine(input, reading2) {
|
|
51788
|
+
if (reading2.branch !== null) {
|
|
51789
|
+
return `a loop holds it on ${reading2.branch}; --while-in-development lets the append through`;
|
|
51790
|
+
}
|
|
51791
|
+
if (input.savedCopies.length > 0)
|
|
51792
|
+
return `planned, its saved copy at ${input.savedCopies.join(", ")}`;
|
|
51793
|
+
return input.labels.length === 0 ? "open, with no plan and no loop building from it" : `open, labelled ${input.labels.join(", ")}, with no saved copy and no loop building from it`;
|
|
51794
|
+
}
|
|
51795
|
+
function weighState(options, found, gates) {
|
|
51796
|
+
const { request } = options;
|
|
51797
|
+
const input = {
|
|
51798
|
+
issue: request.issue,
|
|
51799
|
+
title: found.title,
|
|
51800
|
+
open: found.open,
|
|
51801
|
+
labels: found.labels,
|
|
51802
|
+
savedCopies: findSavedCopies(options.root, options.specsDir, request.issue),
|
|
51803
|
+
kind: request.kind,
|
|
51804
|
+
whileInDevelopment: request.whileInDevelopment
|
|
51805
|
+
};
|
|
51806
|
+
const reading2 = readEditState(input);
|
|
51807
|
+
if (!reading2.pass)
|
|
51808
|
+
gates.refuse(reading2.refusal, editStateRefusalMessage(input, reading2));
|
|
51809
|
+
gates.pass("state", stateLine(input, reading2));
|
|
51810
|
+
return reading2;
|
|
51811
|
+
}
|
|
51812
|
+
function normalised(text2) {
|
|
51813
|
+
return text2.replace(/\r\n/gu, `
|
|
51814
|
+
`).replace(TRAILING_WHITESPACE2, "");
|
|
51815
|
+
}
|
|
51816
|
+
function writeHeld(found, planned, reread) {
|
|
51817
|
+
const { change } = planned;
|
|
51818
|
+
if (change.title !== undefined && reread.title !== change.title)
|
|
51819
|
+
return false;
|
|
51820
|
+
const before = found.body.replace(/\r\n/gu, `
|
|
51821
|
+
`);
|
|
51822
|
+
const after = reread.body.replace(/\r\n/gu, `
|
|
51823
|
+
`);
|
|
51824
|
+
if (planned.block !== null)
|
|
51825
|
+
return originalPartHolds(before, after, normalised(planned.block));
|
|
51826
|
+
return normalised(after) === normalised(change.body ?? found.body);
|
|
51827
|
+
}
|
|
51828
|
+
function conflictPaths(issue4, stamp2, attempt5) {
|
|
51829
|
+
const suffix = attempt5 === 1 ? "" : `-${String(attempt5)}`;
|
|
51830
|
+
const name2 = (side) => join82(EDIT_SCRATCH_DIR, `${boardId(issue4)}-edit-${side}-${stamp2}${suffix}.md`);
|
|
51831
|
+
return { before: name2("before"), after: name2("after") };
|
|
51832
|
+
}
|
|
51833
|
+
function saveConflictBodies(root, issue4, now, before, after) {
|
|
51834
|
+
mkdirSync21(join82(root, EDIT_SCRATCH_DIR), { recursive: true });
|
|
51835
|
+
const stamp2 = fileStamp(now);
|
|
51836
|
+
let attempt5 = 1;
|
|
51837
|
+
let paths = conflictPaths(issue4, stamp2, attempt5);
|
|
51838
|
+
while (existsSync54(join82(root, paths.before)) || existsSync54(join82(root, paths.after))) {
|
|
51839
|
+
attempt5 += 1;
|
|
51840
|
+
paths = conflictPaths(issue4, stamp2, attempt5);
|
|
51841
|
+
}
|
|
51842
|
+
writeFileSync22(join82(root, paths.before), before, { flag: "wx" });
|
|
51843
|
+
writeFileSync22(join82(root, paths.after), after, { flag: "wx" });
|
|
51844
|
+
return paths;
|
|
51845
|
+
}
|
|
51846
|
+
function heldOutcome(request, state) {
|
|
51847
|
+
if (request.kind !== "append")
|
|
51848
|
+
return "replaced";
|
|
51849
|
+
return state.pass && state.staleCopy ? "stale-copy" : "appended";
|
|
51850
|
+
}
|
|
51851
|
+
function outcomeMessage(request, outcome2, branch, name2) {
|
|
51852
|
+
switch (outcome2) {
|
|
51853
|
+
case "appended":
|
|
51854
|
+
return `Appended an update to ${name2}; the original part is unchanged.`;
|
|
51855
|
+
case "stale-copy":
|
|
51856
|
+
return `Appended an update to ${name2}. ${staleCopyMessage(request.issue, branch)}`;
|
|
51857
|
+
case "already":
|
|
51858
|
+
return `${name2} already ends with this update; nothing was written.`;
|
|
51859
|
+
case "replaced": {
|
|
51860
|
+
if (request.text === null)
|
|
51861
|
+
return `Changed the title of ${name2}.`;
|
|
51862
|
+
return request.title === null ? `Replaced the body of ${name2}.` : `Replaced the body and the title of ${name2}.`;
|
|
51863
|
+
}
|
|
51864
|
+
case "conflict":
|
|
51865
|
+
throw new TypeError("issue edit: a conflict is worded with the paths it saved");
|
|
51866
|
+
}
|
|
51867
|
+
}
|
|
51868
|
+
function dryRunMessage(issue4, due, branch) {
|
|
51869
|
+
const stale = due === "stale-copy" ? ` ${staleCopyMessage(issue4, branch)}` : "";
|
|
51870
|
+
return `--dry-run: nothing was written; the edit would answer ${due}.${stale}`;
|
|
51871
|
+
}
|
|
51872
|
+
function conflictMessage(name2, scratch) {
|
|
51873
|
+
return `The edit was written, but ${name2} read back otherwise: somebody changed it around the write. ` + `The body read before is at ${scratch.before} and the body read after at ${scratch.after}; ` + "compare the two and make the edit again over the body as it stands.";
|
|
51874
|
+
}
|
|
51875
|
+
function report2(request, planned, readings, fields) {
|
|
51876
|
+
return Object.freeze({
|
|
51877
|
+
...fields,
|
|
51878
|
+
issue: request.issue,
|
|
51879
|
+
exitCode: editExitCode(fields.outcome),
|
|
51880
|
+
dryRun: request.dryRun,
|
|
51881
|
+
added: planned.shown,
|
|
51882
|
+
readings,
|
|
51883
|
+
refresh: fields.outcome === "stale-copy" ? refreshCommand(request.issue) : null,
|
|
51884
|
+
scratch: null
|
|
51885
|
+
});
|
|
51886
|
+
}
|
|
51887
|
+
async function runIssueEdit(options) {
|
|
51888
|
+
const { request, tracker } = options;
|
|
51889
|
+
const ref15 = issueRef(tracker, String(request.issue));
|
|
51890
|
+
const name2 = issueName(ref15);
|
|
51891
|
+
const now = options.now();
|
|
51892
|
+
const found = await onTracker(tracker, `read ${name2}`, () => tracker.editable(ref15));
|
|
51893
|
+
const gates = gatesFor(request);
|
|
51894
|
+
await weighOwnership(options, found, gates);
|
|
51895
|
+
const planned = planEdit(request, found, now);
|
|
51896
|
+
weighText(request, found, planned, gates);
|
|
51897
|
+
const state = weighState(options, found, gates);
|
|
51898
|
+
const { branch } = state;
|
|
51899
|
+
function done(outcome2, written3, message) {
|
|
51900
|
+
return report2(request, planned, gates.readings, { outcome: outcome2, written: written3, branch, message });
|
|
51901
|
+
}
|
|
51902
|
+
const due = planned.already ? "already" : heldOutcome(request, state);
|
|
51903
|
+
if (request.dryRun)
|
|
51904
|
+
return done(due, false, dryRunMessage(request.issue, due, branch));
|
|
51905
|
+
if (planned.already)
|
|
51906
|
+
return done("already", false, outcomeMessage(request, "already", branch, name2));
|
|
51907
|
+
await onTracker(tracker, `edit ${name2}`, () => tracker.edit(ref15, planned.change));
|
|
51908
|
+
const reread = await onTracker(tracker, `read ${name2} again after the edit was written`, () => tracker.editable(ref15));
|
|
51909
|
+
if (writeHeld(found, planned, reread))
|
|
51910
|
+
return done(due, true, outcomeMessage(request, due, branch, name2));
|
|
51911
|
+
const scratch = saveConflictBodies(options.root, request.issue, now, found.body, reread.body);
|
|
51912
|
+
return Object.freeze({ ...done("conflict", true, conflictMessage(name2, scratch)), scratch });
|
|
51913
|
+
}
|
|
51914
|
+
function renderEditReport(made) {
|
|
51915
|
+
if (!made.dryRun)
|
|
51916
|
+
return [made.message];
|
|
51917
|
+
return [...made.readings.map(renderReading), "added:", made.added, made.message];
|
|
51918
|
+
}
|
|
51919
|
+
async function editIssue2(context, seams) {
|
|
51920
|
+
const line = readEditLine(context.args, context.flags);
|
|
51921
|
+
const request = await readEditRequest(line, seams.stdin ?? (() => Bun.stdin.text()));
|
|
51922
|
+
const project = issueProject(context);
|
|
51923
|
+
const { tracker, data } = await resolveIssueTracker(context, seams);
|
|
51924
|
+
const editing = requireEditingTracker(tracker);
|
|
51925
|
+
const config = issueSubjectConfig(project, () => {
|
|
51926
|
+
return;
|
|
51927
|
+
});
|
|
51928
|
+
const gh = seams.gh ?? createGhRunner({ cwd: project.root });
|
|
51929
|
+
const openGit = seams.openGit ?? createGitRunner;
|
|
51930
|
+
const made = await runIssueEdit({
|
|
51931
|
+
request,
|
|
51932
|
+
tracker: editing,
|
|
51933
|
+
root: project.root,
|
|
51934
|
+
specsDir: config.specsDir,
|
|
51935
|
+
trust: () => ghBoardTrust({
|
|
51936
|
+
gh,
|
|
51937
|
+
trustedAuthors: config.boardTrustedAuthors,
|
|
51938
|
+
repo: boardRepoLabel(openGit(project.root))
|
|
51939
|
+
}),
|
|
51940
|
+
editor: createGhEditorLogin({ gh }),
|
|
51941
|
+
now: seams.now ?? (() => new Date)
|
|
51942
|
+
});
|
|
51943
|
+
return Object.freeze({ ...made, tracker: data });
|
|
51944
|
+
}
|
|
51945
|
+
var EDIT_USAGE, EDIT_REFUSAL_EXIT, EDIT_CONFLICT_EXIT = 1, EDIT_SCRATCH_DIR, STDIN_PATH2 = "-", ISSUE_NUMBER13, TRAILING_WHITESPACE2, ACCOUNTLESS_KIND = "local", LOCAL_OWNERSHIP = "local: the local tracker holds no accounts, so nobody is asked about", FLAG2, EditRefusal;
|
|
51946
|
+
var init_edit_run = __esm(() => {
|
|
51947
|
+
init_github();
|
|
51948
|
+
init_issue_edit_body();
|
|
51949
|
+
init_issue_edit_state();
|
|
51950
|
+
init_issue_edit_text();
|
|
51951
|
+
init_naming();
|
|
51952
|
+
init_plan_spec();
|
|
51953
|
+
init_trust();
|
|
51954
|
+
init_command();
|
|
51955
|
+
init_config_sections();
|
|
51956
|
+
init_git();
|
|
51957
|
+
init_fix_schema2();
|
|
51958
|
+
init_issue_tracker();
|
|
51959
|
+
EDIT_USAGE = "rafa issue edit <n> (--append-file=<file> | --append=<text>) --reason=<text>" + " [--while-in-development] | (--replace-file=<file> [--title=<text>] | --title=<text>) [--dry-run]";
|
|
51960
|
+
EDIT_REFUSAL_EXIT = TRUST_REFUSAL_EXIT;
|
|
51961
|
+
EDIT_SCRATCH_DIR = join82(".rafa", "scratch");
|
|
51962
|
+
ISSUE_NUMBER13 = /^[1-9]\d*$/u;
|
|
51963
|
+
TRAILING_WHITESPACE2 = /\s+$/u;
|
|
51964
|
+
FLAG2 = Object.freeze({
|
|
51965
|
+
appendFile: "append-file",
|
|
51966
|
+
append: "append",
|
|
51967
|
+
reason: "reason",
|
|
51968
|
+
replaceFile: "replace-file",
|
|
51969
|
+
title: "title",
|
|
51970
|
+
dryRun: "dry-run",
|
|
51971
|
+
whileInDevelopment: "while-in-development"
|
|
51972
|
+
});
|
|
51973
|
+
EditRefusal = class EditRefusal extends CommandExit {
|
|
51974
|
+
refusal;
|
|
51975
|
+
readings;
|
|
51976
|
+
constructor(refusal13, sentence, readings, dryRun) {
|
|
51977
|
+
const passed2 = dryRun ? readings.map(renderReading) : [];
|
|
51978
|
+
super(EDIT_REFUSAL_EXIT, [...passed2, `\u274C refused ${refusal13}: ${sentence}`].join(`
|
|
51979
|
+
`));
|
|
51980
|
+
this.refusal = refusal13;
|
|
51981
|
+
this.readings = readings;
|
|
51982
|
+
}
|
|
51983
|
+
};
|
|
51984
|
+
});
|
|
51985
|
+
|
|
51986
|
+
// src/commands/issue/edit.ts
|
|
51987
|
+
function createIssueEditCommand(seams = DEFAULT_EDIT_SEAMS) {
|
|
51988
|
+
const command = {
|
|
51989
|
+
name: "issue edit",
|
|
51990
|
+
subject: "issue",
|
|
51991
|
+
action: "edit",
|
|
51992
|
+
summary: "append a dated update to an issue body, or replace its body or title, after four gates",
|
|
51993
|
+
description: "Edits one issue on the tracker the chain lands on, after four gates weighed in order, the first" + " refusal ending the run with nothing written and exit code 2: the account editing must have write" + " access or be in board.trustedAuthors; so must the issue's author; the text added must leak nothing," + " and a complete spec must stay complete; and the issue must be open, its labels and saved spec copies" + " allowing the edit. An append (`--append-file` or `--append`, with `--reason`) adds a block" + " `**Updated <YYYY-MM-DD>, <reason>:**` below the body, leaving the original part byte for byte; the" + " same block already closing the body answers `already`. `--replace-file` replaces the body and" + " `--title` the title. After the write the issue is read again: a body that no longer holds what was" + " written answers `conflict` with exit code 1, the bodies read before and after saved under" + " `.rafa/scratch/`. An append on an issue already planned answers `stale-copy` and names" + " `rafa plan create --issue=<n> --refresh`, which it never runs. `--dry-run` prints each gate's" + " reading and the added part and writes nothing. With `--output=json` the report and the tracker are" + " the data of the terminal result event.",
|
|
51994
|
+
args: [
|
|
51995
|
+
{
|
|
51996
|
+
name: "n",
|
|
51997
|
+
description: "The issue number on the tracker.",
|
|
51998
|
+
type: "string",
|
|
51999
|
+
required: true
|
|
52000
|
+
}
|
|
52001
|
+
],
|
|
52002
|
+
flags: [
|
|
52003
|
+
{
|
|
52004
|
+
name: "append-file",
|
|
52005
|
+
description: "A file holding the text to append, read whole; `-` reads standard input." + " Needs --reason. Not with --append, --replace-file or --title.",
|
|
52006
|
+
type: "string"
|
|
52007
|
+
},
|
|
52008
|
+
{
|
|
52009
|
+
name: "append",
|
|
52010
|
+
description: "The text to append. Needs --reason. Not with --append-file, --replace-file or --title.",
|
|
52011
|
+
type: "string"
|
|
52012
|
+
},
|
|
52013
|
+
{
|
|
52014
|
+
name: "reason",
|
|
52015
|
+
description: "Why the update was made, written into its heading. Required with an append, refused otherwise.",
|
|
52016
|
+
type: "string"
|
|
52017
|
+
},
|
|
52018
|
+
{
|
|
52019
|
+
name: "replace-file",
|
|
52020
|
+
description: "A file holding the new body, read whole; `-` reads standard input. Not with an append.",
|
|
52021
|
+
type: "string"
|
|
52022
|
+
},
|
|
52023
|
+
{
|
|
52024
|
+
name: "title",
|
|
52025
|
+
description: "The new title, alone or beside --replace-file. Not with an append.",
|
|
52026
|
+
type: "string"
|
|
52027
|
+
},
|
|
52028
|
+
{
|
|
52029
|
+
name: "while-in-development",
|
|
52030
|
+
description: "Allows an append on an issue a loop has claimed, answering stale-copy. Only with an append.",
|
|
52031
|
+
type: "boolean"
|
|
52032
|
+
},
|
|
52033
|
+
{
|
|
52034
|
+
name: "dry-run",
|
|
52035
|
+
description: "Prints the added part and each gate's reading and writes nothing; a refusal still exits 2.",
|
|
52036
|
+
type: "boolean"
|
|
52037
|
+
}
|
|
52038
|
+
],
|
|
52039
|
+
examples: [
|
|
52040
|
+
{
|
|
52041
|
+
cmd: 'rafa issue edit 57 --append-file=update.md --reason="scope narrowed"',
|
|
52042
|
+
note: "Appends what update.md holds to #57 below a dated heading naming the reason."
|
|
52043
|
+
},
|
|
52044
|
+
{
|
|
52045
|
+
cmd: 'rafa issue edit 57 --append="Also covers --dry-run." --reason=clarified --dry-run',
|
|
52046
|
+
note: "Prints each gate's reading and the block it would append, and writes nothing."
|
|
52047
|
+
},
|
|
52048
|
+
{
|
|
52049
|
+
cmd: 'rafa issue edit 57 --title="Faster plan show"',
|
|
52050
|
+
note: "Changes the title of #57 and leaves its body alone."
|
|
52051
|
+
},
|
|
52052
|
+
{
|
|
52053
|
+
cmd: "rafa issue edit 57 --replace-file=spec.md --output=json",
|
|
52054
|
+
note: "Replaces the body of #57; the report and the tracker are the data of the result event."
|
|
52055
|
+
}
|
|
52056
|
+
],
|
|
52057
|
+
outputs: ["text", "json"],
|
|
52058
|
+
run: async (context) => {
|
|
52059
|
+
const made = await editIssue2(context, seams);
|
|
52060
|
+
if (made.exitCode !== 0)
|
|
52061
|
+
throw new CommandExit(made.exitCode, renderEditReport(made).join(`
|
|
52062
|
+
`));
|
|
52063
|
+
if (context.outputMode === "json") {
|
|
52064
|
+
context.output.result(made);
|
|
52065
|
+
return;
|
|
52066
|
+
}
|
|
52067
|
+
for (const line of renderEditReport(made))
|
|
52068
|
+
context.output.info(line);
|
|
52069
|
+
}
|
|
52070
|
+
};
|
|
52071
|
+
return Object.freeze(command);
|
|
52072
|
+
}
|
|
52073
|
+
var DEFAULT_EDIT_SEAMS, edit_default;
|
|
52074
|
+
var init_edit = __esm(() => {
|
|
52075
|
+
init_command();
|
|
52076
|
+
init_edit_run();
|
|
52077
|
+
DEFAULT_EDIT_SEAMS = Object.freeze({});
|
|
52078
|
+
edit_default = createIssueEditCommand();
|
|
52079
|
+
});
|
|
52080
|
+
|
|
51305
52081
|
// src/commands/issue/move.ts
|
|
51306
52082
|
async function moveIssue(context, seams) {
|
|
51307
52083
|
const [id3, word] = expectTwoArguments(context.args, USAGE28);
|
|
@@ -51983,10 +52759,10 @@ var init_pr_lifecycle = __esm(() => {
|
|
|
51983
52759
|
});
|
|
51984
52760
|
|
|
51985
52761
|
// src/notices/notices.ts
|
|
51986
|
-
import { mkdirSync as
|
|
51987
|
-
import { dirname as dirname29, join as
|
|
52762
|
+
import { mkdirSync as mkdirSync22, readFileSync as readFileSync62, writeFileSync as writeFileSync23 } from "fs";
|
|
52763
|
+
import { dirname as dirname29, join as join83 } from "path";
|
|
51988
52764
|
function noticesPath(home) {
|
|
51989
|
-
return
|
|
52765
|
+
return join83(home, ".rafa", "notices.json");
|
|
51990
52766
|
}
|
|
51991
52767
|
function isNoticeId(value) {
|
|
51992
52768
|
return typeof value === "string" && NOTICE_IDS.includes(value);
|
|
@@ -52013,8 +52789,8 @@ function readDismissed(home) {
|
|
|
52013
52789
|
function writeDismissed(home, ids) {
|
|
52014
52790
|
const all = NOTICE_IDS.filter((id3) => ids.includes(id3) || readDismissed(home).includes(id3));
|
|
52015
52791
|
const path4 = noticesPath(home);
|
|
52016
|
-
|
|
52017
|
-
|
|
52792
|
+
mkdirSync22(dirname29(path4), { recursive: true });
|
|
52793
|
+
writeFileSync23(path4, `${JSON.stringify({ dismissed: all }, null, 2)}
|
|
52018
52794
|
`);
|
|
52019
52795
|
}
|
|
52020
52796
|
function pendingNotices(dismissed) {
|
|
@@ -52133,9 +52909,9 @@ var init_budget = __esm(() => {
|
|
|
52133
52909
|
});
|
|
52134
52910
|
|
|
52135
52911
|
// src/start/checkout-guard.ts
|
|
52136
|
-
import { existsSync as
|
|
52912
|
+
import { existsSync as existsSync55, realpathSync as realpathSync14 } from "fs";
|
|
52137
52913
|
function realDirOf(path4) {
|
|
52138
|
-
if (!
|
|
52914
|
+
if (!existsSync55(path4))
|
|
52139
52915
|
return null;
|
|
52140
52916
|
try {
|
|
52141
52917
|
return realpathSync14(path4);
|
|
@@ -52446,17 +53222,17 @@ function truncateDescription(description, budget) {
|
|
|
52446
53222
|
const cut2 = lastSpace > 0 ? window.slice(0, lastSpace) : window.slice(0, budget);
|
|
52447
53223
|
return balanceCodeSpans(cut2.trimEnd()).replace(/[\s,;:-]+$/, "");
|
|
52448
53224
|
}
|
|
52449
|
-
function subjectDescription(
|
|
52450
|
-
const clause = firstClause(
|
|
52451
|
-
const description = clause.length === 0 ?
|
|
53225
|
+
function subjectDescription(normalised2) {
|
|
53226
|
+
const clause = firstClause(normalised2);
|
|
53227
|
+
const description = clause.length === 0 ? normalised2 : clause;
|
|
52452
53228
|
return lowerFirstWord(stripTrailingPeriod(description));
|
|
52453
53229
|
}
|
|
52454
53230
|
function deriveCommitSubject(taskText, options = {}) {
|
|
52455
53231
|
const type = inferCommitType(taskText);
|
|
52456
53232
|
const scope = options.scope;
|
|
52457
53233
|
const prefix = scope === undefined || scope.length === 0 ? `${type}: ` : `${type}(${scope}): `;
|
|
52458
|
-
const
|
|
52459
|
-
const uncut =
|
|
53234
|
+
const normalised2 = normaliseTaskText(taskText);
|
|
53235
|
+
const uncut = normalised2.length === 0 ? FALLBACK_DESCRIPTION : subjectDescription(normalised2);
|
|
52460
53236
|
const maxLength = options.maxLength ?? MAX_SUBJECT_LENGTH;
|
|
52461
53237
|
const description = truncateDescription(uncut, maxLength - prefix.length);
|
|
52462
53238
|
const truncated = description !== uncut;
|
|
@@ -52623,11 +53399,11 @@ function indentBlock(text2) {
|
|
|
52623
53399
|
`);
|
|
52624
53400
|
}
|
|
52625
53401
|
function holdsOf(reading2) {
|
|
52626
|
-
const { report:
|
|
53402
|
+
const { report: report3, issues } = reading2;
|
|
52627
53403
|
const holds2 = [];
|
|
52628
|
-
if (
|
|
53404
|
+
if (report3.status === "blocked")
|
|
52629
53405
|
holds2.push("status: blocked");
|
|
52630
|
-
for (const blocker of
|
|
53406
|
+
for (const blocker of report3.blockers) {
|
|
52631
53407
|
holds2.push(`blocker: ${blocker.what ?? "an entry with no usable what"}`);
|
|
52632
53408
|
}
|
|
52633
53409
|
for (const issue4 of issues) {
|
|
@@ -52810,10 +53586,10 @@ function openingLine(route, plan) {
|
|
|
52810
53586
|
\uD83C\uDF3F Switching to the existing ${plan.branch}.`;
|
|
52811
53587
|
}
|
|
52812
53588
|
function runRoute(route, plan, git) {
|
|
52813
|
-
const
|
|
52814
|
-
if (
|
|
53589
|
+
const refused5 = treeRefusal(readWorkingTree(git, plan), plan);
|
|
53590
|
+
if (refused5 !== null)
|
|
52815
53591
|
throw new CommandExit(1, `
|
|
52816
|
-
${
|
|
53592
|
+
${refused5}`);
|
|
52817
53593
|
const steps = branchSteps(route, plan);
|
|
52818
53594
|
activeOutput().info(openingLine(route, plan));
|
|
52819
53595
|
for (const step2 of steps) {
|
|
@@ -53031,9 +53807,9 @@ var init_claim_catch_up = __esm(() => {
|
|
|
53031
53807
|
|
|
53032
53808
|
// src/start/worktree.ts
|
|
53033
53809
|
import { realpathSync as realpathSync15 } from "fs";
|
|
53034
|
-
import { join as
|
|
53810
|
+
import { join as join84, resolve as resolve37 } from "path";
|
|
53035
53811
|
function worktreePathFor(projectRoot3, worktreeDir, stub) {
|
|
53036
|
-
return
|
|
53812
|
+
return join84(worktreeDirAt(projectRoot3, worktreeDir), stub);
|
|
53037
53813
|
}
|
|
53038
53814
|
function addStep2(route, plan, path4) {
|
|
53039
53815
|
const label = `add the worktree for ${plan.branch} at ${path4}`;
|
|
@@ -53089,7 +53865,7 @@ function canonicalPath(path4) {
|
|
|
53089
53865
|
try {
|
|
53090
53866
|
return realpathSync15(path4);
|
|
53091
53867
|
} catch {
|
|
53092
|
-
return
|
|
53868
|
+
return resolve37(path4);
|
|
53093
53869
|
}
|
|
53094
53870
|
}
|
|
53095
53871
|
function readExisting(listing2, branch, path4) {
|
|
@@ -53282,7 +54058,7 @@ function none(reason, detail) {
|
|
|
53282
54058
|
return Object.freeze({ owns: null, reason, detail });
|
|
53283
54059
|
}
|
|
53284
54060
|
function issueNumberOf2(issue4) {
|
|
53285
|
-
const digits =
|
|
54061
|
+
const digits = ISSUE_NUMBER14.exec(issue4?.trim() ?? "")?.[1];
|
|
53286
54062
|
if (digits === undefined)
|
|
53287
54063
|
return null;
|
|
53288
54064
|
const number = Number(digits);
|
|
@@ -53347,7 +54123,7 @@ async function readPlanOwns(options) {
|
|
|
53347
54123
|
return slug;
|
|
53348
54124
|
return epicOwns(issue4, slug, options.gh);
|
|
53349
54125
|
}
|
|
53350
|
-
var
|
|
54126
|
+
var ISSUE_NUMBER14;
|
|
53351
54127
|
var init_owns = __esm(() => {
|
|
53352
54128
|
init_board_owns();
|
|
53353
54129
|
init_epic_context();
|
|
@@ -53355,7 +54131,7 @@ var init_owns = __esm(() => {
|
|
|
53355
54131
|
init_issue();
|
|
53356
54132
|
init_roadmap_board();
|
|
53357
54133
|
init_config_sections();
|
|
53358
|
-
|
|
54134
|
+
ISSUE_NUMBER14 = /^#?(\d+)$/u;
|
|
53359
54135
|
});
|
|
53360
54136
|
|
|
53361
54137
|
// src/suite/unhandled.ts
|
|
@@ -53442,8 +54218,8 @@ var init_unhandled = __esm(() => {
|
|
|
53442
54218
|
});
|
|
53443
54219
|
|
|
53444
54220
|
// src/suite/run.ts
|
|
53445
|
-
import { existsSync as
|
|
53446
|
-
import { basename as basename22, dirname as dirname30, extname as extname2, isAbsolute as isAbsolute21, join as
|
|
54221
|
+
import { existsSync as existsSync56, mkdirSync as mkdirSync23, readFileSync as readFileSync63, rmSync as rmSync12, writeFileSync as writeFileSync24 } from "fs";
|
|
54222
|
+
import { basename as basename22, dirname as dirname30, extname as extname2, isAbsolute as isAbsolute21, join as join85 } from "path";
|
|
53447
54223
|
function readNoTestFiles(stderr) {
|
|
53448
54224
|
return NO_TEST_FILES_LINE.test(stderr);
|
|
53449
54225
|
}
|
|
@@ -53460,7 +54236,7 @@ function suiteCommand(junitFile, paths, changedSince) {
|
|
|
53460
54236
|
function outputFileFor(junitFile) {
|
|
53461
54237
|
const name2 = basename22(junitFile);
|
|
53462
54238
|
const stem = name2.endsWith(JUNIT_SUFFIX) ? name2.slice(0, -JUNIT_SUFFIX.length) : name2.slice(0, name2.length - extname2(name2).length);
|
|
53463
|
-
return
|
|
54239
|
+
return join85(dirname30(junitFile), `${stem}${OUTPUT_SUFFIX}`);
|
|
53464
54240
|
}
|
|
53465
54241
|
function suiteEnv(base) {
|
|
53466
54242
|
return Object.fromEntries(Object.entries(base).filter(([key]) => key !== CLAUDE_CODE_ENV));
|
|
@@ -53563,7 +54339,7 @@ function parseJunitFailures(xml) {
|
|
|
53563
54339
|
return walk.failures;
|
|
53564
54340
|
}
|
|
53565
54341
|
function readJunit(path4) {
|
|
53566
|
-
if (!
|
|
54342
|
+
if (!existsSync56(path4))
|
|
53567
54343
|
return { junit: "missing", failures: [] };
|
|
53568
54344
|
let text2;
|
|
53569
54345
|
try {
|
|
@@ -53591,13 +54367,13 @@ async function runSuite(options) {
|
|
|
53591
54367
|
}
|
|
53592
54368
|
const command = suiteCommand(options.junitFile, options.paths, options.changedSince);
|
|
53593
54369
|
const outputFile = outputFileFor(options.junitFile);
|
|
53594
|
-
|
|
54370
|
+
mkdirSync23(dirname30(options.junitFile), { recursive: true });
|
|
53595
54371
|
rmSync12(options.junitFile, { force: true });
|
|
53596
54372
|
rmSync12(outputFile, { force: true });
|
|
53597
54373
|
const spawn = options.spawn ?? spawnSuite;
|
|
53598
54374
|
const env = suiteEnv(options.env ?? process.env);
|
|
53599
54375
|
const { exitCode, stderr } = await spawn(command, { cwd: options.cwd, env });
|
|
53600
|
-
|
|
54376
|
+
writeFileSync24(outputFile, unhandledText(stderr));
|
|
53601
54377
|
const { summary, errors } = readSummary2(stderr);
|
|
53602
54378
|
const { junit, failures } = readJunit(options.junitFile);
|
|
53603
54379
|
const unhandled = parseUnhandled(stderr);
|
|
@@ -53615,12 +54391,12 @@ var init_run4 = __esm(() => {
|
|
|
53615
54391
|
});
|
|
53616
54392
|
|
|
53617
54393
|
// src/suite/scope.ts
|
|
53618
|
-
import { existsSync as
|
|
53619
|
-
import { isAbsolute as isAbsolute22, join as
|
|
54394
|
+
import { existsSync as existsSync57, readdirSync as readdirSync21, readFileSync as readFileSync64 } from "fs";
|
|
54395
|
+
import { isAbsolute as isAbsolute22, join as join86, relative as relative17, sep as sep7 } from "path";
|
|
53620
54396
|
function sortedUnique(paths) {
|
|
53621
54397
|
return [...new Set(paths)].sort((a, b) => a.localeCompare(b));
|
|
53622
54398
|
}
|
|
53623
|
-
function
|
|
54399
|
+
function normalised2(paths) {
|
|
53624
54400
|
return paths.map(normaliseFolder).filter((path4) => path4 !== "");
|
|
53625
54401
|
}
|
|
53626
54402
|
function holds2(folder, path4) {
|
|
@@ -53628,24 +54404,24 @@ function holds2(folder, path4) {
|
|
|
53628
54404
|
}
|
|
53629
54405
|
function triggeredPaths(diff, triggers) {
|
|
53630
54406
|
const globs = triggers.globs.map((pattern) => new Bun.Glob(pattern));
|
|
53631
|
-
const preload = new Set(
|
|
54407
|
+
const preload = new Set(normalised2(triggers.preload));
|
|
53632
54408
|
const matches = (path4) => preload.has(path4) || globs.some((glob) => glob.match(path4));
|
|
53633
|
-
return sortedUnique(
|
|
54409
|
+
return sortedUnique(normalised2(diff).filter(matches));
|
|
53634
54410
|
}
|
|
53635
54411
|
function touchedFolders(diff, owns) {
|
|
53636
|
-
const board = { number: 0, owner: null, owns:
|
|
53637
|
-
const touched =
|
|
54412
|
+
const board = { number: 0, owner: null, owns: normalised2(owns) };
|
|
54413
|
+
const touched = normalised2(diff).map((path4) => owningBoard(path4, [board], null)?.match ?? null);
|
|
53638
54414
|
return sortedUnique(touched.filter((folder) => folder !== null));
|
|
53639
54415
|
}
|
|
53640
54416
|
function testFilesUnder(folders, testFiles) {
|
|
53641
|
-
return sortedUnique(
|
|
54417
|
+
return sortedUnique(normalised2(testFiles).filter((file) => folders.some((folder) => holds2(folder, file))));
|
|
53642
54418
|
}
|
|
53643
54419
|
function integrationFiles(integration, testFiles) {
|
|
53644
54420
|
const globs = integration.map((pattern) => new Bun.Glob(pattern));
|
|
53645
|
-
return sortedUnique(
|
|
54421
|
+
return sortedUnique(normalised2(testFiles).filter((file) => globs.some((glob) => glob.match(file))));
|
|
53646
54422
|
}
|
|
53647
54423
|
function ownsFolders(owns) {
|
|
53648
|
-
return owns === null ? [] :
|
|
54424
|
+
return owns === null ? [] : normalised2(owns);
|
|
53649
54425
|
}
|
|
53650
54426
|
function taskStepScope(input) {
|
|
53651
54427
|
const { declared } = input;
|
|
@@ -53696,8 +54472,8 @@ function preloadFilesOf(text2, root) {
|
|
|
53696
54472
|
return paths.filter((path4) => path4 !== null);
|
|
53697
54473
|
}
|
|
53698
54474
|
function readPreloadFiles(root) {
|
|
53699
|
-
const path4 =
|
|
53700
|
-
if (!
|
|
54475
|
+
const path4 = join86(root, BUNFIG_FILE);
|
|
54476
|
+
if (!existsSync57(path4))
|
|
53701
54477
|
return { state: "missing", files: [] };
|
|
53702
54478
|
try {
|
|
53703
54479
|
return { state: "read", files: preloadFilesOf(readFileSync64(path4, "utf8"), root) };
|
|
@@ -53709,7 +54485,7 @@ function readPreloadFiles(root) {
|
|
|
53709
54485
|
function listTestFiles(root) {
|
|
53710
54486
|
const found = [];
|
|
53711
54487
|
const walk = (folder) => {
|
|
53712
|
-
for (const entry of
|
|
54488
|
+
for (const entry of readdirSync21(join86(root, folder), { withFileTypes: true })) {
|
|
53713
54489
|
const path4 = folder === "" ? entry.name : `${folder}/${entry.name}`;
|
|
53714
54490
|
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== DEPENDENCY_FOLDER)
|
|
53715
54491
|
walk(path4);
|
|
@@ -53728,8 +54504,8 @@ var init_scope2 = __esm(() => {
|
|
|
53728
54504
|
});
|
|
53729
54505
|
|
|
53730
54506
|
// src/start/lint-step.ts
|
|
53731
|
-
import { existsSync as
|
|
53732
|
-
import { join as
|
|
54507
|
+
import { existsSync as existsSync58 } from "fs";
|
|
54508
|
+
import { join as join87, relative as relative18 } from "path";
|
|
53733
54509
|
async function runEslint(options) {
|
|
53734
54510
|
const proc = Bun.spawn([...options.argv], {
|
|
53735
54511
|
cwd: options.cwd,
|
|
@@ -53745,7 +54521,7 @@ async function runEslint(options) {
|
|
|
53745
54521
|
return { exitCode, stdout, stderr };
|
|
53746
54522
|
}
|
|
53747
54523
|
function hasEslintConfig(checkout) {
|
|
53748
|
-
return ESLINT_CONFIG_FILES.some((name2) =>
|
|
54524
|
+
return ESLINT_CONFIG_FILES.some((name2) => existsSync58(join87(checkout, name2)));
|
|
53749
54525
|
}
|
|
53750
54526
|
function readLintFiles(git, base) {
|
|
53751
54527
|
const result2 = git(["diff", "--name-only", "-z", "--no-renames", "--diff-filter=d", base, "HEAD"]);
|
|
@@ -53867,7 +54643,7 @@ var init_lint_step = __esm(() => {
|
|
|
53867
54643
|
});
|
|
53868
54644
|
|
|
53869
54645
|
// src/start/suite-blocker.ts
|
|
53870
|
-
import { readFileSync as readFileSync65, writeFileSync as
|
|
54646
|
+
import { readFileSync as readFileSync65, writeFileSync as writeFileSync25 } from "fs";
|
|
53871
54647
|
function failingFiles(failures) {
|
|
53872
54648
|
const counts = new Map;
|
|
53873
54649
|
for (const failure6 of failures)
|
|
@@ -53939,7 +54715,7 @@ function blockRepairAgain(trackerPath, content, line, blocker) {
|
|
|
53939
54715
|
const current = lines2[line] ?? "";
|
|
53940
54716
|
if (current.startsWith(TICKED_PREFIX)) {
|
|
53941
54717
|
const reopened = [...lines2.slice(0, line), `- [ ] ${current.slice(TICKED_PREFIX.length)}`, ...lines2.slice(line + 1)];
|
|
53942
|
-
|
|
54718
|
+
writeFileSync25(trackerPath, reopened.join(`
|
|
53943
54719
|
`), "utf8");
|
|
53944
54720
|
}
|
|
53945
54721
|
return writeTrackerBlocker(trackerPath, line, blocker) ? { line, inserted: false } : null;
|
|
@@ -53962,7 +54738,7 @@ var init_suite_blocker = __esm(() => {
|
|
|
53962
54738
|
});
|
|
53963
54739
|
|
|
53964
54740
|
// src/start/sweep-timing.ts
|
|
53965
|
-
import { existsSync as
|
|
54741
|
+
import { existsSync as existsSync59, readFileSync as readFileSync66 } from "fs";
|
|
53966
54742
|
function fileTimeOf(attributes) {
|
|
53967
54743
|
const file = attributes["file"] ?? attributes["name"];
|
|
53968
54744
|
const seconds = Number(attributes["time"]);
|
|
@@ -54000,7 +54776,7 @@ function slowSweepLine(slow) {
|
|
|
54000
54776
|
return `\uD83D\uDC22 ${slow.length} tests.alwaysRun file(s) took over ${SLOW_SWEEP_SECONDS}s in the task step: ${named3}.`;
|
|
54001
54777
|
}
|
|
54002
54778
|
function readFileTimes(path4) {
|
|
54003
|
-
if (!
|
|
54779
|
+
if (!existsSync59(path4))
|
|
54004
54780
|
return [];
|
|
54005
54781
|
try {
|
|
54006
54782
|
return parseJunitFileTimes(readFileSync66(path4, "utf8")) ?? [];
|
|
@@ -54165,9 +54941,9 @@ var init_suite_stage_step = __esm(() => {
|
|
|
54165
54941
|
});
|
|
54166
54942
|
|
|
54167
54943
|
// src/start/suite-step.ts
|
|
54168
|
-
import { existsSync as
|
|
54944
|
+
import { existsSync as existsSync60, mkdirSync as mkdirSync24, readFileSync as readFileSync68, renameSync as renameSync11, writeFileSync as writeFileSync26 } from "fs";
|
|
54169
54945
|
import { constants as constants3 } from "os";
|
|
54170
|
-
import { basename as basename23, dirname as dirname31, join as
|
|
54946
|
+
import { basename as basename23, dirname as dirname31, join as join88 } from "path";
|
|
54171
54947
|
function seamsOf(context) {
|
|
54172
54948
|
const seams = context.seams ?? {};
|
|
54173
54949
|
return {
|
|
@@ -54183,15 +54959,15 @@ function seamsOf(context) {
|
|
|
54183
54959
|
};
|
|
54184
54960
|
}
|
|
54185
54961
|
function junitFileFor(repoRoot, sessionId, kind) {
|
|
54186
|
-
return
|
|
54962
|
+
return join88(runsDir(repoRoot), sessionId, "suite", `${kind}.junit.xml`);
|
|
54187
54963
|
}
|
|
54188
54964
|
function alwaysRunJunitFileFor(repoRoot, sessionId, kind = "task") {
|
|
54189
|
-
return
|
|
54965
|
+
return join88(runsDir(repoRoot), sessionId, "suite", `${kind}-always-run.junit.xml`);
|
|
54190
54966
|
}
|
|
54191
54967
|
function stageLedgerPathFor(trackerPath) {
|
|
54192
54968
|
const baselinePath = baselinePathFor(trackerPath);
|
|
54193
54969
|
const name2 = basename23(baselinePath).replace(BASELINE_FILE_PREFIX, STAGE_LEDGER_PREFIX);
|
|
54194
|
-
return
|
|
54970
|
+
return join88(dirname31(baselinePath), name2);
|
|
54195
54971
|
}
|
|
54196
54972
|
function isLedgerEntry(value) {
|
|
54197
54973
|
if (typeof value !== "object" || value === null)
|
|
@@ -54215,7 +54991,7 @@ function parseLedger(text2) {
|
|
|
54215
54991
|
return stages;
|
|
54216
54992
|
}
|
|
54217
54993
|
function readStageLedger(path4) {
|
|
54218
|
-
if (!
|
|
54994
|
+
if (!existsSync60(path4))
|
|
54219
54995
|
return [];
|
|
54220
54996
|
let parsed;
|
|
54221
54997
|
try {
|
|
@@ -54229,9 +55005,9 @@ function readStageLedger(path4) {
|
|
|
54229
55005
|
return [];
|
|
54230
55006
|
}
|
|
54231
55007
|
function writeStageLedger(path4, entries) {
|
|
54232
|
-
|
|
55008
|
+
mkdirSync24(dirname31(path4), { recursive: true });
|
|
54233
55009
|
const temporary = `${path4}.${process.pid}.tmp`;
|
|
54234
|
-
|
|
55010
|
+
writeFileSync26(temporary, `${JSON.stringify({ version: STAGE_LEDGER_VERSION, stages: entries }, null, 2)}
|
|
54235
55011
|
`, "utf8");
|
|
54236
55012
|
renameSync11(temporary, path4);
|
|
54237
55013
|
}
|
|
@@ -54645,8 +55421,8 @@ var init_pr_retarget = __esm(() => {
|
|
|
54645
55421
|
});
|
|
54646
55422
|
|
|
54647
55423
|
// src/release/prepare.ts
|
|
54648
|
-
import { mkdirSync as
|
|
54649
|
-
import { dirname as dirname32, join as
|
|
55424
|
+
import { mkdirSync as mkdirSync25, readFileSync as readFileSync69, writeFileSync as writeFileSync27 } from "fs";
|
|
55425
|
+
import { dirname as dirname32, join as join89, posix as posix5 } from "path";
|
|
54650
55426
|
function levelFields(reading2) {
|
|
54651
55427
|
return { level: reading2.level, levelSource: reading2.source, notesLevel: reading2.notesLevel };
|
|
54652
55428
|
}
|
|
@@ -54712,8 +55488,8 @@ function nameOf2(path4) {
|
|
|
54712
55488
|
}
|
|
54713
55489
|
function writeFragment(path4, resolved, text2) {
|
|
54714
55490
|
try {
|
|
54715
|
-
|
|
54716
|
-
|
|
55491
|
+
mkdirSync25(dirname32(resolved), { recursive: true });
|
|
55492
|
+
writeFileSync27(resolved, text2);
|
|
54717
55493
|
return null;
|
|
54718
55494
|
} catch (error) {
|
|
54719
55495
|
return `${path4} could not be written: ${messageOf(error)}`;
|
|
@@ -54737,7 +55513,7 @@ function prepareRelease(input) {
|
|
|
54737
55513
|
const fragment = { plan: input.plan, title: title2, level, notes: lines2.notes };
|
|
54738
55514
|
const name2 = allocateFragmentName(input.plan, read.base.waiting.map((waiting) => nameOf2(waiting.path)));
|
|
54739
55515
|
const path4 = posix5.join(input.settings.releaseFragments.replace(/\\/g, "/"), name2);
|
|
54740
|
-
const resolved =
|
|
55516
|
+
const resolved = join89(input.repoRoot, path4);
|
|
54741
55517
|
const before = textOf3(resolved);
|
|
54742
55518
|
const after = serializeFragment(fragment);
|
|
54743
55519
|
const problems = lines2.problem === null ? read.problems : [...read.problems, lines2.problem];
|
|
@@ -54769,7 +55545,7 @@ var init_prepare = __esm(() => {
|
|
|
54769
55545
|
});
|
|
54770
55546
|
|
|
54771
55547
|
// src/release/verify.ts
|
|
54772
|
-
import { readFileSync as readFileSync70, writeFileSync as
|
|
55548
|
+
import { readFileSync as readFileSync70, writeFileSync as writeFileSync28 } from "fs";
|
|
54773
55549
|
import { posix as posix6 } from "path";
|
|
54774
55550
|
function textOf4(path4) {
|
|
54775
55551
|
try {
|
|
@@ -54789,7 +55565,7 @@ function listOf4(names2) {
|
|
|
54789
55565
|
}
|
|
54790
55566
|
function restoreFragment(file) {
|
|
54791
55567
|
try {
|
|
54792
|
-
|
|
55568
|
+
writeFileSync28(file.resolved, file.after);
|
|
54793
55569
|
return { path: file.path, restored: true, problem: null };
|
|
54794
55570
|
} catch (error) {
|
|
54795
55571
|
return {
|
|
@@ -54916,13 +55692,13 @@ function announcePreparation(preparation) {
|
|
|
54916
55692
|
}
|
|
54917
55693
|
for (const problem2 of preparation.problems)
|
|
54918
55694
|
out.warn(` \u26A0\uFE0F ${problem2}`);
|
|
54919
|
-
const
|
|
55695
|
+
const report3 = releaseLevelReport({
|
|
54920
55696
|
level: preparation.level,
|
|
54921
55697
|
source: preparation.levelSource,
|
|
54922
55698
|
notesLevel: preparation.notesLevel
|
|
54923
55699
|
});
|
|
54924
|
-
if (
|
|
54925
|
-
out.warn(` \u26A0\uFE0F Level report: ${
|
|
55700
|
+
if (report3 !== null)
|
|
55701
|
+
out.warn(` \u26A0\uFE0F Level report: ${report3}`);
|
|
54926
55702
|
}
|
|
54927
55703
|
function prepareReleaseStage(input, seams = {}) {
|
|
54928
55704
|
const io = { ...RELEASE_STAGE_SEAMS, ...seams };
|
|
@@ -55439,13 +56215,13 @@ async function checkWrapUpAnswer(input) {
|
|
|
55439
56215
|
const line = unpromotedLine(check, input.head);
|
|
55440
56216
|
if (line === null)
|
|
55441
56217
|
return check;
|
|
55442
|
-
const
|
|
55443
|
-
if (!
|
|
55444
|
-
out.warn(` This line is not in the pull request body, as ${
|
|
55445
|
-
} else if (
|
|
55446
|
-
out.info(` Pull request #${
|
|
56218
|
+
const report3 = await reportUnpromoted(input.pulls, input.branch, line);
|
|
56219
|
+
if (!report3.written) {
|
|
56220
|
+
out.warn(` This line is not in the pull request body, as ${report3.problem}: ${line}`);
|
|
56221
|
+
} else if (report3.already) {
|
|
56222
|
+
out.info(` Pull request #${report3.number} already names the lessons it does not carry.`);
|
|
55447
56223
|
} else {
|
|
55448
|
-
out.info(` Pull request #${
|
|
56224
|
+
out.info(` Pull request #${report3.number} now names the lessons it does not carry.`);
|
|
55449
56225
|
}
|
|
55450
56226
|
return check;
|
|
55451
56227
|
}
|
|
@@ -55755,8 +56531,8 @@ async function emitPullRequestEvent(place2, branch, known, lookup) {
|
|
|
55755
56531
|
}
|
|
55756
56532
|
emitLoopEvent(number === null ? { kind: "no-pr", reason: `no open pull request for ${branch}` } : { kind: "pr", number });
|
|
55757
56533
|
}
|
|
55758
|
-
function blockedDelivery(
|
|
55759
|
-
return { kind: "blocked", message: `${
|
|
56534
|
+
function blockedDelivery(report3, retriesSpent) {
|
|
56535
|
+
return { kind: "blocked", message: `${report3}
|
|
55760
56536
|
${DELIVERY_BLOCKED_TAIL}`, retriesSpent };
|
|
55761
56537
|
}
|
|
55762
56538
|
async function readOpenPull2(seams, branch) {
|
|
@@ -55805,7 +56581,7 @@ async function openByRunner(seams, branch, retriesSpent) {
|
|
|
55805
56581
|
}
|
|
55806
56582
|
function planIssueNumber(planContent, planStub2, branch) {
|
|
55807
56583
|
const declared = parsePlan(planContent).header.issue?.trim() ?? "";
|
|
55808
|
-
const spelled =
|
|
56584
|
+
const spelled = ISSUE_NUMBER15.exec(declared)?.[1] ?? RAFA_ID.exec(planStub2 ?? "")?.[1] ?? RAFA_ID.exec(branch)?.[1];
|
|
55809
56585
|
return spelled === undefined ? null : Number(spelled);
|
|
55810
56586
|
}
|
|
55811
56587
|
function runnerPrInputFor(source) {
|
|
@@ -55858,7 +56634,7 @@ function deliverySeamsIn(context) {
|
|
|
55858
56634
|
};
|
|
55859
56635
|
}
|
|
55860
56636
|
var NO_PROVIDER_REASON = "no pull request provider is configured", DELIVERY_BLOCKED_TAIL = " The run is recorded stopped, not done. Open the pull request by hand, or fix the step above and run again to retry the wrap-up.", DELIVERY_INTERRUPTED = `
|
|
55861
|
-
\u26A0\uFE0F Interrupted: no further wrap-up session runs and the loop opens no pull request. Run again to retry the wrap-up.`,
|
|
56637
|
+
\u26A0\uFE0F Interrupted: no further wrap-up session runs and the loop opens no pull request. Run again to retry the wrap-up.`, ISSUE_NUMBER15, RAFA_ID;
|
|
55862
56638
|
var init_wrap_up_run = __esm(() => {
|
|
55863
56639
|
init_active();
|
|
55864
56640
|
init_device();
|
|
@@ -55875,7 +56651,7 @@ var init_wrap_up_run = __esm(() => {
|
|
|
55875
56651
|
init_runner_pr();
|
|
55876
56652
|
init_wrap_up_retry();
|
|
55877
56653
|
init_wrap_up();
|
|
55878
|
-
|
|
56654
|
+
ISSUE_NUMBER15 = /^#?(\d+)$/;
|
|
55879
56655
|
RAFA_ID = /(?:^|\/)rafa-(\d+)(?:-|$)/;
|
|
55880
56656
|
});
|
|
55881
56657
|
|
|
@@ -55898,8 +56674,8 @@ function msUntil(startAt, now = new Date) {
|
|
|
55898
56674
|
return target.getTime() - now.getTime();
|
|
55899
56675
|
}
|
|
55900
56676
|
function sleepFor(ms) {
|
|
55901
|
-
return new Promise((
|
|
55902
|
-
setTimeout(
|
|
56677
|
+
return new Promise((resolve38) => {
|
|
56678
|
+
setTimeout(resolve38, ms);
|
|
55903
56679
|
});
|
|
55904
56680
|
}
|
|
55905
56681
|
async function deferUntil(startAt, now = new Date, sleep = sleepFor) {
|
|
@@ -56845,7 +57621,7 @@ function poll(following, before, context, seams) {
|
|
|
56845
57621
|
}
|
|
56846
57622
|
return { cursor, found: null };
|
|
56847
57623
|
}
|
|
56848
|
-
function
|
|
57624
|
+
function lineOf4(found, following, session, reading2) {
|
|
56849
57625
|
if (found.event !== null)
|
|
56850
57626
|
return eventLine(found.event);
|
|
56851
57627
|
if (found.reason === "exit")
|
|
@@ -56866,7 +57642,7 @@ function resultOf6(found, following, seams) {
|
|
|
56866
57642
|
return {
|
|
56867
57643
|
reason: found.reason,
|
|
56868
57644
|
exitCode: found.reason === "timeout" ? WAIT_TIMEOUT_EXIT : waitExitCode(found.reason),
|
|
56869
|
-
line:
|
|
57645
|
+
line: lineOf4(found, following, session, reading2),
|
|
56870
57646
|
event: found.event,
|
|
56871
57647
|
session,
|
|
56872
57648
|
awakeMinutes: reading2.awakeMinutes,
|
|
@@ -57181,7 +57957,7 @@ var init_ceiling = __esm(() => {
|
|
|
57181
57957
|
});
|
|
57182
57958
|
|
|
57183
57959
|
// src/next/lines.ts
|
|
57184
|
-
function
|
|
57960
|
+
function stateLine2(state) {
|
|
57185
57961
|
return `${STATE_MARK} ${state.reading}.`;
|
|
57186
57962
|
}
|
|
57187
57963
|
function proposalLine(state, invocation) {
|
|
@@ -57347,7 +58123,7 @@ async function playTurn(options, state, previous) {
|
|
|
57347
58123
|
for (const problem2 of state.problems)
|
|
57348
58124
|
warn4(problem2);
|
|
57349
58125
|
const invocation = actionInvocation(state, passedOptions(roadmap));
|
|
57350
|
-
info2(
|
|
58126
|
+
info2(stateLine2(state));
|
|
57351
58127
|
info2(proposalLine(state, invocation));
|
|
57352
58128
|
const halt2 = (stop, over = {}) => ({ stop, step: stepOf3(state, invocation, over) });
|
|
57353
58129
|
if (dryRun !== null)
|
|
@@ -57373,7 +58149,7 @@ async function runNextChain(options) {
|
|
|
57373
58149
|
let steps = [];
|
|
57374
58150
|
let hops = [];
|
|
57375
58151
|
let previous = null;
|
|
57376
|
-
const
|
|
58152
|
+
const report3 = (stop) => Object.freeze({
|
|
57377
58153
|
steps: Object.freeze([...steps]),
|
|
57378
58154
|
stop,
|
|
57379
58155
|
...roadmap === undefined ? {} : { hops: Object.freeze([...hops]) }
|
|
@@ -57382,7 +58158,7 @@ async function runNextChain(options) {
|
|
|
57382
58158
|
const line = stopLine(stop, state, ceiling, dryRun, roadmap !== undefined);
|
|
57383
58159
|
if (line !== null)
|
|
57384
58160
|
info2(line);
|
|
57385
|
-
return
|
|
58161
|
+
return report3(stop);
|
|
57386
58162
|
};
|
|
57387
58163
|
const turn = async (state, before) => {
|
|
57388
58164
|
const end = await playTurn(options, state, before);
|
|
@@ -57421,8 +58197,8 @@ async function runStateAction(context, sources, state, passed2) {
|
|
|
57421
58197
|
if (outcome2.said !== "")
|
|
57422
58198
|
context.output.info(outcome2.said);
|
|
57423
58199
|
}
|
|
57424
|
-
function endOfEpic(context, sources,
|
|
57425
|
-
if (epic === null ||
|
|
58200
|
+
function endOfEpic(context, sources, report3, epic) {
|
|
58201
|
+
if (epic === null || report3.steps.at(-1)?.state !== "nothing-left")
|
|
57426
58202
|
return;
|
|
57427
58203
|
const release = sources.release();
|
|
57428
58204
|
if (release.problem !== null)
|
|
@@ -57456,7 +58232,7 @@ async function runNext(context, seams) {
|
|
|
57456
58232
|
const prompter = lazyPrompter2(openPrompter);
|
|
57457
58233
|
const dry = watchDryEpic();
|
|
57458
58234
|
try {
|
|
57459
|
-
const
|
|
58235
|
+
const report3 = await runNextChain({
|
|
57460
58236
|
read: () => readNextState(dry.watch(sources.answer())),
|
|
57461
58237
|
run: (state) => runStateAction(context, sources, state, {
|
|
57462
58238
|
roadmap: sources.roadmap !== undefined,
|
|
@@ -57477,8 +58253,8 @@ async function runNext(context, seams) {
|
|
|
57477
58253
|
}),
|
|
57478
58254
|
...roadmap ? { roadmap: { afterLoop: () => homeAfterLoop2(context, sources), claimAhead } } : {}
|
|
57479
58255
|
});
|
|
57480
|
-
endOfEpic(context, sources,
|
|
57481
|
-
return
|
|
58256
|
+
endOfEpic(context, sources, report3, dry.last());
|
|
58257
|
+
return report3;
|
|
57482
58258
|
} finally {
|
|
57483
58259
|
prompter.close();
|
|
57484
58260
|
}
|
|
@@ -57517,9 +58293,9 @@ function createNextCommand(seams = DEFAULT_NEXT_SEAMS) {
|
|
|
57517
58293
|
outputs: ["text", "json"],
|
|
57518
58294
|
spends: { when: "through", what: "when the step it runs is one of the above" },
|
|
57519
58295
|
run: async (context) => {
|
|
57520
|
-
const
|
|
58296
|
+
const report3 = await runNext(context, seams);
|
|
57521
58297
|
if (context.outputMode === "json")
|
|
57522
|
-
context.output.result(
|
|
58298
|
+
context.output.result(report3);
|
|
57523
58299
|
}
|
|
57524
58300
|
};
|
|
57525
58301
|
return Object.freeze(command);
|
|
@@ -57578,7 +58354,7 @@ import path6 from "path";
|
|
|
57578
58354
|
function unclaimed(issue4, cause, reason, pending = null, warnings = []) {
|
|
57579
58355
|
return { outcome: "unclaimed", issue: issue4, cause, reason, pending, warnings };
|
|
57580
58356
|
}
|
|
57581
|
-
function
|
|
58357
|
+
function refused5(attempt5, branch, owner, reason) {
|
|
57582
58358
|
return { outcome: "refused", issue: attempt5.issue, branch, owner, reason };
|
|
57583
58359
|
}
|
|
57584
58360
|
function claimed(attempt5, via, warnings = []) {
|
|
@@ -57641,7 +58417,7 @@ function claimOnRemote(attempt5, ahead, context) {
|
|
|
57641
58417
|
}
|
|
57642
58418
|
const listed4 = git(["for-each-ref", "--format=%(refname:lstrip=3)", `refs/remotes/${REMOTE}/${BRANCH_PREFIX2}`]);
|
|
57643
58419
|
if (!listed4.ok) {
|
|
57644
|
-
return
|
|
58420
|
+
return refused5(attempt5, attempt5.branch, null, `the ${REMOTE} branches of #${String(attempt5.issue)} could not be listed: ${gitSaid(listed4)}`);
|
|
57645
58421
|
}
|
|
57646
58422
|
const names2 = listed4.stdout.split(`
|
|
57647
58423
|
`).map((line) => line.trim());
|
|
@@ -57681,10 +58457,10 @@ function ownerOf(reading2) {
|
|
|
57681
58457
|
}
|
|
57682
58458
|
function unnamedRefusal(attempt5, reading2) {
|
|
57683
58459
|
if (reading2.state === "unreadable") {
|
|
57684
|
-
return
|
|
58460
|
+
return refused5(attempt5, reading2.branch, null, `the claim on ${reading2.branch} could not be read, so #${String(attempt5.issue)} stays taken: ${reading2.reason}`);
|
|
57685
58461
|
}
|
|
57686
58462
|
if (reading2.state === "found" && reading2.ownership.state === "none") {
|
|
57687
|
-
return
|
|
58463
|
+
return refused5(attempt5, reading2.branch, null, `${reading2.branch} exists on ${REMOTE} carrying no claim commit, so #${String(attempt5.issue)} stays taken`);
|
|
57688
58464
|
}
|
|
57689
58465
|
return null;
|
|
57690
58466
|
}
|
|
@@ -57704,16 +58480,16 @@ function otherBranchRefusal(attempt5, reading2, context) {
|
|
|
57704
58480
|
return null;
|
|
57705
58481
|
const { owner } = weighed;
|
|
57706
58482
|
if (owner === attempt5.storeId) {
|
|
57707
|
-
return
|
|
58483
|
+
return refused5(attempt5, branch, owner, `this device (store ${owner}) already holds ${issue4} on ${branch}; plan it there with --stub=${stubOf(branch)}`);
|
|
57708
58484
|
}
|
|
57709
|
-
return weighed.state === "stale-claimed" ?
|
|
58485
|
+
return weighed.state === "stale-claimed" ? refused5(attempt5, branch, owner, `${issue4} is claimed by store ${owner} on ${branch}, stale; take it over by planning there with --stub=${stubOf(branch)}`) : refused5(attempt5, branch, owner, `${issue4} is claimed by store ${owner} on ${branch}`);
|
|
57710
58486
|
}
|
|
57711
58487
|
function claimOwnBranch(attempt5, reading2, context) {
|
|
57712
58488
|
if (reading2.state === "absent")
|
|
57713
58489
|
return { kind: "fresh" };
|
|
57714
58490
|
const unreadable3 = () => ({
|
|
57715
58491
|
kind: "answer",
|
|
57716
|
-
answer:
|
|
58492
|
+
answer: refused5(attempt5, attempt5.branch, null, `the claim on ${attempt5.branch} could not be read`)
|
|
57717
58493
|
});
|
|
57718
58494
|
const unnamed = unnamedRefusal(attempt5, reading2);
|
|
57719
58495
|
if (unnamed !== null)
|
|
@@ -57729,7 +58505,7 @@ function claimOwnBranch(attempt5, reading2, context) {
|
|
|
57729
58505
|
return { kind: "held" };
|
|
57730
58506
|
const note = weighed.state === "stale-in-development" ? ", stale but in development, which is never taken over automatically" : "";
|
|
57731
58507
|
const reason = `#${String(attempt5.issue)} is claimed by store ${weighed.owner} on ${attempt5.branch}${note}`;
|
|
57732
|
-
return { kind: "answer", answer:
|
|
58508
|
+
return { kind: "answer", answer: refused5(attempt5, attempt5.branch, weighed.owner, reason) };
|
|
57733
58509
|
}
|
|
57734
58510
|
function tipOf(git, ref15) {
|
|
57735
58511
|
const resolved = git(["rev-parse", "--verify", "--quiet", `${ref15}^{commit}`]);
|
|
@@ -57813,7 +58589,7 @@ function pushFreshClaim(attempt5, git) {
|
|
|
57813
58589
|
return keepPending(attempt5, git, "push-failed", pushed.reason, staged.sha, staged.localTip);
|
|
57814
58590
|
if (pushed.outcome === "claimed") {
|
|
57815
58591
|
const owner = ownerOf(pushed.holder);
|
|
57816
|
-
return
|
|
58592
|
+
return refused5(attempt5, attempt5.branch, owner, raceReason(attempt5, "claimed", owner));
|
|
57817
58593
|
}
|
|
57818
58594
|
return claimed(attempt5, "claim", warningsOf(landLocal(attempt5, staged, git)));
|
|
57819
58595
|
}
|
|
@@ -57826,7 +58602,7 @@ function pushTake(attempt5, tip, git) {
|
|
|
57826
58602
|
return keepPending(attempt5, git, "push-failed", pushed.reason, staged.sha, staged.localTip);
|
|
57827
58603
|
if (pushed.outcome === "moved") {
|
|
57828
58604
|
const owner = refetchedOwner(git, attempt5.branch);
|
|
57829
|
-
return
|
|
58605
|
+
return refused5(attempt5, attempt5.branch, owner, raceReason(attempt5, "moved", owner));
|
|
57830
58606
|
}
|
|
57831
58607
|
return claimed(attempt5, "take", warningsOf(landLocal(attempt5, staged, git)));
|
|
57832
58608
|
}
|
|
@@ -57856,20 +58632,20 @@ function claimPair(home, ahead, git) {
|
|
|
57856
58632
|
const line = `#${String(forward.issue)}, the line ahead, was not claimed`;
|
|
57857
58633
|
if (ahead.move.kind === "answer") {
|
|
57858
58634
|
const reason = ahead.move.answer.outcome === "refused" ? ahead.move.answer.reason : `the claim on ${forward.branch} could not be read`;
|
|
57859
|
-
const
|
|
57860
|
-
return neither(home, git, "ahead-taken", pairWhy(forward.issue, reason),
|
|
58635
|
+
const report3 = aheadNotClaimed(forward.issue, "taken", `${line}: ${reason}`);
|
|
58636
|
+
return neither(home, git, "ahead-taken", pairWhy(forward.issue, reason), report3);
|
|
57861
58637
|
}
|
|
57862
58638
|
if (ahead.move.kind === "held")
|
|
57863
58639
|
return withAhead(carryOut(home.attempt, home.move, git), aheadClaimed(forward, "held"));
|
|
57864
58640
|
const aheadStaged = stage(forward, ahead.move, git);
|
|
57865
58641
|
if (!aheadStaged.ok) {
|
|
57866
|
-
const
|
|
57867
|
-
return neither(home, git, "commit-failed", pairWhy(forward.issue, aheadStaged.reason),
|
|
58642
|
+
const report3 = aheadNotClaimed(forward.issue, "failed", `${line}: ${aheadStaged.reason}`);
|
|
58643
|
+
return neither(home, git, "commit-failed", pairWhy(forward.issue, aheadStaged.reason), report3);
|
|
57868
58644
|
}
|
|
57869
58645
|
const homeStaged = home.move.kind === "held" ? null : stage(home.attempt, home.move, git);
|
|
57870
58646
|
if (homeStaged?.ok === false) {
|
|
57871
|
-
const
|
|
57872
|
-
return withAhead(unclaimed(home.attempt.issue, "commit-failed", homeStaged.reason),
|
|
58647
|
+
const report3 = aheadNotClaimed(forward.issue, "not-tried", `${line}: the claim on #${String(home.attempt.issue)} could not be made`);
|
|
58648
|
+
return withAhead(unclaimed(home.attempt.issue, "commit-failed", homeStaged.reason), report3);
|
|
57873
58649
|
}
|
|
57874
58650
|
return pushPair(home, homeStaged, { attempt: forward, staged: aheadStaged }, git);
|
|
57875
58651
|
}
|
|
@@ -57888,16 +58664,16 @@ function pushPair(home, homeStaged, ahead, git) {
|
|
|
57888
58664
|
}
|
|
57889
58665
|
if (pushed.outcome === "refused" && pushed.branch === home.attempt.branch) {
|
|
57890
58666
|
const owner = refetchedOwner(git, home.attempt.branch);
|
|
57891
|
-
return
|
|
58667
|
+
return refused5(home.attempt, home.attempt.branch, owner, raceReason(home.attempt, pushed.by, owner));
|
|
57892
58668
|
}
|
|
57893
58669
|
const reason = pushed.outcome === "refused" ? raceReason(forward, pushed.by, refetchedOwner(git, forward.branch)) : pushed.reason;
|
|
57894
58670
|
const cause = pushed.outcome === "refused" ? "taken" : "failed";
|
|
57895
|
-
const
|
|
58671
|
+
const report3 = aheadNotClaimed(forward.issue, cause, `${line}: ${reason}`);
|
|
57896
58672
|
if (homeStaged === null)
|
|
57897
|
-
return withAhead(claimed(home.attempt, "held"),
|
|
58673
|
+
return withAhead(claimed(home.attempt, "held"), report3);
|
|
57898
58674
|
const homeCause = pushed.outcome === "refused" ? "ahead-taken" : "push-failed";
|
|
57899
58675
|
const why = pushed.outcome === "refused" ? pairWhy(forward.issue, reason) : reason;
|
|
57900
|
-
return withAhead(keepPending(home.attempt, git, homeCause, why, homeStaged.sha, homeStaged.localTip),
|
|
58676
|
+
return withAhead(keepPending(home.attempt, git, homeCause, why, homeStaged.sha, homeStaged.localTip), report3);
|
|
57901
58677
|
}
|
|
57902
58678
|
var init_plan_claim = __esm(() => {
|
|
57903
58679
|
init_roadmap_claims();
|
|
@@ -57953,7 +58729,7 @@ async function aheadRequestOf(spec, setting, output) {
|
|
|
57953
58729
|
return;
|
|
57954
58730
|
}
|
|
57955
58731
|
}
|
|
57956
|
-
function
|
|
58732
|
+
function report3(claim, output) {
|
|
57957
58733
|
if (claim.outcome === "claimed") {
|
|
57958
58734
|
output.info(claimedLine(claim));
|
|
57959
58735
|
} else {
|
|
@@ -57985,7 +58761,7 @@ async function resolveAndClaim(seams) {
|
|
|
57985
58761
|
...ahead === undefined ? {} : { ahead }
|
|
57986
58762
|
});
|
|
57987
58763
|
if (claim.outcome !== "refused") {
|
|
57988
|
-
|
|
58764
|
+
report3(claim, output);
|
|
57989
58765
|
return { outcome: "spec", spec, gate, stub, claim };
|
|
57990
58766
|
}
|
|
57991
58767
|
if (spec.kind !== "next")
|
|
@@ -58514,7 +59290,7 @@ var init_create2 = __esm(() => {
|
|
|
58514
59290
|
|
|
58515
59291
|
// src/commands/plan/risk.ts
|
|
58516
59292
|
import { readFileSync as readFileSync72 } from "fs";
|
|
58517
|
-
import { resolve as
|
|
59293
|
+
import { resolve as resolve38 } from "path";
|
|
58518
59294
|
function spawningRunners2(root) {
|
|
58519
59295
|
return { git: createGitRunner(root), gh: createGhRunner({ cwd: root }) };
|
|
58520
59296
|
}
|
|
@@ -58524,7 +59300,7 @@ function riskPlanPath(root, planDir, typed) {
|
|
|
58524
59300
|
return path9;
|
|
58525
59301
|
if (typed !== null)
|
|
58526
59302
|
throw new CommandExit(1, `\u274C Plan file not found: ${path9}`);
|
|
58527
|
-
const lookedFor = [...new Set([
|
|
59303
|
+
const lookedFor = [...new Set([resolve38(root, planDir, DEFAULT_PLAN_FILE), resolve38(root, DEFAULT_PLAN_FILE)])];
|
|
58528
59304
|
throw new CommandExit(1, `\u274C No plan named, and no default plan at ${lookedFor.join(" or ")}
|
|
58529
59305
|
Usage: ${USAGE38}`);
|
|
58530
59306
|
}
|
|
@@ -58533,8 +59309,8 @@ function riskLine(finding2) {
|
|
|
58533
59309
|
const place2 = finding2.file === undefined ? "" : `${finding2.file}${line}: `;
|
|
58534
59310
|
return `${place2}${finding2.kind}: ${finding2.text}`;
|
|
58535
59311
|
}
|
|
58536
|
-
function strictRefusal(
|
|
58537
|
-
return `\u274C ${
|
|
59312
|
+
function strictRefusal(report4) {
|
|
59313
|
+
return `\u274C ${report4.plan}: ${plural(report4.total.high, "high finding")}; --strict refuses a plan with any`;
|
|
58538
59314
|
}
|
|
58539
59315
|
async function readRisk(path9, project, config, context, seams) {
|
|
58540
59316
|
const makeRunners = seams.runners ?? spawningRunners2;
|
|
@@ -58596,24 +59372,24 @@ function createPlanRiskCommand(seams = {}) {
|
|
|
58596
59372
|
context.output.warn(message);
|
|
58597
59373
|
});
|
|
58598
59374
|
const path9 = riskPlanPath(project.root, config.planDir, typed);
|
|
58599
|
-
const
|
|
58600
|
-
const
|
|
59375
|
+
const report4 = await readRisk(path9, project, config, context, seams);
|
|
59376
|
+
const refused6 = strict && report4.total.high > 0;
|
|
58601
59377
|
if (context.outputMode === "json") {
|
|
58602
|
-
if (!
|
|
58603
|
-
context.output.result(
|
|
59378
|
+
if (!refused6) {
|
|
59379
|
+
context.output.result(report4);
|
|
58604
59380
|
return;
|
|
58605
59381
|
}
|
|
58606
|
-
for (const finding2 of
|
|
59382
|
+
for (const finding2 of report4.findings) {
|
|
58607
59383
|
if (finding2.level === "high")
|
|
58608
59384
|
context.output.error(riskLine(finding2));
|
|
58609
59385
|
}
|
|
58610
59386
|
} else {
|
|
58611
|
-
for (const line of renderRiskText(
|
|
59387
|
+
for (const line of renderRiskText(report4).split(`
|
|
58612
59388
|
`))
|
|
58613
59389
|
context.output.info(line);
|
|
58614
59390
|
}
|
|
58615
|
-
if (
|
|
58616
|
-
throw new CommandExit(1, strictRefusal(
|
|
59391
|
+
if (refused6)
|
|
59392
|
+
throw new CommandExit(1, strictRefusal(report4));
|
|
58617
59393
|
}
|
|
58618
59394
|
};
|
|
58619
59395
|
return Object.freeze(command);
|
|
@@ -58632,7 +59408,7 @@ var init_risk2 = __esm(() => {
|
|
|
58632
59408
|
|
|
58633
59409
|
// src/commands/plan/show.ts
|
|
58634
59410
|
import { readFileSync as readFileSync73 } from "fs";
|
|
58635
|
-
import { join as
|
|
59411
|
+
import { join as join90 } from "path";
|
|
58636
59412
|
function readTrackerFlag(value) {
|
|
58637
59413
|
if (value === undefined || value === false || value === "false")
|
|
58638
59414
|
return false;
|
|
@@ -58648,9 +59424,9 @@ function showPlan(plans, stub, tracker) {
|
|
|
58648
59424
|
throw new CommandExit(1, `\u274C "${stub}" is no plan stub: a stub is letters, digits, ".", "_" and "-"`);
|
|
58649
59425
|
}
|
|
58650
59426
|
const name2 = planFileName(stub, tracker);
|
|
58651
|
-
const file =
|
|
59427
|
+
const file = join90(plans.path, name2);
|
|
58652
59428
|
if (!isFile(file))
|
|
58653
|
-
throw new CommandExit(1, missingText(stub, tracker,
|
|
59429
|
+
throw new CommandExit(1, missingText(stub, tracker, join90(plans.label, name2)));
|
|
58654
59430
|
const model = parsePlan(readFileSync73(file, "utf8"));
|
|
58655
59431
|
const { header } = model;
|
|
58656
59432
|
return {
|
|
@@ -58674,7 +59450,7 @@ function taskLine2(task) {
|
|
|
58674
59450
|
return ` ${checkbox(task.status)} ${task.text}`;
|
|
58675
59451
|
}
|
|
58676
59452
|
function renderShownPlan(shown2, dirLabel) {
|
|
58677
|
-
const relative21 =
|
|
59453
|
+
const relative21 = join90(dirLabel, planFileName(shown2.stub, shown2.tracker));
|
|
58678
59454
|
const fileLabel = shown2.tracker ? "Tracker" : "File";
|
|
58679
59455
|
const lines2 = [`Plan: ${shown2.stub}`, `${fileLabel}: ${relative21}`];
|
|
58680
59456
|
if (shown2.header.issue !== null)
|
|
@@ -59254,7 +60030,7 @@ function freedIssueLine(issue4) {
|
|
|
59254
60030
|
const title2 = issue4.title.trim();
|
|
59255
60031
|
return title2 === "" ? `${INDENT5}#${String(issue4.number)}` : `${INDENT5}#${String(issue4.number)} ${title2}`;
|
|
59256
60032
|
}
|
|
59257
|
-
function
|
|
60033
|
+
function report4(closed, freed, problem2) {
|
|
59258
60034
|
return Object.freeze({ relationships: "native", closed, freed: Object.freeze(freed), problem: problem2 });
|
|
59259
60035
|
}
|
|
59260
60036
|
async function readFreed(gh, closed) {
|
|
@@ -59275,14 +60051,14 @@ async function freedAfterMerge(options) {
|
|
|
59275
60051
|
} catch (error) {
|
|
59276
60052
|
const problem2 = messageOf(error);
|
|
59277
60053
|
warn4(freedProblemLine(problem2));
|
|
59278
|
-
return
|
|
60054
|
+
return report4(closed, [], problem2);
|
|
59279
60055
|
}
|
|
59280
60056
|
if (freed.length > 0) {
|
|
59281
60057
|
info2(freedHeaderLine(closed, freed.length));
|
|
59282
60058
|
for (const issue4 of freed)
|
|
59283
60059
|
info2(freedIssueLine(issue4));
|
|
59284
60060
|
}
|
|
59285
|
-
return
|
|
60061
|
+
return report4(closed, freed, null);
|
|
59286
60062
|
}
|
|
59287
60063
|
var READING2 = "the freed-issue reading";
|
|
59288
60064
|
var init_merge_freed = __esm(() => {
|
|
@@ -59348,13 +60124,13 @@ async function guardBeforeMerge(step2) {
|
|
|
59348
60124
|
const answer5 = answerOf2(reading2);
|
|
59349
60125
|
const reaction = guardReaction(reading2, settings);
|
|
59350
60126
|
const lines2 = guardLines(reading2, settings.releaseVersionFile);
|
|
59351
|
-
const
|
|
60127
|
+
const report5 = { answer: answer5, reaction, lines: lines2 };
|
|
59352
60128
|
if (reaction === "refuse")
|
|
59353
60129
|
throw guardRefusal(refusalHead(step2.detail.number, answer5), lines2);
|
|
59354
60130
|
if (reaction === "ask")
|
|
59355
|
-
return { report:
|
|
60131
|
+
return { report: report5, go: await askGuard(step2, answer5, lines2) };
|
|
59356
60132
|
printLines(step2, reaction, lines2);
|
|
59357
|
-
return { report:
|
|
60133
|
+
return { report: report5, go: true };
|
|
59358
60134
|
}
|
|
59359
60135
|
var YES_ANSWERS4;
|
|
59360
60136
|
var init_merge_guard = __esm(() => {
|
|
@@ -59366,15 +60142,15 @@ var init_merge_guard = __esm(() => {
|
|
|
59366
60142
|
});
|
|
59367
60143
|
|
|
59368
60144
|
// src/commands/pr/merge-loop-worktree.ts
|
|
59369
|
-
import { copyFileSync as copyFileSync5, mkdirSync as
|
|
59370
|
-
import { dirname as dirname33, isAbsolute as isAbsolute24, join as
|
|
60145
|
+
import { copyFileSync as copyFileSync5, mkdirSync as mkdirSync26, realpathSync as realpathSync16, statSync as statSync29 } from "fs";
|
|
60146
|
+
import { dirname as dirname33, isAbsolute as isAbsolute24, join as join91, relative as relative21, resolve as resolve39, sep as sep8 } from "path";
|
|
59371
60147
|
function defaultLoopWorktreeSeams(mainCheckout) {
|
|
59372
60148
|
return {
|
|
59373
60149
|
git: createGitRunner(mainCheckout),
|
|
59374
60150
|
gitAt: createGitRunner,
|
|
59375
|
-
modifiedAt: (path9) =>
|
|
60151
|
+
modifiedAt: (path9) => statSync29(path9, { throwIfNoEntry: false })?.mtime ?? null,
|
|
59376
60152
|
copyFile: (from, to) => {
|
|
59377
|
-
|
|
60153
|
+
mkdirSync26(dirname33(to), { recursive: true });
|
|
59378
60154
|
copyFileSync5(from, to);
|
|
59379
60155
|
},
|
|
59380
60156
|
realPath: (path9) => {
|
|
@@ -59405,11 +60181,11 @@ function readLoopHolder(seams, reading2) {
|
|
|
59405
60181
|
};
|
|
59406
60182
|
}
|
|
59407
60183
|
function freeLoopWorktree(seams, reading2, holder) {
|
|
59408
|
-
const into =
|
|
60184
|
+
const into = resolve39(reading2.mainCheckout, reading2.planDir);
|
|
59409
60185
|
const files = [];
|
|
59410
60186
|
for (const name2 of planFileNames(holder.stub)) {
|
|
59411
|
-
const from =
|
|
59412
|
-
const to =
|
|
60187
|
+
const from = resolve39(holder.path, reading2.planDir, name2);
|
|
60188
|
+
const to = join91(into, name2);
|
|
59413
60189
|
try {
|
|
59414
60190
|
files.push({ name: name2, from, to, outcome: copyPlanFile(seams, from, to) });
|
|
59415
60191
|
} catch (error) {
|
|
@@ -60274,7 +61050,7 @@ function readCap(value) {
|
|
|
60274
61050
|
if (value === undefined)
|
|
60275
61051
|
return FAILED_LOG_TAIL_LINES;
|
|
60276
61052
|
if (!Number.isSafeInteger(value) || value < 1) {
|
|
60277
|
-
throw new TypeError(`${
|
|
61053
|
+
throw new TypeError(`${PREFIX36}: readFailedLog refused a line cap ${describeValue(value)},` + " expected a positive whole number");
|
|
60278
61054
|
}
|
|
60279
61055
|
return value;
|
|
60280
61056
|
}
|
|
@@ -60290,7 +61066,7 @@ function readFailedLog(text2, options = {}) {
|
|
|
60290
61066
|
total: lines2.length
|
|
60291
61067
|
};
|
|
60292
61068
|
}
|
|
60293
|
-
var FAILED_LOG_TAIL_LINES = 40, UNKNOWN_STEP = "UNKNOWN STEP", GROUP_STEP_PREFIX = "##[group]Run ", ERROR_PREFIX2 = "##[error]", COLUMN = "\t", BOM = "\uFEFF", TIMESTAMP, COLOUR,
|
|
61069
|
+
var FAILED_LOG_TAIL_LINES = 40, UNKNOWN_STEP = "UNKNOWN STEP", GROUP_STEP_PREFIX = "##[group]Run ", ERROR_PREFIX2 = "##[error]", COLUMN = "\t", BOM = "\uFEFF", TIMESTAMP, COLOUR, PREFIX36 = "pr triage evidence";
|
|
60294
61070
|
var init_evidence = __esm(() => {
|
|
60295
61071
|
init_config_sections();
|
|
60296
61072
|
TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z /;
|
|
@@ -61236,8 +62012,8 @@ function describeAge(updatedAt, now) {
|
|
|
61236
62012
|
return `${plural7(hours, "hour", "hours")} ago`;
|
|
61237
62013
|
return `${plural7(Math.floor(age / DAY_MS2), "day", "days")} ago`;
|
|
61238
62014
|
}
|
|
61239
|
-
function triageCommand(number,
|
|
61240
|
-
return
|
|
62015
|
+
function triageCommand(number, resolve40 = false) {
|
|
62016
|
+
return resolve40 ? `rafa pr triage ${number} --resolve` : `rafa pr triage ${number}`;
|
|
61241
62017
|
}
|
|
61242
62018
|
function joinNumbers(pulls) {
|
|
61243
62019
|
const names2 = pulls.map((pull2) => `#${pull2.number}`);
|
|
@@ -61248,14 +62024,14 @@ function joinNumbers(pulls) {
|
|
|
61248
62024
|
function byNumber4(pulls) {
|
|
61249
62025
|
return Object.freeze([...pulls].sort((left, right) => left.number - right.number));
|
|
61250
62026
|
}
|
|
61251
|
-
function skipped2(pull2, now,
|
|
62027
|
+
function skipped2(pull2, now, resolve40) {
|
|
61252
62028
|
return Object.freeze({
|
|
61253
62029
|
number: pull2.number,
|
|
61254
62030
|
title: pull2.title,
|
|
61255
62031
|
updatedAt: pull2.updatedAt,
|
|
61256
62032
|
age: describeAge(pull2.updatedAt, now),
|
|
61257
62033
|
fresh: isFreshCandidate(pull2.updatedAt, now),
|
|
61258
|
-
command: triageCommand(pull2.number,
|
|
62034
|
+
command: triageCommand(pull2.number, resolve40)
|
|
61259
62035
|
});
|
|
61260
62036
|
}
|
|
61261
62037
|
function skippedLine(one) {
|
|
@@ -61299,15 +62075,15 @@ function listReading(rest, count2) {
|
|
|
61299
62075
|
return listing2("list", Object.freeze([]), rest, headline);
|
|
61300
62076
|
}
|
|
61301
62077
|
function selectTriagePullRequests(input) {
|
|
61302
|
-
const
|
|
62078
|
+
const resolve40 = input.resolve === true;
|
|
61303
62079
|
const { current, now } = input;
|
|
61304
62080
|
if (current !== null) {
|
|
61305
62081
|
return plain("branch", Object.freeze([current]), `assessing #${current.number}, the pull request open on ${current.headRefName}`);
|
|
61306
62082
|
}
|
|
61307
62083
|
const candidates = byNumber4(input.candidates);
|
|
61308
62084
|
const count2 = candidates.length;
|
|
61309
|
-
const lines2 = candidates.map((pull2) => skipped2(pull2, now,
|
|
61310
|
-
if (
|
|
62085
|
+
const lines2 = candidates.map((pull2) => skipped2(pull2, now, resolve40));
|
|
62086
|
+
if (resolve40 && count2 > 1)
|
|
61311
62087
|
return refusal15(lines2, count2);
|
|
61312
62088
|
if (count2 === 0) {
|
|
61313
62089
|
return plain("none", Object.freeze([]), "no red pull request to triage, and no pull request on the current branch");
|
|
@@ -61663,7 +62439,7 @@ var init_triage_report = __esm(() => {
|
|
|
61663
62439
|
function budgetEntry(usd) {
|
|
61664
62440
|
const spelled2 = String(usd);
|
|
61665
62441
|
if (parseBudgetUsd(spelled2) === null) {
|
|
61666
|
-
throw new TypeError(`${
|
|
62442
|
+
throw new TypeError(`${PREFIX37}: refused an amount of ${JSON.stringify(usd)}, expected US dollars above zero` + " with at most six whole digits and six decimal places");
|
|
61667
62443
|
}
|
|
61668
62444
|
return `${BUDGET_KEY}=${spelled2}`;
|
|
61669
62445
|
}
|
|
@@ -61690,7 +62466,7 @@ function withTaskBudget(plan2, usd) {
|
|
|
61690
62466
|
`).map((line) => TASK_LINE2.test(line) ? withEntry(line, entry) : line).join(`
|
|
61691
62467
|
`);
|
|
61692
62468
|
}
|
|
61693
|
-
var BUDGET_KEY = "budget", TASK_LINE2, TRAILING_BLOCK,
|
|
62469
|
+
var BUDGET_KEY = "budget", TASK_LINE2, TRAILING_BLOCK, PREFIX37 = "pr triage --resolve budget";
|
|
61694
62470
|
var init_budget2 = __esm(() => {
|
|
61695
62471
|
init_declaration();
|
|
61696
62472
|
TASK_LINE2 = /^- \[[^\]]*\] /;
|
|
@@ -61698,8 +62474,8 @@ var init_budget2 = __esm(() => {
|
|
|
61698
62474
|
});
|
|
61699
62475
|
|
|
61700
62476
|
// src/pr/plans/load.ts
|
|
61701
|
-
import { existsSync as
|
|
61702
|
-
import { dirname as dirname34, join as
|
|
62477
|
+
import { existsSync as existsSync61, readFileSync as readFileSync74 } from "fs";
|
|
62478
|
+
import { dirname as dirname34, join as join92 } from "path";
|
|
61703
62479
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
61704
62480
|
function pinnedPlanFileName(triageClass) {
|
|
61705
62481
|
return `resolve-${triageClass}.md`;
|
|
@@ -61710,8 +62486,8 @@ function hasPinnedPlan(triageClass) {
|
|
|
61710
62486
|
function pinnedPlanCandidates(moduleDir, triageClass) {
|
|
61711
62487
|
const name2 = pinnedPlanFileName(triageClass);
|
|
61712
62488
|
return [
|
|
61713
|
-
|
|
61714
|
-
|
|
62489
|
+
join92(moduleDir, PINNED_PLANS_DIRNAME, name2),
|
|
62490
|
+
join92(moduleDir, name2)
|
|
61715
62491
|
];
|
|
61716
62492
|
}
|
|
61717
62493
|
function readPinnedPlan(triageClass, lookup = {}) {
|
|
@@ -61719,7 +62495,7 @@ function readPinnedPlan(triageClass, lookup = {}) {
|
|
|
61719
62495
|
throw new Error(`No pinned resolve plan ships for ${triageClass}; ` + `one ships for ${PINNED_PLAN_CLASSES.join(", ")}`);
|
|
61720
62496
|
}
|
|
61721
62497
|
const candidates = pinnedPlanCandidates(lookup.moduleDir ?? MODULE_DIR5, triageClass);
|
|
61722
|
-
const found = candidates.find((candidate) =>
|
|
62498
|
+
const found = candidates.find((candidate) => existsSync61(candidate));
|
|
61723
62499
|
if (found === undefined) {
|
|
61724
62500
|
throw new Error(`The pinned resolve plan for ${triageClass} is missing: ` + `no file at ${candidates.join(" or ")}`);
|
|
61725
62501
|
}
|
|
@@ -61790,7 +62566,7 @@ var init_load2 = __esm(() => {
|
|
|
61790
62566
|
// src/pr/triage/attempts.ts
|
|
61791
62567
|
function readCap2(maxAttempts) {
|
|
61792
62568
|
if (!Number.isSafeInteger(maxAttempts) || maxAttempts < 1) {
|
|
61793
|
-
throw new TypeError(`${
|
|
62569
|
+
throw new TypeError(`${PREFIX38}: refused a cap of ${JSON.stringify(maxAttempts)},` + " expected a positive whole number");
|
|
61794
62570
|
}
|
|
61795
62571
|
return maxAttempts;
|
|
61796
62572
|
}
|
|
@@ -61860,7 +62636,7 @@ function readAttemptRepeat(input) {
|
|
|
61860
62636
|
reason: `attempt ${attempts} ended as \`${outcome2.triageClass}\`` + ` ${describeStep(outcome2.step)}, ${against}`
|
|
61861
62637
|
};
|
|
61862
62638
|
}
|
|
61863
|
-
var ATTEMPT_STOPS,
|
|
62639
|
+
var ATTEMPT_STOPS, PREFIX38 = "pr triage attempts", WHITESPACE5, NO_STEP_KEY = "";
|
|
61864
62640
|
var init_attempts = __esm(() => {
|
|
61865
62641
|
ATTEMPT_STOPS = Object.freeze([
|
|
61866
62642
|
"cap",
|
|
@@ -61870,16 +62646,16 @@ var init_attempts = __esm(() => {
|
|
|
61870
62646
|
});
|
|
61871
62647
|
|
|
61872
62648
|
// src/commands/pr/resolve-loop.ts
|
|
61873
|
-
import { mkdirSync as
|
|
61874
|
-
import { join as
|
|
62649
|
+
import { mkdirSync as mkdirSync27, writeFileSync as writeFileSync29 } from "fs";
|
|
62650
|
+
import { join as join93 } from "path";
|
|
61875
62651
|
function resolveRunDir(home, number, attempt5) {
|
|
61876
|
-
return
|
|
62652
|
+
return join93(home, RESOLVE_SUBDIR, `${RUN_PREFIX}${number}`, `${ATTEMPT_PREFIX}${attempt5}`);
|
|
61877
62653
|
}
|
|
61878
62654
|
function writeResolvePlan(write) {
|
|
61879
62655
|
const dir = resolveRunDir(write.home, write.number, write.attempt);
|
|
61880
|
-
|
|
61881
|
-
const path9 =
|
|
61882
|
-
|
|
62656
|
+
mkdirSync27(dir, { recursive: true });
|
|
62657
|
+
const path9 = join93(dir, pinnedPlanFileName(write.triageClass));
|
|
62658
|
+
writeFileSync29(path9, write.plan, "utf8");
|
|
61883
62659
|
return path9;
|
|
61884
62660
|
}
|
|
61885
62661
|
function resolveLoopArgv(planPath) {
|
|
@@ -61921,13 +62697,13 @@ var RESOLVE_SUBDIR, RUN_PREFIX = "pr-", ATTEMPT_PREFIX = "attempt-", LOOP_WORDS,
|
|
|
61921
62697
|
var init_resolve_loop = __esm(() => {
|
|
61922
62698
|
init_config_sections();
|
|
61923
62699
|
init_load2();
|
|
61924
|
-
RESOLVE_SUBDIR =
|
|
62700
|
+
RESOLVE_SUBDIR = join93(".rafa", "resolve");
|
|
61925
62701
|
LOOP_WORDS = Object.freeze(["loop", "start"]);
|
|
61926
62702
|
});
|
|
61927
62703
|
|
|
61928
62704
|
// src/pr/triage/version-convert.ts
|
|
61929
|
-
import { mkdirSync as
|
|
61930
|
-
import { dirname as dirname35, join as
|
|
62705
|
+
import { mkdirSync as mkdirSync28, readFileSync as readFileSync75, writeFileSync as writeFileSync30 } from "fs";
|
|
62706
|
+
import { dirname as dirname35, join as join94, posix as posix9 } from "path";
|
|
61931
62707
|
function conversionLevel(from, to) {
|
|
61932
62708
|
if (from === null)
|
|
61933
62709
|
return null;
|
|
@@ -61966,7 +62742,7 @@ function fragmentNamesAt(git, commit, directory2) {
|
|
|
61966
62742
|
return [];
|
|
61967
62743
|
return listed4.stdout.split("\x00").filter((path9) => path9 !== "").map((path9) => posix9.basename(path9));
|
|
61968
62744
|
}
|
|
61969
|
-
function
|
|
62745
|
+
function refused6(problem2, problems) {
|
|
61970
62746
|
return { outcome: "refused", problem: problem2, problems };
|
|
61971
62747
|
}
|
|
61972
62748
|
function fragmentTitle2(title2, plan2) {
|
|
@@ -62003,9 +62779,9 @@ function planConversion(input, problems) {
|
|
|
62003
62779
|
const baseRef = `${input.remote ?? RELEASE_REMOTE}/${input.base}`;
|
|
62004
62780
|
const headCommit = commitOf2(git, "HEAD");
|
|
62005
62781
|
if (headCommit === null)
|
|
62006
|
-
return
|
|
62782
|
+
return refused6(`the worktree at ${input.worktree} has no HEAD commit`, problems);
|
|
62007
62783
|
if (input.head !== null && headCommit !== input.head) {
|
|
62008
|
-
return
|
|
62784
|
+
return refused6(`the worktree's ${input.branch} is at ${headCommit.slice(0, SHORT_HASH_LENGTH2)}, not at the pull request's` + ` head ${input.head.slice(0, SHORT_HASH_LENGTH2)}; bring the branch up to its pull request's head and run it again`, problems);
|
|
62009
62785
|
}
|
|
62010
62786
|
const guard = readGuard({
|
|
62011
62787
|
git,
|
|
@@ -62015,7 +62791,7 @@ function planConversion(input, problems) {
|
|
|
62015
62791
|
now: input.now
|
|
62016
62792
|
});
|
|
62017
62793
|
if (!guard.ok)
|
|
62018
|
-
return
|
|
62794
|
+
return refused6(`the release guard could not read ${input.branch}: ${guard.problem}`, problems);
|
|
62019
62795
|
const { verdict } = guard;
|
|
62020
62796
|
if (verdict.answer === "clean" || verdict.answer === "missing") {
|
|
62021
62797
|
return { outcome: "unstamped", answer: verdict.answer, problems };
|
|
@@ -62023,25 +62799,25 @@ function planConversion(input, problems) {
|
|
|
62023
62799
|
const { stamp: stamp2 } = verdict;
|
|
62024
62800
|
const start2 = mergeBaseSide(git, guard.base.commit, headCommit, settings);
|
|
62025
62801
|
if (start2 === null)
|
|
62026
|
-
return
|
|
62802
|
+
return refused6(`${input.branch} and ${baseRef} share no merge base`, problems);
|
|
62027
62803
|
const level = conversionLevel(start2.version, stamp2.version);
|
|
62028
62804
|
if (level === null) {
|
|
62029
|
-
return
|
|
62805
|
+
return refused6(`no release level reads off the stamp: ${input.branch} stamped ${stamp2.version} over` + ` ${start2.version ?? "no version"} at its merge base with ${baseRef}`, problems);
|
|
62030
62806
|
}
|
|
62031
62807
|
if (start2.version === null)
|
|
62032
|
-
return
|
|
62808
|
+
return refused6(`the merge base declares no version in ${settings.releaseVersionFile} to restore`, problems);
|
|
62033
62809
|
if (start2.changelog === null) {
|
|
62034
|
-
return
|
|
62810
|
+
return refused6(`the merge base holds no ${settings.releaseChangelog}, so ${input.branch} created it and there is no text to restore`, problems);
|
|
62035
62811
|
}
|
|
62036
62812
|
let branchVersionText;
|
|
62037
62813
|
try {
|
|
62038
|
-
branchVersionText = readFileSync75(
|
|
62814
|
+
branchVersionText = readFileSync75(join94(input.worktree, settings.releaseVersionFile), "utf8");
|
|
62039
62815
|
} catch (error) {
|
|
62040
|
-
return
|
|
62816
|
+
return refused6(`${settings.releaseVersionFile} could not be read in the worktree: ${messageOf(error)}`, problems);
|
|
62041
62817
|
}
|
|
62042
62818
|
const rewritten = replaceManifestVersion(branchVersionText, start2.version);
|
|
62043
62819
|
if (rewritten === null) {
|
|
62044
|
-
return
|
|
62820
|
+
return refused6(`${input.branch}'s ${settings.releaseVersionFile} holds no version pair ${start2.version} could be written over`, problems);
|
|
62045
62821
|
}
|
|
62046
62822
|
return {
|
|
62047
62823
|
stamp: stamp2,
|
|
@@ -62061,10 +62837,10 @@ function writeConversion(input, plan2) {
|
|
|
62061
62837
|
[input.settings.releaseChangelog, plan2.changelogText]
|
|
62062
62838
|
];
|
|
62063
62839
|
for (const [path9, text2] of writes) {
|
|
62064
|
-
const target =
|
|
62840
|
+
const target = join94(input.worktree, path9);
|
|
62065
62841
|
try {
|
|
62066
|
-
|
|
62067
|
-
|
|
62842
|
+
mkdirSync28(dirname35(target), { recursive: true });
|
|
62843
|
+
writeFileSync30(target, text2);
|
|
62068
62844
|
} catch (error) {
|
|
62069
62845
|
return `${path9} could not be written in the worktree, which may hold part of the conversion: ${messageOf(error)}`;
|
|
62070
62846
|
}
|
|
@@ -62083,18 +62859,18 @@ function convertStampedVersion(input) {
|
|
|
62083
62859
|
return plan2;
|
|
62084
62860
|
const written3 = writeConversion(input, plan2);
|
|
62085
62861
|
if (written3 !== null)
|
|
62086
|
-
return
|
|
62862
|
+
return refused6(written3, problems);
|
|
62087
62863
|
const paths = [plan2.fragmentPath, settings.releaseVersionFile, settings.releaseChangelog].map((path9) => gitPathOf(path9));
|
|
62088
62864
|
const added = git(["add", "--", ...paths]);
|
|
62089
62865
|
if (!added.ok)
|
|
62090
|
-
return
|
|
62866
|
+
return refused6(`the conversion's files could not be staged, and are left in the worktree: ${gitSaid(added)}`, problems);
|
|
62091
62867
|
const subject = conversionCommitSubject(plan2.plan, plan2.stamp.version);
|
|
62092
62868
|
const made = git(["commit", "--cleanup=whitespace", "-m", subject, "--", ...paths]);
|
|
62093
62869
|
if (!made.ok)
|
|
62094
|
-
return
|
|
62870
|
+
return refused6(`the conversion could not be committed, and is left staged in the worktree: ${gitSaid(made)}`, problems);
|
|
62095
62871
|
const commit = commitOf2(git, "HEAD");
|
|
62096
62872
|
if (commit === null)
|
|
62097
|
-
return
|
|
62873
|
+
return refused6("the conversion was committed, but HEAD names no commit to report", problems);
|
|
62098
62874
|
return {
|
|
62099
62875
|
outcome: "converted",
|
|
62100
62876
|
commit,
|
|
@@ -62563,16 +63339,16 @@ async function redPullRequests(pr) {
|
|
|
62563
63339
|
}
|
|
62564
63340
|
return red;
|
|
62565
63341
|
}
|
|
62566
|
-
async function selectTargets(pr, warn4, now,
|
|
63342
|
+
async function selectTargets(pr, warn4, now, resolve40) {
|
|
62567
63343
|
const branch = readBranchOrNone(pr, warn4);
|
|
62568
63344
|
const current = branch === null ? null : await onProvider(`read the open pull request for the branch "${branch}"`, () => pr.pulls.findOpen(branch));
|
|
62569
63345
|
if (current !== null)
|
|
62570
|
-
return selectTriagePullRequests({ current, candidates: [], now, resolve:
|
|
63346
|
+
return selectTriagePullRequests({ current, candidates: [], now, resolve: resolve40 });
|
|
62571
63347
|
return selectTriagePullRequests({
|
|
62572
63348
|
current: null,
|
|
62573
63349
|
candidates: await redPullRequests(pr),
|
|
62574
63350
|
now,
|
|
62575
|
-
resolve:
|
|
63351
|
+
resolve: resolve40
|
|
62576
63352
|
});
|
|
62577
63353
|
}
|
|
62578
63354
|
async function detailOf16(pr, number) {
|
|
@@ -62709,7 +63485,7 @@ async function runTriage(context, seams) {
|
|
|
62709
63485
|
}
|
|
62710
63486
|
const numbers = asked === null ? (selection?.assess ?? []).map((one) => one.number) : [asked];
|
|
62711
63487
|
const readings = [];
|
|
62712
|
-
let
|
|
63488
|
+
let resolve40 = null;
|
|
62713
63489
|
for (const number of numbers) {
|
|
62714
63490
|
const assess = () => assessOne({
|
|
62715
63491
|
pr,
|
|
@@ -62729,7 +63505,7 @@ async function runTriage(context, seams) {
|
|
|
62729
63505
|
readings.push(reading2);
|
|
62730
63506
|
continue;
|
|
62731
63507
|
}
|
|
62732
|
-
|
|
63508
|
+
resolve40 = await resolvePullRequest({
|
|
62733
63509
|
trust: {
|
|
62734
63510
|
permissions,
|
|
62735
63511
|
trustedAuthors: pr.trustedAuthors,
|
|
@@ -62751,16 +63527,16 @@ async function runTriage(context, seams) {
|
|
|
62751
63527
|
...seams.clock === undefined ? {} : { clock: seams.clock },
|
|
62752
63528
|
...seams.sleep === undefined ? {} : { sleep: seams.sleep }
|
|
62753
63529
|
});
|
|
62754
|
-
readings.push(
|
|
63530
|
+
readings.push(resolve40.reading);
|
|
62755
63531
|
}
|
|
62756
63532
|
const text2 = [
|
|
62757
63533
|
...selection === null ? [] : [selection.message],
|
|
62758
63534
|
...readings.length === 0 ? [] : [renderTriages(readings)],
|
|
62759
|
-
...
|
|
63535
|
+
...resolve40 === null ? [] : resolve40.lines
|
|
62760
63536
|
].join(`
|
|
62761
63537
|
|
|
62762
63538
|
`);
|
|
62763
|
-
return { selection, readings, resolve:
|
|
63539
|
+
return { selection, readings, resolve: resolve40, text: text2, exitCode: resolve40?.exitCode ?? 0 };
|
|
62764
63540
|
}
|
|
62765
63541
|
function createPrTriageCommand(seams = DEFAULT_TRIAGE_SEAMS) {
|
|
62766
63542
|
const command = {
|
|
@@ -63188,9 +63964,9 @@ async function settleByPr(worktree, settings, pulls) {
|
|
|
63188
63964
|
if ("problem" in branch)
|
|
63189
63965
|
return failed4("unpushed", build2, false, branch.problem);
|
|
63190
63966
|
if (!branch.same) {
|
|
63191
|
-
const
|
|
63192
|
-
if (
|
|
63193
|
-
return
|
|
63967
|
+
const refused7 = pushReleaseBranch(worktree, build2, branch.current);
|
|
63968
|
+
if (refused7 !== null)
|
|
63969
|
+
return refused7;
|
|
63194
63970
|
}
|
|
63195
63971
|
const head = branch.same && branch.current !== null ? branch.current : build2.release;
|
|
63196
63972
|
const draft = {
|
|
@@ -63367,9 +64143,9 @@ var init_settle_tag = __esm(() => {
|
|
|
63367
64143
|
});
|
|
63368
64144
|
|
|
63369
64145
|
// src/release/settle-worktree.ts
|
|
63370
|
-
import { existsSync as
|
|
64146
|
+
import { existsSync as existsSync62, mkdtempSync as mkdtempSync3, realpathSync as realpathSync17, rmSync as rmSync13 } from "fs";
|
|
63371
64147
|
import { tmpdir as tmpdir5 } from "os";
|
|
63372
|
-
import { join as
|
|
64148
|
+
import { join as join95 } from "path";
|
|
63373
64149
|
function removeScratch(git, scratch, path9) {
|
|
63374
64150
|
const removed = git(["worktree", "remove", "--force", path9]);
|
|
63375
64151
|
const problems = [];
|
|
@@ -63384,14 +64160,14 @@ function removeScratch(git, scratch, path9) {
|
|
|
63384
64160
|
problems.push(`the worktree record of ${path9} could not be pruned: ${gitSaid(pruned)}`);
|
|
63385
64161
|
}
|
|
63386
64162
|
}
|
|
63387
|
-
if (problems.length === 0 &&
|
|
64163
|
+
if (problems.length === 0 && existsSync62(scratch)) {
|
|
63388
64164
|
problems.push(`the scratch directory ${scratch} is still there`);
|
|
63389
64165
|
}
|
|
63390
64166
|
return problems.length === 0 ? null : problems.join("; ");
|
|
63391
64167
|
}
|
|
63392
64168
|
function makeScratch(root) {
|
|
63393
64169
|
try {
|
|
63394
|
-
return realpathSync17(mkdtempSync3(
|
|
64170
|
+
return realpathSync17(mkdtempSync3(join95(root, SETTLE_SCRATCH_PREFIX)));
|
|
63395
64171
|
} catch (error) {
|
|
63396
64172
|
return { ok: false, problem: `no scratch directory could be made under ${root}: ${messageOf(error)}`, leftover: null };
|
|
63397
64173
|
}
|
|
@@ -63413,7 +64189,7 @@ function addWorktree(options) {
|
|
|
63413
64189
|
const scratch = makeScratch(options.scratchRoot ?? tmpdir5());
|
|
63414
64190
|
if (typeof scratch !== "string")
|
|
63415
64191
|
return scratch;
|
|
63416
|
-
const path9 =
|
|
64192
|
+
const path9 = join95(scratch, WORKTREE_DIRECTORY);
|
|
63417
64193
|
const added = git(["worktree", "add", "--detach", path9, commit]);
|
|
63418
64194
|
if (!added.ok) {
|
|
63419
64195
|
return {
|
|
@@ -63689,7 +64465,7 @@ var init_release_commit = __esm(() => {
|
|
|
63689
64465
|
|
|
63690
64466
|
// src/commands/release/tag.ts
|
|
63691
64467
|
import { readFileSync as readFileSync76 } from "fs";
|
|
63692
|
-
import { join as
|
|
64468
|
+
import { join as join96 } from "path";
|
|
63693
64469
|
function readBranch3(git) {
|
|
63694
64470
|
const result2 = git(["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
63695
64471
|
if (!result2.ok) {
|
|
@@ -63709,7 +64485,7 @@ function textOf5(path9) {
|
|
|
63709
64485
|
}
|
|
63710
64486
|
}
|
|
63711
64487
|
function readVersion(root, configured) {
|
|
63712
|
-
const resolved =
|
|
64488
|
+
const resolved = join96(root, configured);
|
|
63713
64489
|
const text2 = textOf5(resolved);
|
|
63714
64490
|
if (text2 === null) {
|
|
63715
64491
|
return {
|
|
@@ -63723,7 +64499,7 @@ function readVersion(root, configured) {
|
|
|
63723
64499
|
return version2 === null ? { path: configured, text: text2, version: null, problem: `${resolved} declares no version this can read` } : { path: configured, text: text2, version: version2, problem: null };
|
|
63724
64500
|
}
|
|
63725
64501
|
function readNewestRelease(root, configured) {
|
|
63726
|
-
const resolved =
|
|
64502
|
+
const resolved = join96(root, configured);
|
|
63727
64503
|
const text2 = textOf5(resolved);
|
|
63728
64504
|
if (text2 === null) {
|
|
63729
64505
|
return { path: configured, version: null, problem: `the changelog could not be read at ${resolved}` };
|
|
@@ -64011,10 +64787,10 @@ var init_roadmap2 = __esm(() => {
|
|
|
64011
64787
|
});
|
|
64012
64788
|
|
|
64013
64789
|
// src/backfill/proposal-file.ts
|
|
64014
|
-
import { readdirSync as
|
|
64015
|
-
import { join as
|
|
64790
|
+
import { readdirSync as readdirSync22, readFileSync as readFileSync77 } from "fs";
|
|
64791
|
+
import { join as join97 } from "path";
|
|
64016
64792
|
function proposalPath(dir, batch) {
|
|
64017
|
-
return
|
|
64793
|
+
return join97(dir, `${PROPOSAL_FILE_PREFIX}${String(batch).padStart(2, "0")}${PROPOSAL_FILE_EXTENSION}`);
|
|
64018
64794
|
}
|
|
64019
64795
|
function isProposalFileName(name2) {
|
|
64020
64796
|
return name2.startsWith(PROPOSAL_FILE_PREFIX) && name2.endsWith(PROPOSAL_FILE_EXTENSION);
|
|
@@ -64145,12 +64921,12 @@ function parseProposalFile(text2) {
|
|
|
64145
64921
|
function readProposalFiles(dir) {
|
|
64146
64922
|
let names2;
|
|
64147
64923
|
try {
|
|
64148
|
-
names2 =
|
|
64924
|
+
names2 = readdirSync22(dir);
|
|
64149
64925
|
} catch {
|
|
64150
64926
|
return [];
|
|
64151
64927
|
}
|
|
64152
64928
|
return names2.filter((name2) => isProposalFileName(name2)).sort((left, right) => left.localeCompare(right)).map((name2) => {
|
|
64153
|
-
const path9 =
|
|
64929
|
+
const path9 = join97(dir, name2);
|
|
64154
64930
|
try {
|
|
64155
64931
|
return { path: path9, result: parseProposalFile(readFileSync77(path9, "utf8")) };
|
|
64156
64932
|
} catch (error) {
|
|
@@ -64161,7 +64937,7 @@ function readProposalFiles(dir) {
|
|
|
64161
64937
|
var BACKFILL_PATH, PROPOSAL_FILE_PREFIX = "proposals-", PROPOSAL_FILE_EXTENSION = ".yaml", SHA256_PATTERN, PROPOSAL_STATUSES, DRAFT_FILE = "draft", REVIEWED_FILE = "reviewed", PROPOSAL_ROW_STATUSES, UNANSWERED_ROW = "unanswered", ANSWERED_ROW = "answered", PROPOSAL_NEEDS, PROPOSAL_FILE_HEADER;
|
|
64162
64938
|
var init_proposal_file = __esm(() => {
|
|
64163
64939
|
init_skill();
|
|
64164
|
-
BACKFILL_PATH =
|
|
64940
|
+
BACKFILL_PATH = join97(".rafa", "backfill");
|
|
64165
64941
|
SHA256_PATTERN = /^[0-9a-f]{64}$/;
|
|
64166
64942
|
PROPOSAL_STATUSES = ["draft", "reviewed"];
|
|
64167
64943
|
PROPOSAL_ROW_STATUSES = ["answered", "unanswered"];
|
|
@@ -64183,19 +64959,19 @@ var init_proposal_file = __esm(() => {
|
|
|
64183
64959
|
});
|
|
64184
64960
|
|
|
64185
64961
|
// src/backfill/backup.ts
|
|
64186
|
-
import { copyFileSync as copyFileSync6, existsSync as
|
|
64187
|
-
import { dirname as dirname36, isAbsolute as isAbsolute25, join as
|
|
64962
|
+
import { copyFileSync as copyFileSync6, existsSync as existsSync63, mkdirSync as mkdirSync29 } from "fs";
|
|
64963
|
+
import { dirname as dirname36, isAbsolute as isAbsolute25, join as join98, relative as relative22, resolve as resolve40, sep as sep9 } from "path";
|
|
64188
64964
|
function backupDirectory(base) {
|
|
64189
|
-
return
|
|
64965
|
+
return join98(base, BACKUP_PATH);
|
|
64190
64966
|
}
|
|
64191
64967
|
function isUnder(root, path9) {
|
|
64192
|
-
const step2 = relative22(
|
|
64968
|
+
const step2 = relative22(resolve40(root), resolve40(path9));
|
|
64193
64969
|
return step2 === "" || !step2.startsWith(`..${sep9}`) && step2 !== ".." && !isAbsolute25(step2);
|
|
64194
64970
|
}
|
|
64195
64971
|
function backupPathFor(path9, root, backupDir) {
|
|
64196
64972
|
if (!isUnder(root, path9))
|
|
64197
64973
|
return null;
|
|
64198
|
-
return
|
|
64974
|
+
return join98(backupDir, relative22(resolve40(root), resolve40(path9)));
|
|
64199
64975
|
}
|
|
64200
64976
|
function backupFile(path9, options) {
|
|
64201
64977
|
if (options.repoRoot !== null && isUnder(options.repoRoot, path9)) {
|
|
@@ -64204,11 +64980,11 @@ function backupFile(path9, options) {
|
|
|
64204
64980
|
const backup = backupPathFor(path9, options.root, options.backupDir);
|
|
64205
64981
|
if (backup === null)
|
|
64206
64982
|
return { path: path9, kind: "outside", backup: null };
|
|
64207
|
-
if (!
|
|
64983
|
+
if (!existsSync63(path9))
|
|
64208
64984
|
return { path: path9, kind: "missing", backup: null };
|
|
64209
|
-
if (
|
|
64985
|
+
if (existsSync63(backup))
|
|
64210
64986
|
return { path: path9, kind: "kept", backup };
|
|
64211
|
-
|
|
64987
|
+
mkdirSync29(dirname36(backup), { recursive: true });
|
|
64212
64988
|
copyFileSync6(path9, backup);
|
|
64213
64989
|
return { path: path9, kind: "copied", backup };
|
|
64214
64990
|
}
|
|
@@ -64232,12 +65008,12 @@ function countBackups(results) {
|
|
|
64232
65008
|
var BACKUP_PATH, BACKUP_KINDS;
|
|
64233
65009
|
var init_backup = __esm(() => {
|
|
64234
65010
|
init_proposal_file();
|
|
64235
|
-
BACKUP_PATH =
|
|
65011
|
+
BACKUP_PATH = join98(BACKFILL_PATH, "backup");
|
|
64236
65012
|
BACKUP_KINDS = ["copied", "kept", "tracked", "outside", "missing"];
|
|
64237
65013
|
});
|
|
64238
65014
|
|
|
64239
65015
|
// src/backfill/derive.ts
|
|
64240
|
-
import { readFileSync as readFileSync78, writeFileSync as
|
|
65016
|
+
import { readFileSync as readFileSync78, writeFileSync as writeFileSync31 } from "fs";
|
|
64241
65017
|
import { basename as basename24 } from "path";
|
|
64242
65018
|
function renderWhenToUse(trigger, prevents) {
|
|
64243
65019
|
return `${sentenceEnded(trigger)} Prevents: ${prevents}`;
|
|
@@ -64409,7 +65185,7 @@ function applyFile(action, options) {
|
|
|
64409
65185
|
text: null
|
|
64410
65186
|
};
|
|
64411
65187
|
}
|
|
64412
|
-
|
|
65188
|
+
writeFileSync31(action.path, action.text, "utf8");
|
|
64413
65189
|
const after = failureLines(checkFile(action.path, "skill", {
|
|
64414
65190
|
projectRoot: options.projectRoot,
|
|
64415
65191
|
pathDirs: options.pathDirs
|
|
@@ -64417,7 +65193,7 @@ function applyFile(action, options) {
|
|
|
64417
65193
|
const added = addedFailures(action.before, after);
|
|
64418
65194
|
if (added.length === 0)
|
|
64419
65195
|
return action;
|
|
64420
|
-
|
|
65196
|
+
writeFileSync31(action.path, action.original, "utf8");
|
|
64421
65197
|
return {
|
|
64422
65198
|
...action,
|
|
64423
65199
|
kind: "refused",
|
|
@@ -64516,8 +65292,8 @@ function summaryLine3(rows2) {
|
|
|
64516
65292
|
const parts = DEMOTION_VERDICTS.map((verdict) => `${counts[verdict]} ${verdict}`);
|
|
64517
65293
|
return `${files}: ${parts.join(", ")}.`;
|
|
64518
65294
|
}
|
|
64519
|
-
function writeDemotionReport(
|
|
64520
|
-
const rows2 =
|
|
65295
|
+
function writeDemotionReport(report5) {
|
|
65296
|
+
const rows2 = report5.rows.map((row3) => tableLine2([
|
|
64521
65297
|
escapeCell(row3.path),
|
|
64522
65298
|
escapeCell(row3.hash),
|
|
64523
65299
|
escapeCell(row3.verdict),
|
|
@@ -64526,11 +65302,11 @@ function writeDemotionReport(report4) {
|
|
|
64526
65302
|
escapeCell(row3.overrideReason ?? EMPTY_CELL2)
|
|
64527
65303
|
]));
|
|
64528
65304
|
return [
|
|
64529
|
-
renderHeader(
|
|
65305
|
+
renderHeader(report5.status),
|
|
64530
65306
|
"",
|
|
64531
65307
|
REPORT_TITLE,
|
|
64532
65308
|
"",
|
|
64533
|
-
summaryLine3(
|
|
65309
|
+
summaryLine3(report5.rows),
|
|
64534
65310
|
"",
|
|
64535
65311
|
tableLine2(DEMOTION_REPORT_COLUMNS),
|
|
64536
65312
|
tableLine2(DEMOTION_REPORT_COLUMNS.map(() => "---")),
|
|
@@ -64853,8 +65629,8 @@ The files:
|
|
|
64853
65629
|
});
|
|
64854
65630
|
|
|
64855
65631
|
// src/backfill/propose.ts
|
|
64856
|
-
import { mkdirSync as
|
|
64857
|
-
import { join as
|
|
65632
|
+
import { mkdirSync as mkdirSync30, readFileSync as readFileSync80, writeFileSync as writeFileSync32 } from "fs";
|
|
65633
|
+
import { join as join99, resolve as resolve41 } from "path";
|
|
64858
65634
|
function unanswered(candidate, note) {
|
|
64859
65635
|
return {
|
|
64860
65636
|
path: candidate.relative,
|
|
@@ -64927,12 +65703,12 @@ async function runProposalPass(options) {
|
|
|
64927
65703
|
const batches = batchCandidates(candidates);
|
|
64928
65704
|
const written3 = [];
|
|
64929
65705
|
if (batches.length > 0)
|
|
64930
|
-
|
|
65706
|
+
mkdirSync30(options.backfillDir, { recursive: true });
|
|
64931
65707
|
for (const [index, batch] of batches.entries()) {
|
|
64932
65708
|
const number = index + 1;
|
|
64933
65709
|
const file = await runProposalBatch(number, batch, options);
|
|
64934
65710
|
const path9 = proposalPath(options.backfillDir, number);
|
|
64935
|
-
|
|
65711
|
+
writeFileSync32(path9, renderProposalFile(file), "utf8");
|
|
64936
65712
|
written3.push({ path: path9, file });
|
|
64937
65713
|
}
|
|
64938
65714
|
return { written: written3, candidates: candidates.length };
|
|
@@ -64974,7 +65750,7 @@ function writeRow(path9, row3, original, options) {
|
|
|
64974
65750
|
return inert2(path9, row3, "unchanged", "every field the row proposes is already what the file carries");
|
|
64975
65751
|
}
|
|
64976
65752
|
const before = checkLines(path9, options);
|
|
64977
|
-
|
|
65753
|
+
writeFileSync32(path9, writeFrontmatter(document, mergeFrontmatter(document.data, changes)), "utf8");
|
|
64978
65754
|
const added = addedFailures(before, checkLines(path9, options));
|
|
64979
65755
|
if (added.length === 0) {
|
|
64980
65756
|
return {
|
|
@@ -64986,7 +65762,7 @@ function writeRow(path9, row3, original, options) {
|
|
|
64986
65762
|
added: []
|
|
64987
65763
|
};
|
|
64988
65764
|
}
|
|
64989
|
-
|
|
65765
|
+
writeFileSync32(path9, original, "utf8");
|
|
64990
65766
|
return {
|
|
64991
65767
|
path: path9,
|
|
64992
65768
|
relative: row3.path,
|
|
@@ -64997,7 +65773,7 @@ function writeRow(path9, row3, original, options) {
|
|
|
64997
65773
|
};
|
|
64998
65774
|
}
|
|
64999
65775
|
function applyRow(root, row3, options) {
|
|
65000
|
-
const path9 =
|
|
65776
|
+
const path9 = join99(root, ...row3.path.split("/"));
|
|
65001
65777
|
if (row3.status === UNANSWERED_ROW) {
|
|
65002
65778
|
return inert2(path9, row3, "unanswered", row3.note ?? "the row carries no answer");
|
|
65003
65779
|
}
|
|
@@ -65020,7 +65796,7 @@ function fileRefusal(file, root) {
|
|
|
65020
65796
|
if (file.status !== REVIEWED_FILE) {
|
|
65021
65797
|
return `the proposal file is still marked ${file.status}: review it and mark it ${REVIEWED_FILE}`;
|
|
65022
65798
|
}
|
|
65023
|
-
return
|
|
65799
|
+
return resolve41(file.skills) === resolve41(root) ? null : `the proposal file names the skills directory ${file.skills}, not ${root}`;
|
|
65024
65800
|
}
|
|
65025
65801
|
function countProposalActions(actions) {
|
|
65026
65802
|
const counts = Object.fromEntries(PROPOSAL_ACTION_KINDS.map((kind) => [kind, 0]));
|
|
@@ -65034,7 +65810,7 @@ function applyProposals(files, root, options) {
|
|
|
65034
65810
|
for (const file of files) {
|
|
65035
65811
|
const refusal16 = fileRefusal(file, root);
|
|
65036
65812
|
for (const row3 of file.rows) {
|
|
65037
|
-
const action = refusal16 === null ? applyRow(root, row3, options) : inert2(
|
|
65813
|
+
const action = refusal16 === null ? applyRow(root, row3, options) : inert2(join99(root, ...row3.path.split("/")), row3, "refused", refusal16);
|
|
65038
65814
|
actions.push(action);
|
|
65039
65815
|
if (row3.trigger !== null && action.kind !== "refused" && action.kind !== "unanswered") {
|
|
65040
65816
|
triggers[row3.name] = row3.trigger;
|
|
@@ -65061,8 +65837,8 @@ var init_propose = __esm(() => {
|
|
|
65061
65837
|
});
|
|
65062
65838
|
|
|
65063
65839
|
// src/demote/select.ts
|
|
65064
|
-
import { readdirSync as
|
|
65065
|
-
import { basename as basename25, dirname as dirname37, join as
|
|
65840
|
+
import { readdirSync as readdirSync23, readFileSync as readFileSync81, realpathSync as realpathSync18, statSync as statSync30 } from "fs";
|
|
65841
|
+
import { basename as basename25, dirname as dirname37, join as join100 } from "path";
|
|
65066
65842
|
function realOrSelf(path9) {
|
|
65067
65843
|
try {
|
|
65068
65844
|
return realpathSync18(path9);
|
|
@@ -65084,19 +65860,19 @@ function resolveDemotionScope(dir, home) {
|
|
|
65084
65860
|
if (basename25(claude) !== CLAUDE_DIRECTORY)
|
|
65085
65861
|
return null;
|
|
65086
65862
|
const base = dirname37(claude);
|
|
65087
|
-
const demotedDir =
|
|
65863
|
+
const demotedDir = join100(base, DEMOTED_PATH);
|
|
65088
65864
|
return {
|
|
65089
65865
|
scope: samePath(base, home) ? "user" : "project",
|
|
65090
65866
|
dir,
|
|
65091
65867
|
base,
|
|
65092
65868
|
demotedDir,
|
|
65093
|
-
instinctsDir:
|
|
65094
|
-
reportPath:
|
|
65869
|
+
instinctsDir: join100(base, INSTINCTS_PATH),
|
|
65870
|
+
reportPath: join100(demotedDir, REPORT_FILE)
|
|
65095
65871
|
};
|
|
65096
65872
|
}
|
|
65097
65873
|
function entryKind2(path9) {
|
|
65098
65874
|
try {
|
|
65099
|
-
const stats =
|
|
65875
|
+
const stats = statSync30(path9);
|
|
65100
65876
|
if (stats.isFile())
|
|
65101
65877
|
return "file";
|
|
65102
65878
|
if (stats.isDirectory())
|
|
@@ -65108,7 +65884,7 @@ function entryKind2(path9) {
|
|
|
65108
65884
|
}
|
|
65109
65885
|
function visibleNames2(dir) {
|
|
65110
65886
|
try {
|
|
65111
|
-
return
|
|
65887
|
+
return readdirSync23(dir).filter((name2) => !name2.startsWith(".")).sort((left, right) => left.localeCompare(right));
|
|
65112
65888
|
} catch {
|
|
65113
65889
|
return [];
|
|
65114
65890
|
}
|
|
@@ -65118,7 +65894,7 @@ function readSelected(absolute, path9, entries) {
|
|
|
65118
65894
|
let mtime;
|
|
65119
65895
|
try {
|
|
65120
65896
|
text2 = readFileSync81(absolute, "utf8");
|
|
65121
|
-
mtime =
|
|
65897
|
+
mtime = statSync30(absolute).mtime.toISOString();
|
|
65122
65898
|
} catch {
|
|
65123
65899
|
return null;
|
|
65124
65900
|
}
|
|
@@ -65133,14 +65909,14 @@ function selectsLearned(text2, scope) {
|
|
|
65133
65909
|
return origin === AUTO_EXTRACTED_ORIGIN;
|
|
65134
65910
|
}
|
|
65135
65911
|
function selectLearned(scope) {
|
|
65136
|
-
const dir =
|
|
65912
|
+
const dir = join100(scope.dir, LEARNED_DIRECTORY);
|
|
65137
65913
|
if (entryKind2(dir) !== "directory")
|
|
65138
65914
|
return [];
|
|
65139
65915
|
const selected = [];
|
|
65140
65916
|
for (const name2 of visibleNames2(dir)) {
|
|
65141
65917
|
if (!name2.endsWith(MARKDOWN_EXTENSION) || name2 === MARKDOWN_EXTENSION)
|
|
65142
65918
|
continue;
|
|
65143
|
-
const absolute =
|
|
65919
|
+
const absolute = join100(dir, name2);
|
|
65144
65920
|
if (entryKind2(absolute) !== "file")
|
|
65145
65921
|
continue;
|
|
65146
65922
|
const file = readSelected(absolute, `${LEARNED_DIRECTORY}/${name2}`, undefined);
|
|
@@ -65154,10 +65930,10 @@ function selectSkillFiles(scope) {
|
|
|
65154
65930
|
for (const name2 of visibleNames2(scope.dir)) {
|
|
65155
65931
|
if (name2 === LEARNED_DIRECTORY)
|
|
65156
65932
|
continue;
|
|
65157
|
-
const skillDir =
|
|
65933
|
+
const skillDir = join100(scope.dir, name2);
|
|
65158
65934
|
if (entryKind2(skillDir) !== "directory")
|
|
65159
65935
|
continue;
|
|
65160
|
-
const absolute =
|
|
65936
|
+
const absolute = join100(skillDir, SKILL_FILE);
|
|
65161
65937
|
if (entryKind2(absolute) !== "file")
|
|
65162
65938
|
continue;
|
|
65163
65939
|
const file = readSelected(absolute, `${name2}/${SKILL_FILE}`, visibleNames2(skillDir));
|
|
@@ -65174,14 +65950,14 @@ var init_select5 = __esm(() => {
|
|
|
65174
65950
|
init_layout();
|
|
65175
65951
|
init_classify2();
|
|
65176
65952
|
init_report3();
|
|
65177
|
-
DEMOTED_PATH =
|
|
65178
|
-
INSTINCTS_PATH =
|
|
65953
|
+
DEMOTED_PATH = join100(".rafa", "demoted");
|
|
65954
|
+
INSTINCTS_PATH = join100(".rafa", "instincts");
|
|
65179
65955
|
});
|
|
65180
65956
|
|
|
65181
65957
|
// src/commands/skill/backfill.ts
|
|
65182
|
-
import { statSync as
|
|
65183
|
-
import { join as
|
|
65184
|
-
function
|
|
65958
|
+
import { statSync as statSync31 } from "fs";
|
|
65959
|
+
import { join as join101, resolve as resolve42 } from "path";
|
|
65960
|
+
function readSwitch4(name2, value) {
|
|
65185
65961
|
if (value === undefined || value === false || value === "false")
|
|
65186
65962
|
return false;
|
|
65187
65963
|
if (value === true || value === "true")
|
|
@@ -65190,8 +65966,8 @@ function readSwitch3(name2, value) {
|
|
|
65190
65966
|
Usage: ${BACKFILL_USAGE}`);
|
|
65191
65967
|
}
|
|
65192
65968
|
function readMode(flags) {
|
|
65193
|
-
const propose =
|
|
65194
|
-
const apply =
|
|
65969
|
+
const propose = readSwitch4("propose", flags["propose"]);
|
|
65970
|
+
const apply = readSwitch4("apply", flags["apply"]);
|
|
65195
65971
|
if (propose && apply) {
|
|
65196
65972
|
throw new CommandExit(1, "\u274C --propose asks the sessions and --apply writes their reviewed answers, so a run is one or the" + ` other
|
|
65197
65973
|
Usage: ${BACKFILL_USAGE}`);
|
|
@@ -65210,7 +65986,7 @@ Usage: ${BACKFILL_USAGE}`);
|
|
|
65210
65986
|
throw new CommandExit(1, `\u274C Expected one directory, and read "${extra}" as a second
|
|
65211
65987
|
Usage: ${BACKFILL_USAGE}`);
|
|
65212
65988
|
}
|
|
65213
|
-
return
|
|
65989
|
+
return resolve42(cwd(), dir);
|
|
65214
65990
|
}
|
|
65215
65991
|
function readConsumerRoot(value, cwd) {
|
|
65216
65992
|
if (value === undefined || value === false)
|
|
@@ -65219,11 +65995,11 @@ function readConsumerRoot(value, cwd) {
|
|
|
65219
65995
|
throw new CommandExit(1, `\u274C --project needs a path, and the line gave it none
|
|
65220
65996
|
Usage: ${BACKFILL_USAGE}`);
|
|
65221
65997
|
}
|
|
65222
|
-
return
|
|
65998
|
+
return resolve42(cwd(), value);
|
|
65223
65999
|
}
|
|
65224
66000
|
function isDirectory4(path9) {
|
|
65225
66001
|
try {
|
|
65226
|
-
return
|
|
66002
|
+
return statSync31(path9).isDirectory();
|
|
65227
66003
|
} catch {
|
|
65228
66004
|
return false;
|
|
65229
66005
|
}
|
|
@@ -65272,7 +66048,7 @@ function actionLines(actions) {
|
|
|
65272
66048
|
function checkOptions(context, projectRoot3) {
|
|
65273
66049
|
return { projectRoot: projectRoot3, pathDirs: pathDirectories(context.env["PATH"]) };
|
|
65274
66050
|
}
|
|
65275
|
-
function
|
|
66051
|
+
function report5(context, result2, lines2) {
|
|
65276
66052
|
if (context.outputMode === "json") {
|
|
65277
66053
|
context.output.result(result2);
|
|
65278
66054
|
return;
|
|
@@ -65293,7 +66069,7 @@ function runPlan(context, scope, backfillDir, projectRoot3) {
|
|
|
65293
66069
|
counts: plan2.counts,
|
|
65294
66070
|
candidates
|
|
65295
66071
|
};
|
|
65296
|
-
|
|
66072
|
+
report5(context, result2, [
|
|
65297
66073
|
`${scope.scope} scope: ${scope.dir}`,
|
|
65298
66074
|
...actionLines(actions),
|
|
65299
66075
|
derivationLine(plan2),
|
|
@@ -65327,7 +66103,7 @@ async function runPropose(context, scope, backfillDir, seams) {
|
|
|
65327
66103
|
candidates: pass.candidates,
|
|
65328
66104
|
files
|
|
65329
66105
|
};
|
|
65330
|
-
|
|
66106
|
+
report5(context, result2, [
|
|
65331
66107
|
`${scope.scope} scope: ${scope.dir}`,
|
|
65332
66108
|
`${String(pass.candidates)} file(s) to ask about, in ${String(files.length)} batch(es)`,
|
|
65333
66109
|
...files.map((file) => `\u2705 ${file.path}: batch ${String(file.batch)}, session exit ${String(file.exitCode)},` + ` ${String(file.rows)} row(s), ${String(file.unanswered)} unanswered`),
|
|
@@ -65347,7 +66123,7 @@ function reviewedProposals(dir) {
|
|
|
65347
66123
|
return read2.flatMap((entry) => entry.result.file === null ? [] : [entry.result.file]);
|
|
65348
66124
|
}
|
|
65349
66125
|
function rowPaths(files, root) {
|
|
65350
|
-
return files.flatMap((file) => file.status !== REVIEWED_FILE ? [] : file.rows.filter((row3) => row3.status === ANSWERED_ROW).map((row3) =>
|
|
66126
|
+
return files.flatMap((file) => file.status !== REVIEWED_FILE ? [] : file.rows.filter((row3) => row3.status === ANSWERED_ROW).map((row3) => join101(root, ...row3.path.split("/"))));
|
|
65351
66127
|
}
|
|
65352
66128
|
function runApply(context, scope, backfillDir, projectRoot3) {
|
|
65353
66129
|
const options = checkOptions(context, projectRoot3);
|
|
@@ -65382,18 +66158,18 @@ function runApply(context, scope, backfillDir, projectRoot3) {
|
|
|
65382
66158
|
derivationLine(derived),
|
|
65383
66159
|
`${String(copied)} file(s) copied under ${backupDir} before they were rewritten`
|
|
65384
66160
|
];
|
|
65385
|
-
const
|
|
65386
|
-
if (
|
|
65387
|
-
throw new CommandExit(Math.min(
|
|
66161
|
+
const refused7 = proposals.counts.refused + derived.counts.refused;
|
|
66162
|
+
if (refused7 > 0)
|
|
66163
|
+
throw new CommandExit(Math.min(refused7, REFUSED_CAP), lines2.join(`
|
|
65388
66164
|
`));
|
|
65389
|
-
|
|
66165
|
+
report5(context, result2, lines2);
|
|
65390
66166
|
}
|
|
65391
66167
|
async function runBackfill(context, seams) {
|
|
65392
66168
|
const mode = readMode(context.flags);
|
|
65393
66169
|
const dir = readBackfillDirectory(context.args, seams.cwd);
|
|
65394
66170
|
const projectRoot3 = readConsumerRoot(context.flags["project"], seams.cwd);
|
|
65395
66171
|
const scope = backfillScopeOf(dir, projectOf13(context).home);
|
|
65396
|
-
const backfillDir =
|
|
66172
|
+
const backfillDir = join101(scope.base, BACKFILL_PATH);
|
|
65397
66173
|
if (mode === "propose") {
|
|
65398
66174
|
await runPropose(context, scope, backfillDir, seams);
|
|
65399
66175
|
return;
|
|
@@ -65526,9 +66302,9 @@ var init_check3 = __esm(() => {
|
|
|
65526
66302
|
});
|
|
65527
66303
|
|
|
65528
66304
|
// src/demote/apply.ts
|
|
65529
|
-
import { copyFileSync as copyFileSync7, existsSync as
|
|
66305
|
+
import { copyFileSync as copyFileSync7, existsSync as existsSync64, mkdirSync as mkdirSync31, mkdtempSync as mkdtempSync4, readdirSync as readdirSync24, readFileSync as readFileSync82, renameSync as renameSync12, rmSync as rmSync14, statSync as statSync32, unlinkSync as unlinkSync2, writeFileSync as writeFileSync33 } from "fs";
|
|
65530
66306
|
import { tmpdir as tmpdir6 } from "os";
|
|
65531
|
-
import { dirname as dirname38, join as
|
|
66307
|
+
import { dirname as dirname38, join as join102 } from "path";
|
|
65532
66308
|
function isLearnedPath(path9) {
|
|
65533
66309
|
const segments = path9.split("/");
|
|
65534
66310
|
return segments.length === 2 && segments[0] === LEARNED_DIRECTORY && (segments[1] ?? "").endsWith(MARKDOWN_EXTENSION);
|
|
@@ -65538,18 +66314,18 @@ function learnedSkillName(path9) {
|
|
|
65538
66314
|
return base.slice(0, -MARKDOWN_EXTENSION.length);
|
|
65539
66315
|
}
|
|
65540
66316
|
function sourcePath(scope, path9) {
|
|
65541
|
-
return
|
|
66317
|
+
return join102(scope.dir, ...path9.split("/"));
|
|
65542
66318
|
}
|
|
65543
66319
|
function demotedPath(scope, path9) {
|
|
65544
|
-
return
|
|
66320
|
+
return join102(scope.demotedDir, ...path9.split("/"));
|
|
65545
66321
|
}
|
|
65546
66322
|
function promotedPath(scope, path9) {
|
|
65547
|
-
return
|
|
66323
|
+
return join102(scope.dir, learnedSkillName(path9), SKILL_FILE);
|
|
65548
66324
|
}
|
|
65549
66325
|
function takenInstinctIds(dir) {
|
|
65550
66326
|
let names2;
|
|
65551
66327
|
try {
|
|
65552
|
-
names2 =
|
|
66328
|
+
names2 = readdirSync24(dir);
|
|
65553
66329
|
} catch {
|
|
65554
66330
|
return [];
|
|
65555
66331
|
}
|
|
@@ -65557,7 +66333,7 @@ function takenInstinctIds(dir) {
|
|
|
65557
66333
|
}
|
|
65558
66334
|
function readText9(path9) {
|
|
65559
66335
|
try {
|
|
65560
|
-
return
|
|
66336
|
+
return statSync32(path9).isFile() ? readFileSync82(path9, "utf8") : null;
|
|
65561
66337
|
} catch {
|
|
65562
66338
|
return null;
|
|
65563
66339
|
}
|
|
@@ -65585,7 +66361,7 @@ function planKept(scope, row3, file) {
|
|
|
65585
66361
|
return inert3(row3.path, "procedure", "kept", "procedure-shaped: left where it is, for the backfill");
|
|
65586
66362
|
}
|
|
65587
66363
|
const to = promotedPath(scope, row3.path);
|
|
65588
|
-
if (
|
|
66364
|
+
if (existsSync64(to) || existsSync64(dirname38(to))) {
|
|
65589
66365
|
return inert3(row3.path, "procedure", "refused", `kept as a skill, but ${to} is already there`);
|
|
65590
66366
|
}
|
|
65591
66367
|
return {
|
|
@@ -65599,10 +66375,10 @@ function planKept(scope, row3, file) {
|
|
|
65599
66375
|
};
|
|
65600
66376
|
}
|
|
65601
66377
|
function checkCandidate(dir, id3, text2, pathDirs) {
|
|
65602
|
-
const path9 =
|
|
65603
|
-
|
|
65604
|
-
const
|
|
65605
|
-
return failureLines2(
|
|
66378
|
+
const path9 = join102(dir, `${id3}${MARKDOWN_EXTENSION}`);
|
|
66379
|
+
writeFileSync33(path9, text2, "utf8");
|
|
66380
|
+
const report6 = checkFile(path9, "instinct", { projectRoot: null, pathDirs });
|
|
66381
|
+
return failureLines2(report6.issues);
|
|
65606
66382
|
}
|
|
65607
66383
|
function planDemoted(scope, row3, file, context) {
|
|
65608
66384
|
const conversion = convertToInstinct(file, {
|
|
@@ -65620,11 +66396,11 @@ function planDemoted(scope, row3, file, context) {
|
|
|
65620
66396
|
if (failures.length > 0) {
|
|
65621
66397
|
return inert3(row3.path, "observation", "refused", `the record ${id3} fails the checker \u2014 ${failures.join("; ")}`);
|
|
65622
66398
|
}
|
|
65623
|
-
const destination =
|
|
66399
|
+
const destination = join102(scope.instinctsDir, `${id3}${MARKDOWN_EXTENSION}`);
|
|
65624
66400
|
const kept = demotedPath(scope, row3.path);
|
|
65625
|
-
if (
|
|
66401
|
+
if (existsSync64(destination))
|
|
65626
66402
|
return inert3(row3.path, "observation", "refused", `${destination} is already there`);
|
|
65627
|
-
if (
|
|
66403
|
+
if (existsSync64(kept))
|
|
65628
66404
|
return inert3(row3.path, "observation", "refused", `${kept} is already there`);
|
|
65629
66405
|
context.taken.push(id3);
|
|
65630
66406
|
return {
|
|
@@ -65656,7 +66432,7 @@ function planRow(scope, row3, context) {
|
|
|
65656
66432
|
entries: undefined,
|
|
65657
66433
|
absolute,
|
|
65658
66434
|
hash,
|
|
65659
|
-
mtime:
|
|
66435
|
+
mtime: statSync32(absolute).mtime.toISOString()
|
|
65660
66436
|
};
|
|
65661
66437
|
return verdict === "procedure" ? planKept(scope, row3, file) : planDemoted(scope, row3, file, context);
|
|
65662
66438
|
}
|
|
@@ -65666,18 +66442,18 @@ function countActions(actions) {
|
|
|
65666
66442
|
counts[action.kind] += 1;
|
|
65667
66443
|
return counts;
|
|
65668
66444
|
}
|
|
65669
|
-
function planDemotion(
|
|
65670
|
-
const temp = mkdtempSync4(
|
|
66445
|
+
function planDemotion(report6, scope, seams = DEFAULT_APPLY_SEAMS) {
|
|
66446
|
+
const temp = mkdtempSync4(join102(tmpdir6(), "rafa-demote-"));
|
|
65671
66447
|
const taken = [...takenInstinctIds(scope.instinctsDir)];
|
|
65672
66448
|
try {
|
|
65673
|
-
const actions =
|
|
66449
|
+
const actions = report6.rows.map((row3) => planRow(scope, row3, { temp, taken, seams }));
|
|
65674
66450
|
return { scope, actions, counts: countActions(actions) };
|
|
65675
66451
|
} finally {
|
|
65676
66452
|
rmSync14(temp, { recursive: true, force: true });
|
|
65677
66453
|
}
|
|
65678
66454
|
}
|
|
65679
66455
|
function moveFile(move3) {
|
|
65680
|
-
|
|
66456
|
+
mkdirSync31(dirname38(move3.to), { recursive: true });
|
|
65681
66457
|
try {
|
|
65682
66458
|
renameSync12(move3.from, move3.to);
|
|
65683
66459
|
} catch {
|
|
@@ -65688,8 +66464,8 @@ function moveFile(move3) {
|
|
|
65688
66464
|
function applyDemotion(plan2) {
|
|
65689
66465
|
for (const action of plan2.actions) {
|
|
65690
66466
|
if (action.write !== null) {
|
|
65691
|
-
|
|
65692
|
-
|
|
66467
|
+
mkdirSync31(dirname38(action.write.path), { recursive: true });
|
|
66468
|
+
writeFileSync33(action.write.path, action.write.text, "utf8");
|
|
65693
66469
|
}
|
|
65694
66470
|
if (action.move !== null)
|
|
65695
66471
|
moveFile(action.move);
|
|
@@ -65753,8 +66529,8 @@ var init_draft = __esm(() => {
|
|
|
65753
66529
|
});
|
|
65754
66530
|
|
|
65755
66531
|
// src/commands/skill/demote.ts
|
|
65756
|
-
import { existsSync as
|
|
65757
|
-
import { dirname as dirname39, resolve as
|
|
66532
|
+
import { existsSync as existsSync65, mkdirSync as mkdirSync32, readFileSync as readFileSync83, statSync as statSync33, writeFileSync as writeFileSync34 } from "fs";
|
|
66533
|
+
import { dirname as dirname39, resolve as resolve43 } from "path";
|
|
65758
66534
|
function readApply(value) {
|
|
65759
66535
|
if (value === undefined || value === false || value === "false")
|
|
65760
66536
|
return false;
|
|
@@ -65773,11 +66549,11 @@ Usage: ${DEMOTE_USAGE}`);
|
|
|
65773
66549
|
throw new CommandExit(1, `\u274C Expected one directory, and read "${extra}" as a second
|
|
65774
66550
|
Usage: ${DEMOTE_USAGE}`);
|
|
65775
66551
|
}
|
|
65776
|
-
return
|
|
66552
|
+
return resolve43(cwd(), dir);
|
|
65777
66553
|
}
|
|
65778
66554
|
function isDirectory5(path9) {
|
|
65779
66555
|
try {
|
|
65780
|
-
return
|
|
66556
|
+
return statSync33(path9).isDirectory();
|
|
65781
66557
|
} catch {
|
|
65782
66558
|
return false;
|
|
65783
66559
|
}
|
|
@@ -65799,13 +66575,13 @@ function projectOf14(context) {
|
|
|
65799
66575
|
throw new Error("rafa skill demote runs inside a project, and was handed none");
|
|
65800
66576
|
return context.project;
|
|
65801
66577
|
}
|
|
65802
|
-
function verdictLine2(
|
|
65803
|
-
const counts = countVerdicts(
|
|
66578
|
+
function verdictLine2(report6) {
|
|
66579
|
+
const counts = countVerdicts(report6.rows);
|
|
65804
66580
|
const parts = DEMOTION_VERDICTS.map((verdict) => `${String(counts[verdict])} ${verdict}`);
|
|
65805
|
-
return `${String(
|
|
66581
|
+
return `${String(report6.rows.length)} file(s): ${parts.join(", ")}`;
|
|
65806
66582
|
}
|
|
65807
66583
|
function previousReport(path9, context) {
|
|
65808
|
-
if (!
|
|
66584
|
+
if (!existsSync65(path9))
|
|
65809
66585
|
return null;
|
|
65810
66586
|
const parsed = parseDemotionReport(readFileSync83(path9, "utf8"));
|
|
65811
66587
|
if (parsed.report !== null)
|
|
@@ -65815,17 +66591,17 @@ function previousReport(path9, context) {
|
|
|
65815
66591
|
}
|
|
65816
66592
|
function runWrite(context, scope) {
|
|
65817
66593
|
const files = selectSources(scope);
|
|
65818
|
-
const
|
|
65819
|
-
|
|
65820
|
-
|
|
66594
|
+
const report6 = buildDemotionReport(files, previousReport(scope.reportPath, context));
|
|
66595
|
+
mkdirSync32(dirname39(scope.reportPath), { recursive: true });
|
|
66596
|
+
writeFileSync34(scope.reportPath, writeDemotionReport(report6), "utf8");
|
|
65821
66597
|
const result2 = {
|
|
65822
66598
|
applied: false,
|
|
65823
66599
|
scope: scope.scope,
|
|
65824
66600
|
dir: scope.dir,
|
|
65825
66601
|
reportPath: scope.reportPath,
|
|
65826
|
-
status:
|
|
65827
|
-
files:
|
|
65828
|
-
counts: countVerdicts(
|
|
66602
|
+
status: report6.status,
|
|
66603
|
+
files: report6.rows.length,
|
|
66604
|
+
counts: countVerdicts(report6.rows)
|
|
65829
66605
|
};
|
|
65830
66606
|
if (context.outputMode === "json") {
|
|
65831
66607
|
context.output.result(result2);
|
|
@@ -65833,14 +66609,14 @@ function runWrite(context, scope) {
|
|
|
65833
66609
|
}
|
|
65834
66610
|
for (const line of [
|
|
65835
66611
|
`${scope.scope} scope: ${scope.dir}`,
|
|
65836
|
-
verdictLine2(
|
|
65837
|
-
`Report written to ${scope.reportPath} (status: ${
|
|
66612
|
+
verdictLine2(report6),
|
|
66613
|
+
`Report written to ${scope.reportPath} (status: ${report6.status}); nothing was moved`,
|
|
65838
66614
|
`Review each row, then mark the report ${REVIEWED_STATUS} and re-run with --apply`
|
|
65839
66615
|
])
|
|
65840
66616
|
context.output.info(line);
|
|
65841
66617
|
}
|
|
65842
66618
|
function reviewedReport(scope) {
|
|
65843
|
-
if (!
|
|
66619
|
+
if (!existsSync65(scope.reportPath)) {
|
|
65844
66620
|
throw new CommandExit(1, `\u274C No report at ${scope.reportPath}; run "rafa skill demote ${scope.dir}" first, then review it`);
|
|
65845
66621
|
}
|
|
65846
66622
|
const parsed = parseDemotionReport(readFileSync83(scope.reportPath, "utf8"));
|
|
@@ -65870,8 +66646,8 @@ function renderApply(result2) {
|
|
|
65870
66646
|
return [...rows2, `${String(result2.actions.length)} row(s) of ${result2.reportPath}: ${parts.join(", ")}`];
|
|
65871
66647
|
}
|
|
65872
66648
|
function runApply2(context, scope) {
|
|
65873
|
-
const
|
|
65874
|
-
const plan2 = planDemotion(
|
|
66649
|
+
const report6 = reviewedReport(scope);
|
|
66650
|
+
const plan2 = planDemotion(report6, scope, {
|
|
65875
66651
|
now: () => new Date().toISOString(),
|
|
65876
66652
|
pathDirs: pathDirectories(context.env["PATH"])
|
|
65877
66653
|
});
|
|
@@ -66244,8 +67020,8 @@ var init_render = __esm(() => {
|
|
|
66244
67020
|
|
|
66245
67021
|
// src/status/blocked-count.ts
|
|
66246
67022
|
async function labelsCount(options) {
|
|
66247
|
-
const
|
|
66248
|
-
return
|
|
67023
|
+
const report6 = await options.blockedIssues(options.gh);
|
|
67024
|
+
return report6.problem === null ? { count: report6.readings.length, notes: [] } : { count: null, notes: [`the issues labelled ${SPEC_BLOCKED_LABEL} could not be read: ${report6.problem}`] };
|
|
66249
67025
|
}
|
|
66250
67026
|
async function nativeCount(relations, listing3) {
|
|
66251
67027
|
try {
|
|
@@ -66379,7 +67155,7 @@ var init_waiting = __esm(() => {
|
|
|
66379
67155
|
});
|
|
66380
67156
|
|
|
66381
67157
|
// src/status/sections.ts
|
|
66382
|
-
import { existsSync as
|
|
67158
|
+
import { existsSync as existsSync66 } from "fs";
|
|
66383
67159
|
function isIdleWorktree(row3) {
|
|
66384
67160
|
return !row3.blockers.some((blocker) => blocker.kind === "recent");
|
|
66385
67161
|
}
|
|
@@ -66425,9 +67201,9 @@ function boundedRunner(open, root, deadline) {
|
|
|
66425
67201
|
}
|
|
66426
67202
|
async function networkSection(what, deadline, work) {
|
|
66427
67203
|
let timer;
|
|
66428
|
-
const expired = new Promise((
|
|
67204
|
+
const expired = new Promise((resolve44) => {
|
|
66429
67205
|
timer = setTimeout(() => {
|
|
66430
|
-
|
|
67206
|
+
resolve44(unread4(`the ${what} was not read within the ${String(deadline.ms)}ms network deadline`));
|
|
66431
67207
|
}, Math.max(0, deadline.left()));
|
|
66432
67208
|
});
|
|
66433
67209
|
try {
|
|
@@ -66517,7 +67293,7 @@ function nextOfPlace(current, epic, walk) {
|
|
|
66517
67293
|
return epic?.members.some((member) => member.number === line.issue) === true ? line.issue : null;
|
|
66518
67294
|
}
|
|
66519
67295
|
function hasBoards(root, listing3) {
|
|
66520
|
-
if (
|
|
67296
|
+
if (existsSync66(positionFilePath(root)))
|
|
66521
67297
|
return true;
|
|
66522
67298
|
return listing3.some((issue5) => issue5.state === "OPEN" && issue5.labels.includes(ROADMAP_LABEL));
|
|
66523
67299
|
}
|
|
@@ -66755,10 +67531,10 @@ var init_board = __esm(() => {
|
|
|
66755
67531
|
});
|
|
66756
67532
|
|
|
66757
67533
|
// src/project/lock.ts
|
|
66758
|
-
import { existsSync as
|
|
66759
|
-
import { join as
|
|
67534
|
+
import { existsSync as existsSync67, lstatSync as lstatSync3, readFileSync as readFileSync84, writeFileSync as writeFileSync35 } from "fs";
|
|
67535
|
+
import { join as join103 } from "path";
|
|
66760
67536
|
function lockPath(root) {
|
|
66761
|
-
return
|
|
67537
|
+
return join103(root, LOCK_FILE);
|
|
66762
67538
|
}
|
|
66763
67539
|
function projectLockText(version2) {
|
|
66764
67540
|
const lock = { lockfileVersion: LOCKFILE_VERSION, rafa: version2 };
|
|
@@ -66791,7 +67567,7 @@ function lockOf(value) {
|
|
|
66791
67567
|
}
|
|
66792
67568
|
function readProjectLock(root) {
|
|
66793
67569
|
const path9 = lockPath(root);
|
|
66794
|
-
if (!
|
|
67570
|
+
if (!existsSync67(path9)) {
|
|
66795
67571
|
if (isLink(path9))
|
|
66796
67572
|
refuse17("is a link to nothing");
|
|
66797
67573
|
return null;
|
|
@@ -66811,7 +67587,7 @@ function readProjectLock(root) {
|
|
|
66811
67587
|
return lockOf(value);
|
|
66812
67588
|
}
|
|
66813
67589
|
function writeProjectLock(root, version2) {
|
|
66814
|
-
|
|
67590
|
+
writeFileSync35(lockPath(root), projectLockText(version2), "utf8");
|
|
66815
67591
|
}
|
|
66816
67592
|
var LOCK_FILE = "rafa.lock", LOCKFILE_VERSION = 1, ProjectLockError;
|
|
66817
67593
|
var init_lock = __esm(() => {
|
|
@@ -66823,10 +67599,10 @@ var init_lock = __esm(() => {
|
|
|
66823
67599
|
});
|
|
66824
67600
|
|
|
66825
67601
|
// src/project/update-current.ts
|
|
66826
|
-
import { existsSync as
|
|
66827
|
-
import { join as
|
|
67602
|
+
import { existsSync as existsSync68 } from "fs";
|
|
67603
|
+
import { join as join104 } from "path";
|
|
66828
67604
|
function missingFolders(root) {
|
|
66829
|
-
return PROJECT_TREE.map((name2) =>
|
|
67605
|
+
return PROJECT_TREE.map((name2) => join104(SCOPE_DIR, name2)).filter((relative24) => !existsSync68(join104(root, relative24)));
|
|
66830
67606
|
}
|
|
66831
67607
|
async function readBoard3(access) {
|
|
66832
67608
|
if (access.gh === null)
|
|
@@ -66841,10 +67617,10 @@ async function readBoard3(access) {
|
|
|
66841
67617
|
function lockChangeOf(range) {
|
|
66842
67618
|
if (range.kind === "adopt")
|
|
66843
67619
|
return "created";
|
|
66844
|
-
return range.kind === "
|
|
67620
|
+
return range.kind === "same" ? "unchanged" : "updated";
|
|
66845
67621
|
}
|
|
66846
67622
|
function fromOf(range) {
|
|
66847
|
-
if (range.kind === "patch")
|
|
67623
|
+
if (range.kind === "patch" || range.kind === "minor")
|
|
66848
67624
|
return range.from;
|
|
66849
67625
|
if (range.kind === "same")
|
|
66850
67626
|
return range.to;
|
|
@@ -66868,7 +67644,7 @@ function planChanges(plan2) {
|
|
|
66868
67644
|
return plan2.folders.length > 0 || labels > 0 || plan2.deprecations.length > 0 || plan2.lock !== "unchanged";
|
|
66869
67645
|
}
|
|
66870
67646
|
function foldersNowThere(plan2) {
|
|
66871
|
-
return plan2.folders.filter((relative24) =>
|
|
67647
|
+
return plan2.folders.filter((relative24) => existsSync68(join104(plan2.root, relative24)));
|
|
66872
67648
|
}
|
|
66873
67649
|
function writeFolders(plan2) {
|
|
66874
67650
|
if (plan2.folders.length === 0)
|
|
@@ -66915,27 +67691,29 @@ var init_update_current = __esm(() => {
|
|
|
66915
67691
|
});
|
|
66916
67692
|
|
|
66917
67693
|
// src/project/update-range.ts
|
|
66918
|
-
function
|
|
67694
|
+
function refused7(reason, message) {
|
|
66919
67695
|
return { kind: "refused", reason, message };
|
|
66920
67696
|
}
|
|
66921
67697
|
function readCurrentRange(recorded, installed) {
|
|
66922
67698
|
const to = parseSemanticVersion(installed);
|
|
66923
67699
|
if (to === null)
|
|
66924
|
-
return
|
|
67700
|
+
return refused7("unreadable", `the installed rafa answers "${installed}", which is no version`);
|
|
66925
67701
|
if (recorded === null)
|
|
66926
67702
|
return { kind: "adopt", to: installed };
|
|
66927
67703
|
const from = parseSemanticVersion(recorded);
|
|
66928
67704
|
if (from === null)
|
|
66929
|
-
return
|
|
67705
|
+
return refused7("unreadable", `the project records rafa "${recorded}", which is no version`);
|
|
66930
67706
|
const order = compareVersions(to, from);
|
|
66931
67707
|
if (order < 0) {
|
|
66932
|
-
return
|
|
67708
|
+
return refused7("older", `the installed rafa ${installed} is older than the project's ${recorded}, and no downgrade runs before 1.0.0`);
|
|
66933
67709
|
}
|
|
66934
67710
|
if (to.major !== from.major) {
|
|
66935
|
-
return
|
|
67711
|
+
return refused7("newer-major", `the installed rafa ${installed} is a newer major than the project's ${recorded}; that move is rafa update latest`);
|
|
66936
67712
|
}
|
|
67713
|
+
if (to.minor !== from.minor && to.major === 0)
|
|
67714
|
+
return { kind: "minor", from: recorded, to: installed };
|
|
66937
67715
|
if (to.minor !== from.minor) {
|
|
66938
|
-
return
|
|
67716
|
+
return refused7("newer-minor", `the installed rafa ${installed} is a newer minor than the project's ${recorded}; that move is rafa update next`);
|
|
66939
67717
|
}
|
|
66940
67718
|
return order === 0 ? { kind: "same", to: installed } : { kind: "patch", from: recorded, to: installed };
|
|
66941
67719
|
}
|
|
@@ -66952,7 +67730,7 @@ function checkoutLockRoot(root, dir) {
|
|
|
66952
67730
|
const top = run.stdout.toString().trim();
|
|
66953
67731
|
return top !== "" && mainCheckoutOf(top) === root ? top : root;
|
|
66954
67732
|
}
|
|
66955
|
-
function
|
|
67733
|
+
function readSwitch5(context, name2) {
|
|
66956
67734
|
const value = context.flags[name2];
|
|
66957
67735
|
if (value === undefined || value === false || value === "false")
|
|
66958
67736
|
return false;
|
|
@@ -67082,10 +67860,10 @@ async function applyAndReport(plan2, gh, context) {
|
|
|
67082
67860
|
return applied;
|
|
67083
67861
|
}
|
|
67084
67862
|
function refusedLabels(applied) {
|
|
67085
|
-
const
|
|
67086
|
-
if (
|
|
67863
|
+
const refused8 = applied.labels.filter((part) => part.outcome === "refused");
|
|
67864
|
+
if (refused8.length === 0)
|
|
67087
67865
|
return null;
|
|
67088
|
-
return new CommandExit(1, `${String(
|
|
67866
|
+
return new CommandExit(1, `${String(refused8.length)} board label(s) were not created; everything else was applied.` + " Run rafa update current again once gh can create them.");
|
|
67089
67867
|
}
|
|
67090
67868
|
function stopLine2(plan2, dryRun) {
|
|
67091
67869
|
if (!planChanges(plan2))
|
|
@@ -67096,8 +67874,8 @@ function stopLine2(plan2, dryRun) {
|
|
|
67096
67874
|
}
|
|
67097
67875
|
async function runUpdateCurrent(context, seams) {
|
|
67098
67876
|
expectNoArgument(context.args, USAGE48);
|
|
67099
|
-
const dryRun =
|
|
67100
|
-
const yes =
|
|
67877
|
+
const dryRun = readSwitch5(context, "dry-run");
|
|
67878
|
+
const yes = readSwitch5(context, "yes");
|
|
67101
67879
|
const project = projectOf17(context);
|
|
67102
67880
|
const lockRoot = seams.lockRootOf(project.root);
|
|
67103
67881
|
const range = readRange2(lockRoot, seams.installed);
|
|
@@ -67133,8 +67911,8 @@ function createUpdateCurrentCommand(seams = DEFAULT_UPDATE_CURRENT_SEAMS) {
|
|
|
67133
67911
|
name: "update current",
|
|
67134
67912
|
subject: "update",
|
|
67135
67913
|
action: "current",
|
|
67136
|
-
summary: "bring this project to the installed rafa
|
|
67137
|
-
description: "Brings the project to the installed rafa when the installed version shares the major and" + ` minor of the version \`${LOCK_FILE}\` records at the project root, and is the same patch or newer
|
|
67914
|
+
summary: "bring this project to the installed rafa: a newer patch, or any newer minor below 1.0.0",
|
|
67915
|
+
description: "Brings the project to the installed rafa when the installed version shares the major and" + ` minor of the version \`${LOCK_FILE}\` records at the project root, and is the same patch or newer;` + " below 1.0.0 it also crosses newer minors, as `0.34.1` to `0.36.0`." + " A project with no lock is adopted at the installed version. It creates the missing `.rafa/` folders" + " and the missing board labels on a GitHub board, runs the deprecations step (none registered yet)," + ` and writes \`${LOCK_FILE}\`. It prints every change first; \`--dry-run\` stops there. Otherwise it` + " warns that the changes cannot be rolled back and asks once, `--yes` answering; with no terminal and" + " no `--yes` it refuses with exit code 1. A newer minor from 1.0.0 on, a newer major, or an installed rafa older than the" + " lock, refuses with exit code 1, and so does a board label `gh` would not create, once everything" + " else is applied. A lock or config that cannot be read, or a `.rafa/` path holding something else," + " exits 2 before anything is asked; a folder or the lock that cannot be written exits 2 naming the" + " step and what was already written. In a linked worktree the lock is the worktree's, on its branch." + " With `--output=json` the plan and what was applied are the data of the terminal result event.",
|
|
67138
67916
|
args: [],
|
|
67139
67917
|
flags: [
|
|
67140
67918
|
{ name: "dry-run", description: "Print every change and write nothing.", type: "boolean" },
|
|
@@ -67267,6 +68045,7 @@ var init_commands2 = __esm(() => {
|
|
|
67267
68045
|
init_check2();
|
|
67268
68046
|
init_comment();
|
|
67269
68047
|
init_create();
|
|
68048
|
+
init_edit();
|
|
67270
68049
|
init_list3();
|
|
67271
68050
|
init_move5();
|
|
67272
68051
|
init_ready();
|
|
@@ -67319,7 +68098,7 @@ var init_commands2 = __esm(() => {
|
|
|
67319
68098
|
CORE_SUBJECTS = Object.freeze([
|
|
67320
68099
|
{ name: "plan", summary: "create plans from specs; list, show and validate them; read their risk and needs" },
|
|
67321
68100
|
{ name: "loop", summary: "start a plan; stop, pause, resume, show and list its sessions" },
|
|
67322
|
-
{ name: "issue", summary: "the tracker: list, show, create, comment on and move issues; mark one ready, unblock it and check its references" },
|
|
68101
|
+
{ name: "issue", summary: "the tracker: list, show, create, edit, comment on and move issues; mark one ready, unblock it and check its references" },
|
|
67323
68102
|
{ name: "pr", summary: "the pull request of a branch: one line, in full or in the browser; list, wait on, merge and triage them" },
|
|
67324
68103
|
{ name: "effort", summary: "collect session and commit rows; report per plan; read and repair the store: its schema, a copy for testing, migrations, and fixes; merge or import another device's store; move an NDJSON store to SQLite" },
|
|
67325
68104
|
{ name: "module", summary: "list the configured modules; run an action a module provides" },
|
|
@@ -67354,6 +68133,7 @@ var init_commands2 = __esm(() => {
|
|
|
67354
68133
|
ready_default,
|
|
67355
68134
|
unblock_default,
|
|
67356
68135
|
check_default2,
|
|
68136
|
+
edit_default,
|
|
67357
68137
|
current_default,
|
|
67358
68138
|
show_default6,
|
|
67359
68139
|
view_default,
|
|
@@ -68040,12 +68820,12 @@ init_config_sections();
|
|
|
68040
68820
|
init_sessions();
|
|
68041
68821
|
init_scope();
|
|
68042
68822
|
init_sections2();
|
|
68043
|
-
import { mkdirSync as
|
|
68044
|
-
import { dirname as dirname40, join as
|
|
68823
|
+
import { mkdirSync as mkdirSync33, readFileSync as readFileSync85, renameSync as renameSync13, writeFileSync as writeFileSync36 } from "fs";
|
|
68824
|
+
import { dirname as dirname40, join as join105 } from "path";
|
|
68045
68825
|
var SEEN_FILE = "status-seen.json";
|
|
68046
68826
|
var SEEN_VERSION = 1;
|
|
68047
68827
|
function seenFilePath(root) {
|
|
68048
|
-
return
|
|
68828
|
+
return join105(scopeAt(root).dir, SEEN_FILE);
|
|
68049
68829
|
}
|
|
68050
68830
|
function readSeenSessions(root, isAlive) {
|
|
68051
68831
|
const sessions = {};
|
|
@@ -68112,9 +68892,9 @@ function readSeenFile(root) {
|
|
|
68112
68892
|
}
|
|
68113
68893
|
function writeSeenFile(root, snapshot) {
|
|
68114
68894
|
const file = seenFilePath(root);
|
|
68115
|
-
|
|
68895
|
+
mkdirSync33(dirname40(file), { recursive: true });
|
|
68116
68896
|
const temporary = `${file}.${String(process.pid)}.tmp`;
|
|
68117
|
-
|
|
68897
|
+
writeFileSync36(temporary, `${JSON.stringify(snapshot, null, 2)}
|
|
68118
68898
|
`);
|
|
68119
68899
|
renameSync13(temporary, file);
|
|
68120
68900
|
}
|