@open-tomato/rafa 0.9.0 → 0.9.1
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 +25 -8
- package/dist/cli.js +791 -501
- package/dist/index.js +393 -143
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1914,7 +1914,7 @@ async function report(args, repoRoot) {
|
|
|
1914
1914
|
}
|
|
1915
1915
|
}
|
|
1916
1916
|
// package.json
|
|
1917
|
-
var version = "0.9.
|
|
1917
|
+
var version = "0.9.1";
|
|
1918
1918
|
|
|
1919
1919
|
// src/modules/manifest.ts
|
|
1920
1920
|
var MANIFEST_VERSION = 1;
|
|
@@ -3503,8 +3503,8 @@ function createGhIssueBoard(options) {
|
|
|
3503
3503
|
}
|
|
3504
3504
|
|
|
3505
3505
|
// src/board/issue.ts
|
|
3506
|
-
import { existsSync as existsSync7, mkdirSync as
|
|
3507
|
-
import { dirname as dirname2, resolve as
|
|
3506
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync6, statSync as statSync5, writeFileSync as writeFileSync2 } from "fs";
|
|
3507
|
+
import { dirname as dirname2, resolve as resolve6 } from "path";
|
|
3508
3508
|
|
|
3509
3509
|
// src/board/naming.ts
|
|
3510
3510
|
import path2 from "path";
|
|
@@ -3584,8 +3584,72 @@ function notesPath(specsDir, issue) {
|
|
|
3584
3584
|
return path2.join(specsDir, notesFileName(issue));
|
|
3585
3585
|
}
|
|
3586
3586
|
|
|
3587
|
+
// src/board/previous-copy.ts
|
|
3588
|
+
import { linkSync, mkdirSync as mkdirSync2, readdirSync as readdirSync3, statSync as statSync4, unlinkSync } from "fs";
|
|
3589
|
+
import { basename as basename3, extname, join as join5, resolve as resolve5 } from "path";
|
|
3590
|
+
var PREFIX2 = "board previous copy";
|
|
3591
|
+
var PREVIOUS_DIR_NAME = "previous";
|
|
3592
|
+
var COPY_EXTENSION = ".md";
|
|
3593
|
+
var FIRST_SUFFIX = 2;
|
|
3594
|
+
function previousDir(specsDir) {
|
|
3595
|
+
return join5(specsDir, PREVIOUS_DIR_NAME);
|
|
3596
|
+
}
|
|
3597
|
+
function two(value) {
|
|
3598
|
+
return String(value).padStart(2, "0");
|
|
3599
|
+
}
|
|
3600
|
+
function previousTimestamp(mtime) {
|
|
3601
|
+
const date = `${String(mtime.getUTCFullYear()).padStart(4, "0")}${two(mtime.getUTCMonth() + 1)}${two(mtime.getUTCDate())}`;
|
|
3602
|
+
const time = `${two(mtime.getUTCHours())}${two(mtime.getUTCMinutes())}${two(mtime.getUTCSeconds())}`;
|
|
3603
|
+
return `${date}T${time}Z`;
|
|
3604
|
+
}
|
|
3605
|
+
function previousCopyName(savedName, timestamp, attempt) {
|
|
3606
|
+
const stem = basename3(savedName, extname(savedName));
|
|
3607
|
+
const suffix = attempt < FIRST_SUFFIX ? "" : `-${String(attempt)}`;
|
|
3608
|
+
return `${stem}.${timestamp}${suffix}${COPY_EXTENSION}`;
|
|
3609
|
+
}
|
|
3610
|
+
function isTaken(error) {
|
|
3611
|
+
return error instanceof Error && "code" in error && error.code === "EEXIST";
|
|
3612
|
+
}
|
|
3613
|
+
function linkUnderFreeName(source, directory, savedName, timestamp) {
|
|
3614
|
+
for (let attempt = 1;; attempt += 1) {
|
|
3615
|
+
const name = previousCopyName(savedName, timestamp, attempt);
|
|
3616
|
+
try {
|
|
3617
|
+
linkSync(source, join5(directory, name));
|
|
3618
|
+
return name;
|
|
3619
|
+
} catch (error) {
|
|
3620
|
+
if (!isTaken(error))
|
|
3621
|
+
throw error;
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
function movePreviousCopy(options) {
|
|
3626
|
+
const { repoRoot, specsDir, path: path3 } = options;
|
|
3627
|
+
const source = resolve5(repoRoot, path3);
|
|
3628
|
+
const directory = previousDir(specsDir);
|
|
3629
|
+
const absoluteDirectory = resolve5(repoRoot, directory);
|
|
3630
|
+
const savedName = basename3(path3);
|
|
3631
|
+
let name;
|
|
3632
|
+
try {
|
|
3633
|
+
const timestamp = previousTimestamp(statSync4(source).mtime);
|
|
3634
|
+
mkdirSync2(absoluteDirectory, { recursive: true });
|
|
3635
|
+
name = linkUnderFreeName(source, absoluteDirectory, savedName, timestamp);
|
|
3636
|
+
} catch (error) {
|
|
3637
|
+
throw new Error(`${PREFIX2}: ${path3} could not be moved to ${directory}: ${messageOf(error)}`, { cause: error });
|
|
3638
|
+
}
|
|
3639
|
+
const moved = {
|
|
3640
|
+
path: join5(directory, name),
|
|
3641
|
+
absolute: join5(absoluteDirectory, name)
|
|
3642
|
+
};
|
|
3643
|
+
try {
|
|
3644
|
+
unlinkSync(source);
|
|
3645
|
+
} catch (error) {
|
|
3646
|
+
throw new Error(`${PREFIX2}: ${path3} was copied to ${moved.path} but could not be removed: ${messageOf(error)}`, { cause: error });
|
|
3647
|
+
}
|
|
3648
|
+
return moved;
|
|
3649
|
+
}
|
|
3650
|
+
|
|
3587
3651
|
// src/board/issue.ts
|
|
3588
|
-
var
|
|
3652
|
+
var PREFIX3 = "board issue";
|
|
3589
3653
|
var ISSUE_VIEW_FIELDS = "number,title,body,state,labels,author";
|
|
3590
3654
|
var SPEC_LABEL = "type:spec";
|
|
3591
3655
|
var ISSUE_REFUSAL_EXIT = 2;
|
|
@@ -3596,7 +3660,7 @@ function detailOf3(result, command) {
|
|
|
3596
3660
|
}
|
|
3597
3661
|
function issueNumber2(value) {
|
|
3598
3662
|
if (!Number.isSafeInteger(value) || value < 1) {
|
|
3599
|
-
throw new TypeError(`${
|
|
3663
|
+
throw new TypeError(`${PREFIX3}: the read refused issue number ${describeValue(value)}, expected a positive whole number`);
|
|
3600
3664
|
}
|
|
3601
3665
|
return String(value);
|
|
3602
3666
|
}
|
|
@@ -3631,11 +3695,11 @@ function readViewedIssue(stdout, number, command) {
|
|
|
3631
3695
|
try {
|
|
3632
3696
|
payload = JSON.parse(stdout);
|
|
3633
3697
|
} catch (error) {
|
|
3634
|
-
throw new Error(`${
|
|
3698
|
+
throw new Error(`${PREFIX3}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
|
|
3635
3699
|
}
|
|
3636
3700
|
const problem = viewProblem(payload, number);
|
|
3637
3701
|
if (problem !== null)
|
|
3638
|
-
throw new Error(`${
|
|
3702
|
+
throw new Error(`${PREFIX3}: ${command} answered ${problem}`);
|
|
3639
3703
|
const checked = payload;
|
|
3640
3704
|
return {
|
|
3641
3705
|
number,
|
|
@@ -3653,7 +3717,7 @@ function createGhSpecIssueReader(options) {
|
|
|
3653
3717
|
const command = `gh issue view ${number} --json ${ISSUE_VIEW_FIELDS}`;
|
|
3654
3718
|
const result = await gh(["issue", "view", number, "--json", ISSUE_VIEW_FIELDS]);
|
|
3655
3719
|
if (!result.ok)
|
|
3656
|
-
throw new Error(`${
|
|
3720
|
+
throw new Error(`${PREFIX3}: ${detailOf3(result, command)}`);
|
|
3657
3721
|
return readViewedIssue(result.stdout, issue, command);
|
|
3658
3722
|
};
|
|
3659
3723
|
}
|
|
@@ -3691,10 +3755,91 @@ ${local}`
|
|
|
3691
3755
|
`)}
|
|
3692
3756
|
`;
|
|
3693
3757
|
}
|
|
3758
|
+
var NOTES_SEPARATOR = `
|
|
3759
|
+
|
|
3760
|
+
${LOCAL_NOTES_HEADING}
|
|
3761
|
+
|
|
3762
|
+
`;
|
|
3763
|
+
var HEADING = /^#{1,6}(?:[ \t]|$)/u;
|
|
3764
|
+
var FENCE = /^ {0,3}(?:`{3,}|~{3,})/u;
|
|
3765
|
+
function commonLines(before, after) {
|
|
3766
|
+
let previous = new Uint32Array(after.length + 1);
|
|
3767
|
+
for (const line of before) {
|
|
3768
|
+
const row = new Uint32Array(after.length + 1);
|
|
3769
|
+
after.forEach((other, index) => {
|
|
3770
|
+
row[index + 1] = line === other ? (previous[index] ?? 0) + 1 : Math.max(previous[index + 1] ?? 0, row[index] ?? 0);
|
|
3771
|
+
});
|
|
3772
|
+
previous = row;
|
|
3773
|
+
}
|
|
3774
|
+
return previous[after.length] ?? 0;
|
|
3775
|
+
}
|
|
3776
|
+
function headingName(line) {
|
|
3777
|
+
const text = line.replace(/^#+/u, "").replace(/[ \t]+#+[ \t]*$/u, "").trim();
|
|
3778
|
+
return text === "" ? line.trim() : text;
|
|
3779
|
+
}
|
|
3780
|
+
function headingSections(lines) {
|
|
3781
|
+
const sections = new Map;
|
|
3782
|
+
let fenced = false;
|
|
3783
|
+
let current = null;
|
|
3784
|
+
const close = () => {
|
|
3785
|
+
if (current === null)
|
|
3786
|
+
return;
|
|
3787
|
+
sections.set(current.key, [...sections.get(current.key) ?? [], current.lines.join(`
|
|
3788
|
+
`)]);
|
|
3789
|
+
};
|
|
3790
|
+
for (const line of lines) {
|
|
3791
|
+
if (FENCE.test(line))
|
|
3792
|
+
fenced = !fenced;
|
|
3793
|
+
if (fenced || !HEADING.test(line)) {
|
|
3794
|
+
current?.lines.push(line);
|
|
3795
|
+
continue;
|
|
3796
|
+
}
|
|
3797
|
+
close();
|
|
3798
|
+
current = { key: line.trim(), lines: [] };
|
|
3799
|
+
}
|
|
3800
|
+
close();
|
|
3801
|
+
return sections;
|
|
3802
|
+
}
|
|
3803
|
+
function changedHeadings(before, after) {
|
|
3804
|
+
const old = headingSections(before);
|
|
3805
|
+
const now = headingSections(after);
|
|
3806
|
+
const keys = [...now.keys(), ...[...old.keys()].filter((key) => !now.has(key))];
|
|
3807
|
+
const changed = keys.filter((key) => JSON.stringify(old.get(key) ?? []) !== JSON.stringify(now.get(key) ?? []));
|
|
3808
|
+
return [...new Set(changed.map(headingName))];
|
|
3809
|
+
}
|
|
3810
|
+
function bodyChangeLine(before, after) {
|
|
3811
|
+
const old = before.split(`
|
|
3812
|
+
`);
|
|
3813
|
+
const now = after.split(`
|
|
3814
|
+
`);
|
|
3815
|
+
const common = commonLines(old, now);
|
|
3816
|
+
const headings = changedHeadings(old, now);
|
|
3817
|
+
const clause = headings.length === 0 ? "no heading changed" : `headings changed: ${headings.join(", ")}`;
|
|
3818
|
+
return `issue body: +${String(now.length - common)} -${String(old.length - common)} lines; ${clause}`;
|
|
3819
|
+
}
|
|
3820
|
+
function notesChangeLine(path3) {
|
|
3821
|
+
return `local notes: ${path3} changed since the saved copy`;
|
|
3822
|
+
}
|
|
3823
|
+
function readSnapshotChange(options) {
|
|
3824
|
+
const { saved, body, notes, notesPath: path3 } = options;
|
|
3825
|
+
if (saved === snapshotText(body, notes))
|
|
3826
|
+
return { kind: "unchanged", bodyLine: null, notesLine: null };
|
|
3827
|
+
const now = normalise(body);
|
|
3828
|
+
if (saved === `${now}
|
|
3829
|
+
` || saved.startsWith(`${now}${NOTES_SEPARATOR}`)) {
|
|
3830
|
+
return { kind: "notes", bodyLine: null, notesLine: notesChangeLine(path3) };
|
|
3831
|
+
}
|
|
3832
|
+
const split = saved.lastIndexOf(NOTES_SEPARATOR);
|
|
3833
|
+
const oldBody = split === -1 ? saved : saved.slice(0, split);
|
|
3834
|
+
const oldNotes = split === -1 ? "" : normalise(saved.slice(split + NOTES_SEPARATOR.length)).trim();
|
|
3835
|
+
const newNotes = notes === null ? "" : normalise(notes).trim();
|
|
3836
|
+
const bodyLine = bodyChangeLine(normalise(oldBody), now);
|
|
3837
|
+
return oldNotes === newNotes ? { kind: "body", bodyLine, notesLine: null } : { kind: "both", bodyLine, notesLine: notesChangeLine(path3) };
|
|
3838
|
+
}
|
|
3694
3839
|
function readIfFile(file, what) {
|
|
3695
3840
|
if (!existsSync7(file))
|
|
3696
3841
|
return null;
|
|
3697
|
-
if (!
|
|
3842
|
+
if (!statSync5(file).isFile()) {
|
|
3698
3843
|
throw new CommandExit(ISSUE_REFUSAL_EXIT, `${what} ${file} is not a file, and a spec is one`);
|
|
3699
3844
|
}
|
|
3700
3845
|
try {
|
|
@@ -3704,7 +3849,7 @@ function readIfFile(file, what) {
|
|
|
3704
3849
|
}
|
|
3705
3850
|
}
|
|
3706
3851
|
function readLocalNotes(repoRoot, specsDir, issue) {
|
|
3707
|
-
return readIfFile(
|
|
3852
|
+
return readIfFile(resolve6(repoRoot, notesPath(specsDir, issue)), "the local notes");
|
|
3708
3853
|
}
|
|
3709
3854
|
function snapshotDiffersMessage(path3, issue) {
|
|
3710
3855
|
return `${path3} is a snapshot of issue #${String(issue)} that no longer matches it:` + " the issue body, or the local notes appended to it, changed since the snapshot was written;" + ` pass ${REFRESH_FLAG} to plan from the issue as it reads now, or --spec=${path3} to plan from` + " the snapshot as it stands";
|
|
@@ -3721,27 +3866,38 @@ function writeSpecSnapshot(options) {
|
|
|
3721
3866
|
}
|
|
3722
3867
|
const local = readLocalNotes(repoRoot, specsDir, issue.number);
|
|
3723
3868
|
const text = snapshotText(issue.body, local);
|
|
3724
|
-
const absolute =
|
|
3869
|
+
const absolute = resolve6(repoRoot, path3);
|
|
3725
3870
|
const existing = readIfFile(absolute, "the spec snapshot");
|
|
3726
3871
|
const written = {
|
|
3727
3872
|
path: path3,
|
|
3728
3873
|
absolute,
|
|
3729
3874
|
action: "created",
|
|
3730
3875
|
notes: local === null ? null : notes,
|
|
3876
|
+
previous: null,
|
|
3731
3877
|
text
|
|
3732
3878
|
};
|
|
3733
3879
|
if (existing === text)
|
|
3734
3880
|
return { ...written, action: "unchanged" };
|
|
3735
|
-
|
|
3881
|
+
const action = rewriteAction(existing, issue.body, local, notes, refresh);
|
|
3882
|
+
if (action === null) {
|
|
3736
3883
|
throw new CommandExit(ISSUE_REFUSAL_EXIT, snapshotDiffersMessage(path3, issue.number));
|
|
3737
3884
|
}
|
|
3885
|
+
const previous = action === "created" ? null : movePreviousCopy({ repoRoot, specsDir, path: path3 }).path;
|
|
3738
3886
|
try {
|
|
3739
|
-
|
|
3887
|
+
mkdirSync3(dirname2(absolute), { recursive: true });
|
|
3740
3888
|
writeFileSync2(absolute, text);
|
|
3741
3889
|
} catch (error) {
|
|
3742
|
-
throw new Error(`${
|
|
3890
|
+
throw new Error(`${PREFIX3}: the snapshot ${path3} could not be written: ${messageOf(error)}`, { cause: error });
|
|
3743
3891
|
}
|
|
3744
|
-
return
|
|
3892
|
+
return { ...written, action, previous };
|
|
3893
|
+
}
|
|
3894
|
+
function rewriteAction(existing, body, notes, notesFile, refresh) {
|
|
3895
|
+
if (existing === null)
|
|
3896
|
+
return "created";
|
|
3897
|
+
const { kind } = readSnapshotChange({ saved: existing, body, notes, notesPath: notesFile });
|
|
3898
|
+
if (kind === "notes")
|
|
3899
|
+
return "notes-rebuilt";
|
|
3900
|
+
return refresh ? "refreshed" : null;
|
|
3745
3901
|
}
|
|
3746
3902
|
|
|
3747
3903
|
// src/board/leak.ts
|
|
@@ -3843,7 +3999,7 @@ function requireNoLeak(source, body) {
|
|
|
3843
3999
|
}
|
|
3844
4000
|
|
|
3845
4001
|
// src/board/roadmap.ts
|
|
3846
|
-
var
|
|
4002
|
+
var PREFIX4 = "board roadmap";
|
|
3847
4003
|
var ROADMAP_TITLE = "Roadmap";
|
|
3848
4004
|
var ROADMAP_SETTING = "roadmap.issue";
|
|
3849
4005
|
var ROADMAP_REFUSAL_EXIT = 2;
|
|
@@ -3852,7 +4008,7 @@ var OPEN_PULL_REQUEST_LIMIT = 100;
|
|
|
3852
4008
|
var PR_LIST_FIELDS = "number,headRefName,body";
|
|
3853
4009
|
var ISSUE_LIST_FIELDS = "number,title";
|
|
3854
4010
|
var TASK_LINE = /^\s*[-*+]\s+\[([ xX])\]\s+#(\d+)\s*(.*)$/u;
|
|
3855
|
-
var
|
|
4011
|
+
var FENCE2 = /^\s*(?:`{3,}|~{3,})/u;
|
|
3856
4012
|
var WHY_SEPARATOR = /^[-:,.\u2013\u2014]\s*/u;
|
|
3857
4013
|
var CLOSING = /\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\b\s*:?\s*#(\d+)\b/giu;
|
|
3858
4014
|
function whyOf(rest) {
|
|
@@ -3862,7 +4018,7 @@ function parseRoadmapBody(body) {
|
|
|
3862
4018
|
let lines = [];
|
|
3863
4019
|
let fenced = false;
|
|
3864
4020
|
body.split(/\r\n?|\n/u).forEach((text, index) => {
|
|
3865
|
-
if (
|
|
4021
|
+
if (FENCE2.test(text)) {
|
|
3866
4022
|
fenced = !fenced;
|
|
3867
4023
|
return;
|
|
3868
4024
|
}
|
|
@@ -3893,24 +4049,24 @@ function parseRows(stdout, command) {
|
|
|
3893
4049
|
try {
|
|
3894
4050
|
payload = JSON.parse(stdout);
|
|
3895
4051
|
} catch (error) {
|
|
3896
|
-
throw new Error(`${
|
|
4052
|
+
throw new Error(`${PREFIX4}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
|
|
3897
4053
|
}
|
|
3898
4054
|
if (!Array.isArray(payload)) {
|
|
3899
|
-
throw new Error(`${
|
|
4055
|
+
throw new Error(`${PREFIX4}: ${command} answered ${describeValue(payload)}, expected a list`);
|
|
3900
4056
|
}
|
|
3901
4057
|
return payload;
|
|
3902
4058
|
}
|
|
3903
4059
|
function rowNumber(row, key, command, where) {
|
|
3904
4060
|
const value = isMapping(row) ? row[key] : null;
|
|
3905
4061
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) {
|
|
3906
|
-
throw new Error(`${
|
|
4062
|
+
throw new Error(`${PREFIX4}: ${command} answered ${where}.${key} as ${describeValue(value)}, expected a positive whole number`);
|
|
3907
4063
|
}
|
|
3908
4064
|
return value;
|
|
3909
4065
|
}
|
|
3910
4066
|
function rowText(row, key, command, where) {
|
|
3911
4067
|
const value = isMapping(row) ? row[key] : null;
|
|
3912
4068
|
if (typeof value !== "string") {
|
|
3913
|
-
throw new Error(`${
|
|
4069
|
+
throw new Error(`${PREFIX4}: ${command} answered ${where}.${key} as ${describeValue(value)}, expected a string`);
|
|
3914
4070
|
}
|
|
3915
4071
|
return value;
|
|
3916
4072
|
}
|
|
@@ -3922,7 +4078,7 @@ function createGhRoadmapSearch(options) {
|
|
|
3922
4078
|
return async () => {
|
|
3923
4079
|
const result = await gh(args);
|
|
3924
4080
|
if (!result.ok)
|
|
3925
|
-
throw new Error(`${
|
|
4081
|
+
throw new Error(`${PREFIX4}: ${detailOf4(result, command)}`);
|
|
3926
4082
|
return Object.freeze(parseRows(result.stdout, command).map((row, index) => ({
|
|
3927
4083
|
number: rowNumber(row, "number", command, `issue ${String(index)}`),
|
|
3928
4084
|
title: rowText(row, "title", command, `issue ${String(index)}`)
|
|
@@ -3957,7 +4113,7 @@ function createGhOpenPullRequests(options) {
|
|
|
3957
4113
|
return async () => {
|
|
3958
4114
|
const result = await gh(args);
|
|
3959
4115
|
if (!result.ok)
|
|
3960
|
-
throw new Error(`${
|
|
4116
|
+
throw new Error(`${PREFIX4}: ${detailOf4(result, command)}`);
|
|
3961
4117
|
return Object.freeze(parseRows(result.stdout, command).map((row, index) => ({
|
|
3962
4118
|
number: rowNumber(row, "number", command, `pull request ${String(index)}`),
|
|
3963
4119
|
headRefName: rowText(row, "headRefName", command, `pull request ${String(index)}`),
|
|
@@ -4216,8 +4372,74 @@ function declinedMessage(alternative) {
|
|
|
4216
4372
|
return `#${String(alternative)} was not planned, and nothing was written`;
|
|
4217
4373
|
}
|
|
4218
4374
|
|
|
4375
|
+
// src/board/snapshot-settle.ts
|
|
4376
|
+
import { existsSync as existsSync8, readFileSync as readFileSync7, statSync as statSync6 } from "fs";
|
|
4377
|
+
import { resolve as resolve7 } from "path";
|
|
4378
|
+
var PREFIX5 = "board snapshot settle";
|
|
4379
|
+
var DATE_LENGTH = 10;
|
|
4380
|
+
function savedCopyDate(savedAt) {
|
|
4381
|
+
return savedAt.toISOString().slice(0, DATE_LENGTH);
|
|
4382
|
+
}
|
|
4383
|
+
function refreshQuestion(issue, savedAt) {
|
|
4384
|
+
return `Issue #${String(issue)} changed since the saved copy of ${savedCopyDate(savedAt)}.` + " Plan from it as it reads now? [y/N] ";
|
|
4385
|
+
}
|
|
4386
|
+
function notesRebuiltLine(path3, issue, previous) {
|
|
4387
|
+
return `local notes changed; rebuilt ${path3} from issue #${String(issue)} and the notes,` + ` the old copy is at ${previous}`;
|
|
4388
|
+
}
|
|
4389
|
+
function readSavedCopy(absolute, path3) {
|
|
4390
|
+
if (!existsSync8(absolute))
|
|
4391
|
+
return null;
|
|
4392
|
+
try {
|
|
4393
|
+
const stat = statSync6(absolute);
|
|
4394
|
+
if (!stat.isFile())
|
|
4395
|
+
return null;
|
|
4396
|
+
return { text: readFileSync7(absolute, "utf8"), savedAt: stat.mtime };
|
|
4397
|
+
} catch (error) {
|
|
4398
|
+
throw new Error(`${PREFIX5}: the saved copy ${path3} could not be read: ${messageOf(error)}`, { cause: error });
|
|
4399
|
+
}
|
|
4400
|
+
}
|
|
4401
|
+
function printChange(change, output) {
|
|
4402
|
+
for (const line of [change.bodyLine, change.notesLine]) {
|
|
4403
|
+
if (line !== null)
|
|
4404
|
+
output.info(line);
|
|
4405
|
+
}
|
|
4406
|
+
}
|
|
4407
|
+
async function settleSpecSnapshot(options) {
|
|
4408
|
+
const { repoRoot, specsDir, issue, refresh, output } = options;
|
|
4409
|
+
const write = (rewrite) => writeSpecSnapshot({ repoRoot, specsDir, issue, refresh: rewrite });
|
|
4410
|
+
const path3 = specPath(specsDir, issue.number, issue.title);
|
|
4411
|
+
const notes = notesPath(specsDir, issue.number);
|
|
4412
|
+
if (path3 === notes)
|
|
4413
|
+
return write(refresh);
|
|
4414
|
+
const saved = readSavedCopy(resolve7(repoRoot, path3), path3);
|
|
4415
|
+
if (saved === null)
|
|
4416
|
+
return write(refresh);
|
|
4417
|
+
const change = readSnapshotChange({
|
|
4418
|
+
saved: saved.text,
|
|
4419
|
+
body: issue.body,
|
|
4420
|
+
notes: readLocalNotes(repoRoot, specsDir, issue.number),
|
|
4421
|
+
notesPath: notes
|
|
4422
|
+
});
|
|
4423
|
+
if (change.kind === "unchanged")
|
|
4424
|
+
return write(refresh);
|
|
4425
|
+
printChange(change, output);
|
|
4426
|
+
if (change.kind === "notes") {
|
|
4427
|
+
const rebuilt = write(refresh);
|
|
4428
|
+
if (rebuilt.previous !== null)
|
|
4429
|
+
output.info(notesRebuiltLine(rebuilt.path, issue.number, rebuilt.previous));
|
|
4430
|
+
return rebuilt;
|
|
4431
|
+
}
|
|
4432
|
+
if (refresh)
|
|
4433
|
+
return write(true);
|
|
4434
|
+
const offer = options.offerRefresh ?? null;
|
|
4435
|
+
const accepted = offer !== null && await offer({ issue: issue.number, path: path3, savedAt: saved.savedAt });
|
|
4436
|
+
if (!accepted)
|
|
4437
|
+
throw new CommandExit(ISSUE_REFUSAL_EXIT, snapshotDiffersMessage(path3, issue.number));
|
|
4438
|
+
return write(true);
|
|
4439
|
+
}
|
|
4440
|
+
|
|
4219
4441
|
// src/board/spec-source.ts
|
|
4220
|
-
var
|
|
4442
|
+
var PREFIX6 = "board spec source";
|
|
4221
4443
|
var SOURCE_FLAGS = [SPEC_FLAG, ISSUE_FLAG, NEXT_FLAG];
|
|
4222
4444
|
var SOURCE_REFUSAL_EXIT = 1;
|
|
4223
4445
|
function severalSourcesMessage(given) {
|
|
@@ -4336,7 +4558,7 @@ async function settleBlockedPick(options) {
|
|
|
4336
4558
|
async function pickRoadmapIssue(request, options, issues, output) {
|
|
4337
4559
|
const seams = options.roadmap;
|
|
4338
4560
|
if (seams === undefined) {
|
|
4339
|
-
throw new TypeError(`${
|
|
4561
|
+
throw new TypeError(`${PREFIX6}: ${NEXT_FLAG} was resolved with no roadmap seams`);
|
|
4340
4562
|
}
|
|
4341
4563
|
const roadmap = await resolveRoadmapIssue({
|
|
4342
4564
|
configured: request.roadmap ?? seams.configured,
|
|
@@ -4409,7 +4631,14 @@ async function resolveSpecSource(options) {
|
|
|
4409
4631
|
output.info(dryRunLine(describeIssue(read)));
|
|
4410
4632
|
return stopped("dry-run");
|
|
4411
4633
|
}
|
|
4412
|
-
const snapshot =
|
|
4634
|
+
const snapshot = await settleSpecSnapshot({
|
|
4635
|
+
repoRoot,
|
|
4636
|
+
specsDir,
|
|
4637
|
+
issue: read,
|
|
4638
|
+
refresh,
|
|
4639
|
+
offerRefresh: options.offerRefresh ?? null,
|
|
4640
|
+
output
|
|
4641
|
+
});
|
|
4413
4642
|
return Object.freeze({
|
|
4414
4643
|
outcome: "spec",
|
|
4415
4644
|
spec: Object.freeze({
|
|
@@ -4482,6 +4711,7 @@ async function resolvePlanSpec(options) {
|
|
|
4482
4711
|
const offer = offerReady === null || options.dryRun ? undefined : (issue) => offerReady({ issue, gh, trust: trust(), output });
|
|
4483
4712
|
const offerAlternative = options.offerAlternative ?? null;
|
|
4484
4713
|
const alternative = offerAlternative === null || options.dryRun ? undefined : offerAlternative;
|
|
4714
|
+
const offerRefresh = options.dryRun ? null : options.offerRefresh ?? null;
|
|
4485
4715
|
const resolution = await resolveSpecSource({
|
|
4486
4716
|
request: options.request,
|
|
4487
4717
|
refresh: options.refresh,
|
|
@@ -4491,6 +4721,7 @@ async function resolvePlanSpec(options) {
|
|
|
4491
4721
|
findSpec: options.findSpec,
|
|
4492
4722
|
issues: createGhSpecIssueReader({ gh }),
|
|
4493
4723
|
inspect: (issue) => inspectSpecIssue(issue, trust(), offer),
|
|
4724
|
+
offerRefresh,
|
|
4494
4725
|
roadmap: {
|
|
4495
4726
|
configured: options.roadmapIssue,
|
|
4496
4727
|
search: createGhRoadmapSearch({ gh }),
|
|
@@ -4516,15 +4747,15 @@ async function resolvePlanSpec(options) {
|
|
|
4516
4747
|
import { createInterface as createInterface2 } from "readline";
|
|
4517
4748
|
|
|
4518
4749
|
// src/project/roots.ts
|
|
4519
|
-
import { accessSync, constants, readFileSync as
|
|
4750
|
+
import { accessSync, constants, readFileSync as readFileSync8, statSync as statSync7 } from "fs";
|
|
4520
4751
|
|
|
4521
4752
|
// src/project/scope.ts
|
|
4522
|
-
import { existsSync as
|
|
4523
|
-
import { dirname as dirname3, isAbsolute as isAbsolute2, join as
|
|
4753
|
+
import { existsSync as existsSync9, realpathSync as realpathSync2 } from "fs";
|
|
4754
|
+
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join6 } from "path";
|
|
4524
4755
|
var SCOPE_DIR = dirname3(CONFIG_FILE);
|
|
4525
4756
|
var INIT_COMMAND = "rafa init";
|
|
4526
4757
|
var DISK_FILE_SYSTEM = Object.freeze({
|
|
4527
|
-
exists: (path3) =>
|
|
4758
|
+
exists: (path3) => existsSync9(path3),
|
|
4528
4759
|
realpath: (path3) => realpathSync2(path3)
|
|
4529
4760
|
});
|
|
4530
4761
|
|
|
@@ -4535,7 +4766,7 @@ class ScopeError extends Error {
|
|
|
4535
4766
|
}
|
|
4536
4767
|
}
|
|
4537
4768
|
function scopeAt(base) {
|
|
4538
|
-
return { dir:
|
|
4769
|
+
return { dir: join6(base, SCOPE_DIR), configFile: configFilePath(base) };
|
|
4539
4770
|
}
|
|
4540
4771
|
function initHint(start, passedUserConfig = null) {
|
|
4541
4772
|
const passed2 = passedUserConfig === null ? [] : [`${passedUserConfig} is the user scope's config and marks no project`];
|
|
@@ -4612,8 +4843,8 @@ var MONOREPO_MARKER_FILES = Object.freeze([
|
|
|
4612
4843
|
]);
|
|
4613
4844
|
var DISK_ROOTS_FILE_SYSTEM = Object.freeze({
|
|
4614
4845
|
...DISK_FILE_SYSTEM,
|
|
4615
|
-
readFile: (path3) =>
|
|
4616
|
-
isDirectory: (path3) =>
|
|
4846
|
+
readFile: (path3) => readFileSync8(path3, "utf8"),
|
|
4847
|
+
isDirectory: (path3) => statSync7(path3).isDirectory(),
|
|
4617
4848
|
assertWritable: (path3) => accessSync(path3, constants.W_OK)
|
|
4618
4849
|
});
|
|
4619
4850
|
|
|
@@ -4731,8 +4962,8 @@ function formatRows(rows) {
|
|
|
4731
4962
|
`);
|
|
4732
4963
|
}
|
|
4733
4964
|
function defaultSleep(ms) {
|
|
4734
|
-
return new Promise((
|
|
4735
|
-
setTimeout(
|
|
4965
|
+
return new Promise((resolve8) => {
|
|
4966
|
+
setTimeout(resolve8, ms);
|
|
4736
4967
|
});
|
|
4737
4968
|
}
|
|
4738
4969
|
async function waitForChecks(options) {
|
|
@@ -4877,7 +5108,7 @@ function compareUrl(remote, branch) {
|
|
|
4877
5108
|
return `https://${segments[0] ?? host}/${path3}/compare/${encodeBranch(branch)}${COMPARE_QUERY}`;
|
|
4878
5109
|
}
|
|
4879
5110
|
// src/pr/gh.ts
|
|
4880
|
-
var
|
|
5111
|
+
var PREFIX7 = "gh pull requests";
|
|
4881
5112
|
var REPO_PATH3 = "{owner}/{repo}";
|
|
4882
5113
|
var SUMMARY_FIELDS = "author,baseRefName,headRefName,isCrossRepository,number,state,title,updatedAt,url";
|
|
4883
5114
|
var DETAIL_FIELDS = `${SUMMARY_FIELDS},body,headRefOid,labels,mergeStateStatus,mergeable`;
|
|
@@ -4906,16 +5137,16 @@ function detailOf5(result, command) {
|
|
|
4906
5137
|
return result.ok ? `${command} exited 0 and wrote nothing` : `${command} exited non-zero and wrote nothing`;
|
|
4907
5138
|
}
|
|
4908
5139
|
function failure2(command, result) {
|
|
4909
|
-
return new Error(`${
|
|
5140
|
+
return new Error(`${PREFIX7}: ${command} failed: ${detailOf5(result, command)}`);
|
|
4910
5141
|
}
|
|
4911
5142
|
function refuse3(command, problem) {
|
|
4912
|
-
throw new Error(`${
|
|
5143
|
+
throw new Error(`${PREFIX7}: ${command} answered ${problem}`);
|
|
4913
5144
|
}
|
|
4914
5145
|
function parseJson2(stdout, command) {
|
|
4915
5146
|
try {
|
|
4916
5147
|
return JSON.parse(stdout);
|
|
4917
5148
|
} catch (error) {
|
|
4918
|
-
throw new Error(`${
|
|
5149
|
+
throw new Error(`${PREFIX7}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
|
|
4919
5150
|
}
|
|
4920
5151
|
}
|
|
4921
5152
|
function readString2(value, command, where) {
|
|
@@ -5018,7 +5249,7 @@ function readWorkflowCount(stdout) {
|
|
|
5018
5249
|
}
|
|
5019
5250
|
function pullNumber(value, member) {
|
|
5020
5251
|
if (!Number.isSafeInteger(value) || value < 1) {
|
|
5021
|
-
throw new TypeError(`${
|
|
5252
|
+
throw new TypeError(`${PREFIX7}: ${member} refused pull request number ${describeValue(value)},` + " expected a positive whole number");
|
|
5022
5253
|
}
|
|
5023
5254
|
return String(value);
|
|
5024
5255
|
}
|
|
@@ -5026,13 +5257,13 @@ function textArgument(value, member, what, whole) {
|
|
|
5026
5257
|
const bad = typeof value !== "string" || value === "" || whole && !(WHOLE_NUMBER.test(value) && Number.isSafeInteger(Number(value)));
|
|
5027
5258
|
if (bad) {
|
|
5028
5259
|
const expected2 = whole ? "a positive whole number with no leading zero" : "a non-empty string";
|
|
5029
|
-
throw new TypeError(`${
|
|
5260
|
+
throw new TypeError(`${PREFIX7}: ${member} refused ${what} ${describeValue(value)}, expected ${expected2}`);
|
|
5030
5261
|
}
|
|
5031
5262
|
return value;
|
|
5032
5263
|
}
|
|
5033
5264
|
function bodyText(value, member) {
|
|
5034
5265
|
if (typeof value !== "string") {
|
|
5035
|
-
throw new TypeError(`${
|
|
5266
|
+
throw new TypeError(`${PREFIX7}: ${member} refused a body ${describeValue(value)}, expected a string`);
|
|
5036
5267
|
}
|
|
5037
5268
|
return value;
|
|
5038
5269
|
}
|
|
@@ -5102,7 +5333,7 @@ function createGhPullRequests(options) {
|
|
|
5102
5333
|
merge: async (number, method) => {
|
|
5103
5334
|
const target = pullNumber(number, "merge");
|
|
5104
5335
|
if (!isMergeMethod(method)) {
|
|
5105
|
-
throw new TypeError(`${
|
|
5336
|
+
throw new TypeError(`${PREFIX7}: merge refused method ${describeValue(method)},` + ` expected one of: ${MERGE_METHODS.join(", ")}`);
|
|
5106
5337
|
}
|
|
5107
5338
|
const command = `gh pr merge ${target} --${method}`;
|
|
5108
5339
|
const result = await gh(["pr", "merge", target, `--${method}`]);
|
|
@@ -5418,19 +5649,19 @@ function parseArgs(argv, spec = {}) {
|
|
|
5418
5649
|
|
|
5419
5650
|
// src/commands/loop/loop-sessions.ts
|
|
5420
5651
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
5421
|
-
import { join as
|
|
5652
|
+
import { join as join8, relative } from "path";
|
|
5422
5653
|
|
|
5423
5654
|
// src/loop/sessions.ts
|
|
5424
5655
|
import {
|
|
5425
|
-
linkSync,
|
|
5426
|
-
mkdirSync as
|
|
5427
|
-
readdirSync as
|
|
5428
|
-
readFileSync as
|
|
5656
|
+
linkSync as linkSync2,
|
|
5657
|
+
mkdirSync as mkdirSync4,
|
|
5658
|
+
readdirSync as readdirSync4,
|
|
5659
|
+
readFileSync as readFileSync9,
|
|
5429
5660
|
renameSync as renameSync2,
|
|
5430
5661
|
rmSync,
|
|
5431
5662
|
writeFileSync as writeFileSync3
|
|
5432
5663
|
} from "fs";
|
|
5433
|
-
import { basename as
|
|
5664
|
+
import { basename as basename4, dirname as dirname4, join as join7 } from "path";
|
|
5434
5665
|
var SESSION_STATES = Object.freeze(["running", "paused", "stopped", "done"]);
|
|
5435
5666
|
var RUNS_DIR = "runs";
|
|
5436
5667
|
var RECORD_EXTENSION = ".json";
|
|
@@ -5470,13 +5701,13 @@ function isSessionId(value) {
|
|
|
5470
5701
|
return SESSION_ID_PATTERN.test(value);
|
|
5471
5702
|
}
|
|
5472
5703
|
function runsDir(root) {
|
|
5473
|
-
return
|
|
5704
|
+
return join7(scopeAt(root).dir, RUNS_DIR);
|
|
5474
5705
|
}
|
|
5475
5706
|
function sessionFilePath(root, sessionId) {
|
|
5476
5707
|
if (!isSessionId(sessionId)) {
|
|
5477
5708
|
throw new Error(`session record: unusable session id ${JSON.stringify(sessionId)}`);
|
|
5478
5709
|
}
|
|
5479
|
-
return
|
|
5710
|
+
return join7(runsDir(root), `${sessionId}${RECORD_EXTENSION}`);
|
|
5480
5711
|
}
|
|
5481
5712
|
function describeValue3(value) {
|
|
5482
5713
|
return value === undefined ? "missing" : JSON.stringify(value) ?? String(value);
|
|
@@ -5507,7 +5738,7 @@ function sessionIdProblem(sessionId, file) {
|
|
|
5507
5738
|
if (typeof sessionId !== "string" || !isSessionId(sessionId)) {
|
|
5508
5739
|
return `sessionId is ${describeValue3(sessionId)}, expected a plain file name`;
|
|
5509
5740
|
}
|
|
5510
|
-
return
|
|
5741
|
+
return basename4(file) === `${sessionId}${RECORD_EXTENSION}` ? null : `sessionId ${JSON.stringify(sessionId)} is not the file's name`;
|
|
5511
5742
|
}
|
|
5512
5743
|
function planStubProblem(planStub2) {
|
|
5513
5744
|
return planStub2 === null || typeof planStub2 === "string" && isStampableStub(planStub2) ? null : `planStub is ${describeValue3(planStub2)}, expected null or a plan stub`;
|
|
@@ -5578,7 +5809,7 @@ function readState2(record, isAlive = isPidAlive) {
|
|
|
5578
5809
|
function readRecordFile(file) {
|
|
5579
5810
|
let text;
|
|
5580
5811
|
try {
|
|
5581
|
-
text =
|
|
5812
|
+
text = readFileSync9(file, "utf8");
|
|
5582
5813
|
} catch (error) {
|
|
5583
5814
|
throw new SessionRecordError(file, `cannot be read: ${messageOf(error)}`);
|
|
5584
5815
|
}
|
|
@@ -5586,7 +5817,7 @@ function readRecordFile(file) {
|
|
|
5586
5817
|
}
|
|
5587
5818
|
function recordNames(dir) {
|
|
5588
5819
|
try {
|
|
5589
|
-
return
|
|
5820
|
+
return readdirSync4(dir);
|
|
5590
5821
|
} catch (error) {
|
|
5591
5822
|
if (errorCode(error) === "ENOENT")
|
|
5592
5823
|
return [];
|
|
@@ -5599,7 +5830,7 @@ function byStart(a, b) {
|
|
|
5599
5830
|
function readSessions(root, seams = {}) {
|
|
5600
5831
|
const dir = runsDir(root);
|
|
5601
5832
|
const isAlive = seams.isAlive ?? isPidAlive;
|
|
5602
|
-
const records = recordNames(dir).filter((name) => name.endsWith(RECORD_EXTENSION)).map((name) => readRecordFile(
|
|
5833
|
+
const records = recordNames(dir).filter((name) => name.endsWith(RECORD_EXTENSION)).map((name) => readRecordFile(join7(dir, name))).map((record) => Object.freeze({ ...record, state: readState2(record, isAlive) }));
|
|
5603
5834
|
return Object.freeze(records.sort(byStart));
|
|
5604
5835
|
}
|
|
5605
5836
|
function readSession(root, sessionId, seams = {}) {
|
|
@@ -5625,13 +5856,13 @@ function checkRecord(record, file) {
|
|
|
5625
5856
|
}
|
|
5626
5857
|
function writeRecordFile(file, record, isNew) {
|
|
5627
5858
|
checkRecord(record, file);
|
|
5628
|
-
|
|
5859
|
+
mkdirSync4(dirname4(file), { recursive: true });
|
|
5629
5860
|
const temporary = `${file}.${process.pid}.tmp`;
|
|
5630
5861
|
writeFileSync3(temporary, `${JSON.stringify(record, null, 2)}
|
|
5631
5862
|
`);
|
|
5632
5863
|
try {
|
|
5633
5864
|
if (isNew)
|
|
5634
|
-
|
|
5865
|
+
linkSync2(temporary, file);
|
|
5635
5866
|
else
|
|
5636
5867
|
renameSync2(temporary, file);
|
|
5637
5868
|
} finally {
|
|
@@ -5708,7 +5939,7 @@ function readRecords(root, seams) {
|
|
|
5708
5939
|
}
|
|
5709
5940
|
|
|
5710
5941
|
// src/next/sources.ts
|
|
5711
|
-
var
|
|
5942
|
+
var PREFIX8 = "rafa next";
|
|
5712
5943
|
var DEFAULT_BASE_BRANCH = "main";
|
|
5713
5944
|
var DEFAULT_NEXT_SOURCE_SEAMS = Object.freeze({});
|
|
5714
5945
|
function memoiseIssues2(issues) {
|
|
@@ -5746,7 +5977,7 @@ function ghNextBoard(options) {
|
|
|
5746
5977
|
}
|
|
5747
5978
|
function nextProject(context) {
|
|
5748
5979
|
if (context.project === null)
|
|
5749
|
-
throw new Error(`${
|
|
5980
|
+
throw new Error(`${PREFIX8} runs inside a project, and was handed none`);
|
|
5750
5981
|
return context.project;
|
|
5751
5982
|
}
|
|
5752
5983
|
function nextConfig(project, warn) {
|
|
@@ -5756,7 +5987,7 @@ function nextConfig(project, warn) {
|
|
|
5756
5987
|
if (!(error instanceof ConfigError))
|
|
5757
5988
|
throw error;
|
|
5758
5989
|
throw new CommandExit(1, [
|
|
5759
|
-
`\u274C ${
|
|
5990
|
+
`\u274C ${PREFIX8}: the config cannot be used:`,
|
|
5760
5991
|
...error.problems.map((problem) => ` ${problem}`)
|
|
5761
5992
|
].join(`
|
|
5762
5993
|
`));
|
|
@@ -5786,22 +6017,22 @@ function openNextSources(context, seams = DEFAULT_NEXT_SOURCE_SEAMS) {
|
|
|
5786
6017
|
}
|
|
5787
6018
|
|
|
5788
6019
|
// src/commands/plan/list.ts
|
|
5789
|
-
import { existsSync as
|
|
5790
|
-
import { join as
|
|
6020
|
+
import { existsSync as existsSync10, readdirSync as readdirSync5, readFileSync as readFileSync10 } from "fs";
|
|
6021
|
+
import { join as join9 } from "path";
|
|
5791
6022
|
var USAGE2 = "rafa plan list";
|
|
5792
6023
|
function listing(dir, stub) {
|
|
5793
|
-
const plan =
|
|
5794
|
-
const trackerPath =
|
|
6024
|
+
const plan = join9(dir, planFileName(stub, false));
|
|
6025
|
+
const trackerPath = join9(dir, planFileName(stub, true));
|
|
5795
6026
|
const tracker = isFile(trackerPath) ? trackerPath : null;
|
|
5796
|
-
const planModel = parsePlan(
|
|
5797
|
-
const counted2 = tracker === null ? planModel : parsePlan(
|
|
6027
|
+
const planModel = parsePlan(readFileSync10(plan, "utf8"));
|
|
6028
|
+
const counted2 = tracker === null ? planModel : parsePlan(readFileSync10(tracker, "utf8"));
|
|
5798
6029
|
return { stub, plan, tracker, tasks: countTasks(counted2.tasks), issues: planModel.issues.length };
|
|
5799
6030
|
}
|
|
5800
6031
|
function listPlans(plans) {
|
|
5801
6032
|
const dir = plans.path;
|
|
5802
|
-
if (!
|
|
6033
|
+
if (!existsSync10(dir))
|
|
5803
6034
|
return { dir, plans: [] };
|
|
5804
|
-
const stubs =
|
|
6035
|
+
const stubs = readdirSync5(dir).filter((name) => isFile(join9(dir, name))).map((name) => stubOfPlanFile(name)).filter((stub) => stub !== null).sort((a, b) => a.localeCompare(b));
|
|
5805
6036
|
return { dir, plans: stubs.map((stub) => listing(dir, stub)) };
|
|
5806
6037
|
}
|
|
5807
6038
|
function rowNotes(plan) {
|
|
@@ -5996,7 +6227,7 @@ function branchLabel(world) {
|
|
|
5996
6227
|
}
|
|
5997
6228
|
|
|
5998
6229
|
// src/next/state.ts
|
|
5999
|
-
var
|
|
6230
|
+
var PREFIX9 = "rafa next";
|
|
6000
6231
|
var MAX_NAMED_FILES = 5;
|
|
6001
6232
|
var NEXT_PRECONDITIONS = Object.freeze([
|
|
6002
6233
|
"tree-modified",
|
|
@@ -6274,7 +6505,7 @@ async function readNextState(sources) {
|
|
|
6274
6505
|
if (found !== null)
|
|
6275
6506
|
return answer(found, world.problems());
|
|
6276
6507
|
}
|
|
6277
|
-
throw new Error(`${
|
|
6508
|
+
throw new Error(`${PREFIX9}: no row of the table answered, and the last row answers for every reading`);
|
|
6278
6509
|
}
|
|
6279
6510
|
|
|
6280
6511
|
// src/next/hint.ts
|
|
@@ -6300,8 +6531,8 @@ function wantsHint(flags) {
|
|
|
6300
6531
|
}
|
|
6301
6532
|
var DEFAULT_HINT_SEAMS = Object.freeze({});
|
|
6302
6533
|
function afterDelay(ms) {
|
|
6303
|
-
return new Promise((
|
|
6304
|
-
setTimeout(
|
|
6534
|
+
return new Promise((resolve8) => {
|
|
6535
|
+
setTimeout(resolve8, ms).unref();
|
|
6305
6536
|
});
|
|
6306
6537
|
}
|
|
6307
6538
|
function silenced() {
|
|
@@ -6355,10 +6586,10 @@ async function nextStepHint(context, seams = DEFAULT_HINT_SEAMS) {
|
|
|
6355
6586
|
}
|
|
6356
6587
|
|
|
6357
6588
|
// src/next/actions.ts
|
|
6358
|
-
var
|
|
6589
|
+
var PREFIX10 = "rafa next";
|
|
6359
6590
|
function needed(state, value, what) {
|
|
6360
6591
|
if (value === null) {
|
|
6361
|
-
throw new Error(`${
|
|
6592
|
+
throw new Error(`${PREFIX10}: state "${state.id}" proposes "${state.action}" and names no ${what}`);
|
|
6362
6593
|
}
|
|
6363
6594
|
return String(value);
|
|
6364
6595
|
}
|
|
@@ -6408,12 +6639,12 @@ function actionContext(caller, command, argv) {
|
|
|
6408
6639
|
async function runAction(caller, state) {
|
|
6409
6640
|
const invocation = actionInvocation(state);
|
|
6410
6641
|
if (invocation === null) {
|
|
6411
|
-
throw new Error(`${
|
|
6642
|
+
throw new Error(`${PREFIX10}: the action "${state.action}" of state "${state.id}" runs no registered command`);
|
|
6412
6643
|
}
|
|
6413
6644
|
const spec = ACTION_COMMANDS[invocation.action];
|
|
6414
6645
|
const command = caller.registry.find(spec.subject, spec.action);
|
|
6415
6646
|
if (command === undefined) {
|
|
6416
|
-
throw new CommandExit(1, `\u274C ${
|
|
6647
|
+
throw new CommandExit(1, `\u274C ${PREFIX10}: the "${invocation.action}" step runs "rafa ${invocation.command}", which is registered by nothing`);
|
|
6417
6648
|
}
|
|
6418
6649
|
await command.run(actionContext(caller, command, invocation.argv));
|
|
6419
6650
|
}
|
|
@@ -6452,7 +6683,7 @@ async function endWithNextStep(context, seams = DEFAULT_ENDING_SEAMS) {
|
|
|
6452
6683
|
}
|
|
6453
6684
|
|
|
6454
6685
|
// src/adapters/tracker/resolve.ts
|
|
6455
|
-
var
|
|
6686
|
+
var PREFIX11 = "tracker chain";
|
|
6456
6687
|
var FAILURE_SEPARATOR = "; ";
|
|
6457
6688
|
function warnThroughActiveOutput(message) {
|
|
6458
6689
|
activeOutput().warn(message);
|
|
@@ -6493,9 +6724,9 @@ async function resolveTracker(options) {
|
|
|
6493
6724
|
}
|
|
6494
6725
|
attempts = [...attempts, Object.freeze({ kind, ok: false, reason: outcome.reason })];
|
|
6495
6726
|
failures = [...failures, `${kind}: ${outcome.reason}`];
|
|
6496
|
-
log(`${
|
|
6727
|
+
log(`${PREFIX11}: ${kind} unavailable: ${outcome.reason}`);
|
|
6497
6728
|
}
|
|
6498
|
-
throw new Error(`${
|
|
6729
|
+
throw new Error(`${PREFIX11}: no tracker available; tried ${failures.join(FAILURE_SEPARATOR)}`);
|
|
6499
6730
|
}
|
|
6500
6731
|
|
|
6501
6732
|
// src/commands/issue/issue-tracker.ts
|
|
@@ -6738,6 +6969,23 @@ function createPlanReadyOffer(seams = DEFAULT_OFFER_SEAMS) {
|
|
|
6738
6969
|
};
|
|
6739
6970
|
}
|
|
6740
6971
|
|
|
6972
|
+
// src/commands/plan/refresh-offer.ts
|
|
6973
|
+
var DEFAULT_REFRESH_OFFER_SEAMS = Object.freeze({});
|
|
6974
|
+
function createPlanRefreshOffer(seams = DEFAULT_REFRESH_OFFER_SEAMS) {
|
|
6975
|
+
const isTerminal = seams.isTerminal ?? (() => process.stdin.isTTY === true);
|
|
6976
|
+
if (!isTerminal())
|
|
6977
|
+
return null;
|
|
6978
|
+
const openPrompter = seams.openPrompter ?? (() => createLinePrompter(process.stdin, process.stderr));
|
|
6979
|
+
return async (request) => {
|
|
6980
|
+
const prompter = lazyPrompter(openPrompter);
|
|
6981
|
+
try {
|
|
6982
|
+
return await prompter.ask(refreshQuestion(request.issue, request.savedAt));
|
|
6983
|
+
} finally {
|
|
6984
|
+
prompter.close();
|
|
6985
|
+
}
|
|
6986
|
+
};
|
|
6987
|
+
}
|
|
6988
|
+
|
|
6741
6989
|
// src/commands/plan/spec-route.ts
|
|
6742
6990
|
function specCandidates(specArg, specsDir) {
|
|
6743
6991
|
if (path3.isAbsolute(specArg))
|
|
@@ -6767,10 +7015,11 @@ async function resolveCreateSpec(options, seams = DEFAULT_ROUTE_SEAMS) {
|
|
|
6767
7015
|
const source = readSpecSourceFlags(options.args);
|
|
6768
7016
|
if (source.request === null)
|
|
6769
7017
|
throw new CommandExit(SOURCE_REFUSAL_EXIT, usageRefusal(specsDir));
|
|
6770
|
-
const
|
|
7018
|
+
const resolve8 = seams.resolve ?? resolvePlanSpec;
|
|
6771
7019
|
const makeReadyOffer = seams.makeReadyOffer ?? createPlanReadyOffer;
|
|
6772
7020
|
const makeAlternativeOffer = seams.makeAlternativeOffer ?? createPlanBlockedOffer;
|
|
6773
|
-
|
|
7021
|
+
const makeRefreshOffer = seams.makeRefreshOffer ?? createPlanRefreshOffer;
|
|
7022
|
+
return await resolve8({
|
|
6774
7023
|
request: source.request,
|
|
6775
7024
|
refresh: source.refresh,
|
|
6776
7025
|
dryRun: source.dryRun,
|
|
@@ -6780,7 +7029,8 @@ async function resolveCreateSpec(options, seams = DEFAULT_ROUTE_SEAMS) {
|
|
|
6780
7029
|
trustedAuthors: options.trustedAuthors,
|
|
6781
7030
|
findSpec: (spec) => findSpec(repoRoot, spec, specsDir),
|
|
6782
7031
|
offerReady: makeReadyOffer(),
|
|
6783
|
-
offerAlternative: makeAlternativeOffer()
|
|
7032
|
+
offerAlternative: makeAlternativeOffer(),
|
|
7033
|
+
offerRefresh: makeRefreshOffer()
|
|
6784
7034
|
});
|
|
6785
7035
|
}
|
|
6786
7036
|
|
|
@@ -6791,13 +7041,13 @@ import { homedir as homedir3 } from "os";
|
|
|
6791
7041
|
var RAFA_VERSION = version;
|
|
6792
7042
|
|
|
6793
7043
|
// src/notices/notices.ts
|
|
6794
|
-
import { mkdirSync as
|
|
6795
|
-
import { dirname as dirname5, join as
|
|
7044
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "fs";
|
|
7045
|
+
import { dirname as dirname5, join as join10 } from "path";
|
|
6796
7046
|
var NOTICE_IDS = Object.freeze(["alpha", "danger"]);
|
|
6797
7047
|
var FEEDBACK_URL = "https://github.com/open-tomato/rafa/issues/new/choose";
|
|
6798
7048
|
var ROADMAP_URL = "https://github.com/open-tomato/rafa/issues/31";
|
|
6799
7049
|
function noticesPath(home) {
|
|
6800
|
-
return
|
|
7050
|
+
return join10(home, ".rafa", "notices.json");
|
|
6801
7051
|
}
|
|
6802
7052
|
function isNoticeId(value) {
|
|
6803
7053
|
return typeof value === "string" && NOTICE_IDS.includes(value);
|
|
@@ -6805,7 +7055,7 @@ function isNoticeId(value) {
|
|
|
6805
7055
|
function readDismissed(home) {
|
|
6806
7056
|
let raw;
|
|
6807
7057
|
try {
|
|
6808
|
-
raw =
|
|
7058
|
+
raw = readFileSync11(noticesPath(home), "utf8");
|
|
6809
7059
|
} catch {
|
|
6810
7060
|
return [];
|
|
6811
7061
|
}
|
|
@@ -6824,7 +7074,7 @@ function readDismissed(home) {
|
|
|
6824
7074
|
function writeDismissed(home, ids) {
|
|
6825
7075
|
const all = NOTICE_IDS.filter((id) => ids.includes(id) || readDismissed(home).includes(id));
|
|
6826
7076
|
const path4 = noticesPath(home);
|
|
6827
|
-
|
|
7077
|
+
mkdirSync5(dirname5(path4), { recursive: true });
|
|
6828
7078
|
writeFileSync4(path4, `${JSON.stringify({ dismissed: all }, null, 2)}
|
|
6829
7079
|
`);
|
|
6830
7080
|
}
|
|
@@ -7514,7 +7764,7 @@ import { randomUUID as randomUUID7 } from "crypto";
|
|
|
7514
7764
|
|
|
7515
7765
|
// src/effort/store/absences.ts
|
|
7516
7766
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
7517
|
-
import { existsSync as
|
|
7767
|
+
import { existsSync as existsSync11 } from "fs";
|
|
7518
7768
|
var ABSENCE_REASONS = {
|
|
7519
7769
|
"no-block": true,
|
|
7520
7770
|
"unclosed-block": true,
|
|
@@ -7573,13 +7823,13 @@ function writeReportAbsence(repoRoot, write, seams = {}) {
|
|
|
7573
7823
|
write.outcome,
|
|
7574
7824
|
collectedAt
|
|
7575
7825
|
];
|
|
7576
|
-
const appended = withSqliteStore(path5, !
|
|
7826
|
+
const appended = withSqliteStore(path5, !existsSync11(path5), (db) => db.query(INSERT_ABSENCE).run(...values).changes);
|
|
7577
7827
|
return { path: path5, appended, skipped: 1 - appended };
|
|
7578
7828
|
}
|
|
7579
7829
|
|
|
7580
7830
|
// src/effort/store/changes.ts
|
|
7581
7831
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
7582
|
-
import { existsSync as
|
|
7832
|
+
import { existsSync as existsSync12 } from "fs";
|
|
7583
7833
|
var INSERT_CHANGE = `
|
|
7584
7834
|
INSERT INTO changes (
|
|
7585
7835
|
id, session_id, plan_stub, task_line,
|
|
@@ -7658,7 +7908,7 @@ var SELECT_PLAN_CHANGES = `
|
|
|
7658
7908
|
`;
|
|
7659
7909
|
function readPlanChanges(repoRoot, planStub2) {
|
|
7660
7910
|
const path5 = sqliteStorePath(repoRoot);
|
|
7661
|
-
if (!
|
|
7911
|
+
if (!existsSync12(path5))
|
|
7662
7912
|
return [];
|
|
7663
7913
|
const rows = withSqliteStore(path5, false, (db) => db.query(SELECT_PLAN_CHANGES).all(planStub2));
|
|
7664
7914
|
return rows.map((row) => ({
|
|
@@ -7891,8 +8141,8 @@ function describeTaskReportRecord(record) {
|
|
|
7891
8141
|
}
|
|
7892
8142
|
|
|
7893
8143
|
// src/utils/progress.ts
|
|
7894
|
-
import { existsSync as
|
|
7895
|
-
import { join as
|
|
8144
|
+
import { existsSync as existsSync13, writeFileSync as writeFileSync5 } from "fs";
|
|
8145
|
+
import { join as join11 } from "path";
|
|
7896
8146
|
var PROGRESS_FILE_NAME = "progress.txt";
|
|
7897
8147
|
var PROGRESS_CAP_BYTES = 16000;
|
|
7898
8148
|
var LISTED_FIELDS = [
|
|
@@ -7934,7 +8184,7 @@ var ESCAPED_CODE_POINTS = new Set([
|
|
|
7934
8184
|
8233
|
|
7935
8185
|
]);
|
|
7936
8186
|
function progressFilePath(repoRoot) {
|
|
7937
|
-
return
|
|
8187
|
+
return join11(repoRoot, PROGRESS_FILE_NAME);
|
|
7938
8188
|
}
|
|
7939
8189
|
function escapeValue(value) {
|
|
7940
8190
|
let escaped = "";
|
|
@@ -7995,7 +8245,7 @@ function renderProgressText(findings, capBytes = PROGRESS_CAP_BYTES) {
|
|
|
7995
8245
|
}
|
|
7996
8246
|
function readProgressFindings(repoRoot, planStub2) {
|
|
7997
8247
|
const path5 = sqliteStorePath(repoRoot);
|
|
7998
|
-
if (!
|
|
8248
|
+
if (!existsSync13(path5))
|
|
7999
8249
|
return [];
|
|
8000
8250
|
const rows = withSqliteStore(path5, false, (db) => {
|
|
8001
8251
|
const query = db.query(SELECT_FINDINGS);
|
|
@@ -8022,16 +8272,16 @@ function writeProgress(repoRoot, planStub2) {
|
|
|
8022
8272
|
|
|
8023
8273
|
// src/start/preflight.ts
|
|
8024
8274
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
8025
|
-
import { existsSync as
|
|
8275
|
+
import { existsSync as existsSync14, readFileSync as readFileSync13 } from "fs";
|
|
8026
8276
|
import { homedir as homedir5 } from "os";
|
|
8027
|
-
import { basename as
|
|
8277
|
+
import { basename as basename5 } from "path";
|
|
8028
8278
|
|
|
8029
8279
|
// src/preflight/first-dispatch.ts
|
|
8030
|
-
import { readFileSync as
|
|
8280
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
8031
8281
|
var TICKED_TASK = /^- \[[xX]\] (.+)/;
|
|
8032
8282
|
function readIfReadable(path5) {
|
|
8033
8283
|
try {
|
|
8034
|
-
return
|
|
8284
|
+
return readFileSync12(path5, "utf8");
|
|
8035
8285
|
} catch {
|
|
8036
8286
|
return null;
|
|
8037
8287
|
}
|
|
@@ -8064,11 +8314,11 @@ function knownMissingNotice(lines) {
|
|
|
8064
8314
|
}
|
|
8065
8315
|
function agentSourcePath(planPath) {
|
|
8066
8316
|
const tracker = trackerPathFor(planPath);
|
|
8067
|
-
return
|
|
8317
|
+
return existsSync14(tracker) ? tracker : planPath;
|
|
8068
8318
|
}
|
|
8069
8319
|
function readIfReadable2(path5) {
|
|
8070
8320
|
try {
|
|
8071
|
-
return
|
|
8321
|
+
return readFileSync13(path5, "utf8");
|
|
8072
8322
|
} catch {
|
|
8073
8323
|
return null;
|
|
8074
8324
|
}
|
|
@@ -8084,7 +8334,7 @@ function refuseUnresolvableAgents(options) {
|
|
|
8084
8334
|
if (missing.length === 0)
|
|
8085
8335
|
return;
|
|
8086
8336
|
throw new CommandExit(1, [
|
|
8087
|
-
`\u274C Refusing to start: ${
|
|
8337
|
+
`\u274C Refusing to start: ${basename5(path5)} names ${missing.length} agent(s) no loaded scope` + ` defines (loop.settingSources: ${settingSources.join(", ")}).`,
|
|
8088
8338
|
...missing.map((agent) => ` ${missingAgentLine(agent)}`),
|
|
8089
8339
|
" Nothing was checked and nothing was dispatched."
|
|
8090
8340
|
].join(`
|
|
@@ -8117,7 +8367,7 @@ function skippedStartLine(item, tracker) {
|
|
|
8117
8367
|
return `\u23ED start-only item ${item.kind} ${JSON.stringify(item.name)} was not checked:` + " it is probed on a first dispatch alone," + ` and ${tracker} already holds a ticked task`;
|
|
8118
8368
|
}
|
|
8119
8369
|
function announceSkippedStart(planPath, skipped) {
|
|
8120
|
-
const tracker =
|
|
8370
|
+
const tracker = basename5(trackerPathFor(planPath));
|
|
8121
8371
|
const output = activeOutput();
|
|
8122
8372
|
for (const [index, item] of skipped.entries()) {
|
|
8123
8373
|
const lead = index === 0 ? `
|
|
@@ -8136,7 +8386,7 @@ function startTier(planPath, items) {
|
|
|
8136
8386
|
function announceReminders(planPath, reminders) {
|
|
8137
8387
|
if (reminders.length === 0)
|
|
8138
8388
|
return;
|
|
8139
|
-
const file =
|
|
8389
|
+
const file = basename5(prerequisitesPathForPlan(planPath) ?? planPath);
|
|
8140
8390
|
const output = activeOutput();
|
|
8141
8391
|
output.info(`
|
|
8142
8392
|
\uD83D\uDCCC ${file} names ${reminders.length} step(s) the preflight does not check:`);
|
|
@@ -8372,14 +8622,14 @@ async function holdWhilePaused(options) {
|
|
|
8372
8622
|
}
|
|
8373
8623
|
|
|
8374
8624
|
// src/start/plan-path.ts
|
|
8375
|
-
import { existsSync as
|
|
8376
|
-
import { resolve as
|
|
8625
|
+
import { existsSync as existsSync15 } from "fs";
|
|
8626
|
+
import { resolve as resolve8 } from "path";
|
|
8377
8627
|
var DEFAULT_PLAN_FILE = "PLAN.md";
|
|
8378
8628
|
function resolvePlanPath(repoRoot, planDir, planArg) {
|
|
8379
8629
|
if (planArg)
|
|
8380
|
-
return
|
|
8381
|
-
const inPlanDir =
|
|
8382
|
-
return
|
|
8630
|
+
return resolve8(repoRoot, planArg);
|
|
8631
|
+
const inPlanDir = resolve8(repoRoot, planDir, DEFAULT_PLAN_FILE);
|
|
8632
|
+
return existsSync15(inPlanDir) ? inPlanDir : resolve8(repoRoot, DEFAULT_PLAN_FILE);
|
|
8383
8633
|
}
|
|
8384
8634
|
|
|
8385
8635
|
// src/utils/git.ts
|
|
@@ -8562,7 +8812,7 @@ async function handleRedChecks(io, branch, prNumber, rows) {
|
|
|
8562
8812
|
}
|
|
8563
8813
|
|
|
8564
8814
|
// src/release/prepare.ts
|
|
8565
|
-
import { readFileSync as
|
|
8815
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync7 } from "fs";
|
|
8566
8816
|
|
|
8567
8817
|
// src/release/changelog.ts
|
|
8568
8818
|
var RELEASE_HEADING_FIELDS = ["version", "date", "title"];
|
|
@@ -8747,17 +8997,17 @@ function changelogDate(now) {
|
|
|
8747
8997
|
}
|
|
8748
8998
|
|
|
8749
8999
|
// src/release/enabled.ts
|
|
8750
|
-
import { statSync as
|
|
8751
|
-
import { resolve as
|
|
9000
|
+
import { statSync as statSync8 } from "fs";
|
|
9001
|
+
import { resolve as resolve9 } from "path";
|
|
8752
9002
|
function isRegularFile(full) {
|
|
8753
9003
|
try {
|
|
8754
|
-
return
|
|
9004
|
+
return statSync8(full).isFile();
|
|
8755
9005
|
} catch {
|
|
8756
9006
|
return false;
|
|
8757
9007
|
}
|
|
8758
9008
|
}
|
|
8759
9009
|
function readFile(repoRoot, path5) {
|
|
8760
|
-
const resolved =
|
|
9010
|
+
const resolved = resolve9(repoRoot, path5);
|
|
8761
9011
|
return { path: path5, resolved, present: isRegularFile(resolved) };
|
|
8762
9012
|
}
|
|
8763
9013
|
function resolveReleaseEnabled(settings, repoRoot) {
|
|
@@ -8794,7 +9044,7 @@ function resolveReleaseLevel(declared, notes) {
|
|
|
8794
9044
|
}
|
|
8795
9045
|
|
|
8796
9046
|
// src/release/version.ts
|
|
8797
|
-
import { readFileSync as
|
|
9047
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync6 } from "fs";
|
|
8798
9048
|
var RELEASE_REMOTE = "origin";
|
|
8799
9049
|
var RELEASE_BASE_BRANCH = "main";
|
|
8800
9050
|
var VERSION_SHAPE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z.-]+))?(?:\+([0-9A-Za-z.-]+))?$/;
|
|
@@ -8886,7 +9136,7 @@ function writeManifestVersion(path5, next) {
|
|
|
8886
9136
|
const unwritten = { path: path5, written: false, previous: null, version: next };
|
|
8887
9137
|
let text;
|
|
8888
9138
|
try {
|
|
8889
|
-
text =
|
|
9139
|
+
text = readFileSync14(path5, "utf8");
|
|
8890
9140
|
} catch (error) {
|
|
8891
9141
|
return { ...unwritten, problem: `${path5} could not be read: ${messageOf(error)}` };
|
|
8892
9142
|
}
|
|
@@ -8989,7 +9239,7 @@ function planVersion(input, versionFile, level) {
|
|
|
8989
9239
|
}
|
|
8990
9240
|
function textOf(path5) {
|
|
8991
9241
|
try {
|
|
8992
|
-
return
|
|
9242
|
+
return readFileSync15(path5, "utf8");
|
|
8993
9243
|
} catch {
|
|
8994
9244
|
return null;
|
|
8995
9245
|
}
|
|
@@ -9102,7 +9352,7 @@ function changelogFailure(failed3, versionEdit, restored) {
|
|
|
9102
9352
|
}
|
|
9103
9353
|
|
|
9104
9354
|
// src/release/verify.ts
|
|
9105
|
-
import { readFileSync as
|
|
9355
|
+
import { readFileSync as readFileSync16, writeFileSync as writeFileSync8 } from "fs";
|
|
9106
9356
|
function changelogInsertionSpan(before, after) {
|
|
9107
9357
|
const beforeLines = before.split(`
|
|
9108
9358
|
`);
|
|
@@ -9119,7 +9369,7 @@ function changelogInsertionSpan(before, after) {
|
|
|
9119
9369
|
}
|
|
9120
9370
|
function textOf2(path5) {
|
|
9121
9371
|
try {
|
|
9122
|
-
return
|
|
9372
|
+
return readFileSync16(path5, "utf8");
|
|
9123
9373
|
} catch {
|
|
9124
9374
|
return null;
|
|
9125
9375
|
}
|
|
@@ -9601,11 +9851,11 @@ function announcePlanIssues(planContent) {
|
|
|
9601
9851
|
}
|
|
9602
9852
|
|
|
9603
9853
|
// src/start/runtime.ts
|
|
9604
|
-
import { existsSync as
|
|
9854
|
+
import { existsSync as existsSync16, readdirSync as readdirSync6, realpathSync as realpathSync3, statSync as statSync9 } from "fs";
|
|
9605
9855
|
import { homedir as homedir6 } from "os";
|
|
9606
|
-
import { isAbsolute as isAbsolute3, join as
|
|
9856
|
+
import { isAbsolute as isAbsolute3, join as join12, relative as relative3, resolve as resolve10, sep } from "path";
|
|
9607
9857
|
var RUNTIME_FLAG = "--runtime";
|
|
9608
|
-
var RUNTIME_SUBDIR =
|
|
9858
|
+
var RUNTIME_SUBDIR = join12(".rafa", "runtime");
|
|
9609
9859
|
var RUNTIME_ENTRY = "cli.js";
|
|
9610
9860
|
var SOURCE_DIR = "src";
|
|
9611
9861
|
var RUNTIME_COMMAND = ["start"];
|
|
@@ -9622,7 +9872,7 @@ function resolveRuntime(value, places) {
|
|
|
9622
9872
|
throw refusal3([`\u274C Refusing to start: \`--runtime\` names no runtime. Spell it ${SPELLING}.`]);
|
|
9623
9873
|
}
|
|
9624
9874
|
const isVersion = VERSION_SHAPE2.test(value);
|
|
9625
|
-
const named = isVersion ?
|
|
9875
|
+
const named = isVersion ? join12(places.home, RUNTIME_SUBDIR, value, RUNTIME_ENTRY) : resolve10(places.cwd, value);
|
|
9626
9876
|
refuseInsideSource(value, named, places);
|
|
9627
9877
|
const entry = entryOf(value, named, isVersion, places.home);
|
|
9628
9878
|
const real = realpathSync3(entry);
|
|
@@ -9633,7 +9883,7 @@ function entryOf(value, named, isVersion, home) {
|
|
|
9633
9883
|
if (isVersion) {
|
|
9634
9884
|
if (isFile2(named))
|
|
9635
9885
|
return named;
|
|
9636
|
-
const root =
|
|
9886
|
+
const root = join12(home, RUNTIME_SUBDIR);
|
|
9637
9887
|
const installed = installedVersions(root);
|
|
9638
9888
|
throw refusal3([
|
|
9639
9889
|
`\u274C Refusing to start: \`--runtime=${value}\` names no installed runtime: ${named} is no file.`,
|
|
@@ -9642,7 +9892,7 @@ function entryOf(value, named, isVersion, home) {
|
|
|
9642
9892
|
}
|
|
9643
9893
|
if (isFile2(named))
|
|
9644
9894
|
return named;
|
|
9645
|
-
const inside =
|
|
9895
|
+
const inside = join12(named, RUNTIME_ENTRY);
|
|
9646
9896
|
if (isDirectory(named) && isFile2(inside))
|
|
9647
9897
|
return inside;
|
|
9648
9898
|
throw refusal3([
|
|
@@ -9660,8 +9910,8 @@ function refuseInsideSource(value, path5, places) {
|
|
|
9660
9910
|
]);
|
|
9661
9911
|
}
|
|
9662
9912
|
function sourceDirs({ cwd, root }) {
|
|
9663
|
-
const dirs = [
|
|
9664
|
-
const real = dirs.filter((dir) =>
|
|
9913
|
+
const dirs = [join12(cwd, SOURCE_DIR), join12(root, SOURCE_DIR)];
|
|
9914
|
+
const real = dirs.filter((dir) => existsSync16(dir)).map((dir) => realpathSync3(dir));
|
|
9665
9915
|
return [...new Set([...dirs, ...real])];
|
|
9666
9916
|
}
|
|
9667
9917
|
function isInside(path5, dir) {
|
|
@@ -9670,21 +9920,21 @@ function isInside(path5, dir) {
|
|
|
9670
9920
|
}
|
|
9671
9921
|
function installedVersions(root) {
|
|
9672
9922
|
try {
|
|
9673
|
-
return
|
|
9923
|
+
return readdirSync6(root).filter((name) => isFile2(join12(root, name, RUNTIME_ENTRY))).sort((a, b) => a.localeCompare(b));
|
|
9674
9924
|
} catch {
|
|
9675
9925
|
return [];
|
|
9676
9926
|
}
|
|
9677
9927
|
}
|
|
9678
9928
|
function isFile2(path5) {
|
|
9679
9929
|
try {
|
|
9680
|
-
return
|
|
9930
|
+
return statSync9(path5).isFile();
|
|
9681
9931
|
} catch {
|
|
9682
9932
|
return false;
|
|
9683
9933
|
}
|
|
9684
9934
|
}
|
|
9685
9935
|
function isDirectory(path5) {
|
|
9686
9936
|
try {
|
|
9687
|
-
return
|
|
9937
|
+
return statSync9(path5).isDirectory();
|
|
9688
9938
|
} catch {
|
|
9689
9939
|
return false;
|
|
9690
9940
|
}
|
|
@@ -9715,7 +9965,7 @@ function realOrResolved(path5) {
|
|
|
9715
9965
|
try {
|
|
9716
9966
|
return realpathSync3(path5);
|
|
9717
9967
|
} catch {
|
|
9718
|
-
return
|
|
9968
|
+
return resolve10(path5);
|
|
9719
9969
|
}
|
|
9720
9970
|
}
|
|
9721
9971
|
async function runRuntime(entry, words, run) {
|
|
@@ -9801,11 +10051,11 @@ function eventOf(line) {
|
|
|
9801
10051
|
}
|
|
9802
10052
|
|
|
9803
10053
|
// src/triage/triage.ts
|
|
9804
|
-
import { basename as
|
|
10054
|
+
import { basename as basename6, join as join13 } from "path";
|
|
9805
10055
|
|
|
9806
10056
|
// src/effort/store/tracker-refs.ts
|
|
9807
10057
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
9808
|
-
import { existsSync as
|
|
10058
|
+
import { existsSync as existsSync17 } from "fs";
|
|
9809
10059
|
var SELECT_HELD = `
|
|
9810
10060
|
SELECT seq, tracker_ref FROM findings
|
|
9811
10061
|
WHERE session_id = ? AND artifact = ?
|
|
@@ -9928,7 +10178,7 @@ function writeTrackerRef(repoRoot, write, seams = {}) {
|
|
|
9928
10178
|
wanted.json,
|
|
9929
10179
|
collectedAt
|
|
9930
10180
|
];
|
|
9931
|
-
const [action, stored] = withSqliteStore(path5, !
|
|
10181
|
+
const [action, stored] = withSqliteStore(path5, !existsSync17(path5), (db) => {
|
|
9932
10182
|
const place = db.transaction(() => placeRef(db, path5, write, wanted, insertValues));
|
|
9933
10183
|
return place.immediate();
|
|
9934
10184
|
});
|
|
@@ -9937,14 +10187,14 @@ function writeTrackerRef(repoRoot, write, seams = {}) {
|
|
|
9937
10187
|
function readTrackerRef(repoRoot, artifact) {
|
|
9938
10188
|
checkArtifact("read", artifact);
|
|
9939
10189
|
const path5 = sqliteStorePath(repoRoot);
|
|
9940
|
-
if (!
|
|
10190
|
+
if (!existsSync17(path5))
|
|
9941
10191
|
return null;
|
|
9942
10192
|
const oldest = withSqliteStore(path5, false, (db) => db.query(SELECT_OLDEST).get(artifact));
|
|
9943
10193
|
return oldest === null ? null : heldRefOf(path5, oldest.seq, oldest.tracker_ref).ref;
|
|
9944
10194
|
}
|
|
9945
10195
|
|
|
9946
10196
|
// src/triage/triage.ts
|
|
9947
|
-
var PRIVATE_TRIAGE_DIR =
|
|
10197
|
+
var PRIVATE_TRIAGE_DIR = join13(".rafa", "triage", "private");
|
|
9948
10198
|
var SECRET_ENV_NAMES = ["GITHUB_TOKEN", "ANTHROPIC_API_KEY", "LINEAR_API_KEY"];
|
|
9949
10199
|
var TRIAGE_MODULE = "unassigned";
|
|
9950
10200
|
var BLOCKER_SEPARATOR = "; ";
|
|
@@ -9955,7 +10205,7 @@ var MIN_FENCE_LENGTH = 3;
|
|
|
9955
10205
|
var ISSUE_OPENING = "An out-of-scope bug a rafa task session reported. The loop filed it and" + " dispatches no task for it: a plan that wants it fixed declares a task.";
|
|
9956
10206
|
var COMMENT_OPENING = "Reported again by a rafa task session.";
|
|
9957
10207
|
function privateTriageDir(repoRoot) {
|
|
9958
|
-
return
|
|
10208
|
+
return join13(repoRoot, PRIVATE_TRIAGE_DIR);
|
|
9959
10209
|
}
|
|
9960
10210
|
function createPrivateTriageTracker(repoRoot, options = {}) {
|
|
9961
10211
|
return createLocalTracker({
|
|
@@ -10018,7 +10268,7 @@ function oneLine3(text) {
|
|
|
10018
10268
|
return text.replace(/\s+/g, " ").trim();
|
|
10019
10269
|
}
|
|
10020
10270
|
function bugKeyOf(trackerPath, artifact) {
|
|
10021
|
-
return `${
|
|
10271
|
+
return `${basename6(trackerPath)}${KEY_SEPARATOR}${oneLine3(artifact)}`;
|
|
10022
10272
|
}
|
|
10023
10273
|
function fenced(value) {
|
|
10024
10274
|
const runs = Array.from(value.matchAll(/`+/g), (run) => run[0].length);
|
|
@@ -10252,9 +10502,9 @@ function describeStartTriage(result) {
|
|
|
10252
10502
|
};
|
|
10253
10503
|
}
|
|
10254
10504
|
async function resolvePublicTracker(options, redact) {
|
|
10255
|
-
const
|
|
10505
|
+
const resolve11 = options.resolve ?? resolveTracker;
|
|
10256
10506
|
try {
|
|
10257
|
-
const { tracker, attempts } = await
|
|
10507
|
+
const { tracker, attempts } = await resolve11({
|
|
10258
10508
|
config: options.config,
|
|
10259
10509
|
context: { repoRoot: options.repoRoot }
|
|
10260
10510
|
});
|
|
@@ -10425,8 +10675,8 @@ function msUntil(startAt, now = new Date) {
|
|
|
10425
10675
|
return target.getTime() - now.getTime();
|
|
10426
10676
|
}
|
|
10427
10677
|
function sleepFor(ms) {
|
|
10428
|
-
return new Promise((
|
|
10429
|
-
setTimeout(
|
|
10678
|
+
return new Promise((resolve11) => {
|
|
10679
|
+
setTimeout(resolve11, ms);
|
|
10430
10680
|
});
|
|
10431
10681
|
}
|
|
10432
10682
|
async function deferUntil(startAt, now = new Date, sleep = sleepFor) {
|