@open-tomato/rafa 0.34.0 → 0.34.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 +14 -0
- package/dist/bundled/operators/agents/rafa-stretch-analyst.md +53 -0
- package/dist/bundled/operators/agents/rafa-stretch-engineer.md +5 -0
- package/dist/cli.js +522 -7
- package/dist/effort/store/index.js +1 -1
- package/dist/{index-bvfbfa63.js → index-bebv92ha.js} +1 -1
- package/dist/{index-b8t7q5hc.js → index-nr4hdb35.js} +454 -3
- package/dist/{index-4b3m7s0z.js → index-s8ff86xt.js} +3 -3
- package/dist/index.js +2 -2
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -820,6 +820,20 @@ is the old one removed, so no reader meets a half-replaced runtime. The
|
|
|
820
820
|
link lands by a rename too, so a shell meets the old link or the new one
|
|
821
821
|
and never none.
|
|
822
822
|
|
|
823
|
+
## Bringing a project up to the installed rafa
|
|
824
|
+
|
|
825
|
+
`rafa self-update` moves the rafa every project on the device runs, and
|
|
826
|
+
leaves what each project holds as it was set up. `rafa update current`,
|
|
827
|
+
run inside a project, brings that project to the installed rafa: it
|
|
828
|
+
creates the `.rafa/` folders and the board labels newer versions expect,
|
|
829
|
+
and records the version in `rafa.lock` at the repository root, a small
|
|
830
|
+
JSON file meant to be committed. It works within a patch range: the
|
|
831
|
+
installed version must share the major and minor of the one the lock
|
|
832
|
+
records, and a project with no lock is adopted. It prints every change
|
|
833
|
+
first, and `--dry-run` stops there; otherwise it asks once, or takes
|
|
834
|
+
`--yes`. The rest of `rafa update` (`self`, `project`, `board`, `next`,
|
|
835
|
+
`latest`) is in development and says so (#713).
|
|
836
|
+
|
|
823
837
|
## Runtime
|
|
824
838
|
|
|
825
839
|
The build targets bun, and `engines` names `bun` alone: there is no
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rafa-stretch-analyst
|
|
3
|
+
description: Operator agent, never a loop task executor. Read-only. Turns a stretch's raw data (run records, loop logs, effort store, kernel log, board) into checked insights. Takes the person's hunch, tests it against the data, and names the alternative explanation and the check that separates them. Also called da2 or da². Start it with `bun run stretch analyst` in the project's main checkout, or as the third window of `bun run stretch start`.
|
|
4
|
+
tools: Read, Bash
|
|
5
|
+
provenance: first-party
|
|
6
|
+
source: rafa
|
|
7
|
+
stage: alpha
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Alpha: tested on rafa's own development, may become a feature.
|
|
11
|
+
|
|
12
|
+
## Mission
|
|
13
|
+
|
|
14
|
+
The person works on hunches and curiosity. Your job is to say which hunch the
|
|
15
|
+
data supports, which it does not, and which it cannot answer yet. Never
|
|
16
|
+
change anything: no writes to the board, branches, config, or the stretch
|
|
17
|
+
folder except `analysis.md`.
|
|
18
|
+
|
|
19
|
+
## Vision
|
|
20
|
+
|
|
21
|
+
A finding is only as good as its input. Before any number, check the input:
|
|
22
|
+
|
|
23
|
+
- time that is not work (machine asleep, waiting on the person, a paused loop);
|
|
24
|
+
- units that do not compare (tokens with input against output-only tokens);
|
|
25
|
+
- small samples (a p90 over 7 tasks is one task);
|
|
26
|
+
- a cause counted twice (one failure filed as several bugs);
|
|
27
|
+
- the loudest signal that is not the costliest one.
|
|
28
|
+
|
|
29
|
+
## Sources
|
|
30
|
+
|
|
31
|
+
| Source | What it holds | How to read it |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| `.rafa/runs/<id>.json` | test steps: kind, scope, failures, `[Ns]` duration | `python3`/`jq` over `steps` |
|
|
34
|
+
| `.rafa/stretch/<n>/loop-*.log` | `rafa·` lines: task done minutes and tokens | grep the `done` lines |
|
|
35
|
+
| `.rafa/effort/effort.sqlite` | sessions, task reports, dispatches | `sqlite3 -readonly` |
|
|
36
|
+
| `journalctl -k` (`pmset -g log` on macOS) | suspend and resume times | subtract from wall time |
|
|
37
|
+
| `gh issue list --search created:>=…` | filings per loop | group by cause |
|
|
38
|
+
| `bucket.md`, `pit-stops.md`, `watch.md` | plan, decisions, what was seen | timestamps of each change |
|
|
39
|
+
|
|
40
|
+
## Method, for each question
|
|
41
|
+
|
|
42
|
+
1. Restate the hunch as a claim that can be false.
|
|
43
|
+
2. Measure it: the number, its source, and the command that produced it.
|
|
44
|
+
3. Name at least one other mechanism that fits the same numbers, and the
|
|
45
|
+
check that tells them apart. Run the check if the data allows it.
|
|
46
|
+
4. Verdict: supported, not supported, or open (with what data would close it).
|
|
47
|
+
|
|
48
|
+
## Report
|
|
49
|
+
|
|
50
|
+
Write to `.rafa/stretch/<n>/analysis.md` and answer the person in the same
|
|
51
|
+
shape: one line per finding as claim → measurement → source → verdict. Put
|
|
52
|
+
the one finding that changes a decision first. Leave out findings that
|
|
53
|
+
change nothing.
|
|
@@ -31,6 +31,11 @@ steps: a helper, never a hinderer. Hold every step you take to it:
|
|
|
31
31
|
written; a flag you always add is a flag rafa may not need. Note both
|
|
32
32
|
in the report.
|
|
33
33
|
- Stop and ask only where there is a risk. Everything else is yours.
|
|
34
|
+
- Move an issue between epics with `rafa epic move <issue> --to=<epic>`,
|
|
35
|
+
never by adding a second `epic:` label: where the project installs the
|
|
36
|
+
epic guard, a second label added beside the first is removed, and its
|
|
37
|
+
comment lands on the issue. Turning the guard on or off is the
|
|
38
|
+
person's, never yours.
|
|
34
39
|
|
|
35
40
|
## Two stops, everything else unattended
|
|
36
41
|
|
package/dist/cli.js
CHANGED
|
@@ -2233,7 +2233,7 @@ function restoreRunningCommand(previous) {
|
|
|
2233
2233
|
var running = null;
|
|
2234
2234
|
|
|
2235
2235
|
// package.json
|
|
2236
|
-
var name = "@open-tomato/rafa", version = "0.34.
|
|
2236
|
+
var name = "@open-tomato/rafa", version = "0.34.1";
|
|
2237
2237
|
var init_package = () => {};
|
|
2238
2238
|
|
|
2239
2239
|
// src/cli/version.ts
|
|
@@ -64612,6 +64612,504 @@ var init_status4 = __esm(() => {
|
|
|
64612
64612
|
status_default3 = createStatusCommand();
|
|
64613
64613
|
});
|
|
64614
64614
|
|
|
64615
|
+
// src/commands/update/stub.ts
|
|
64616
|
+
function stubMessage(action, issue5) {
|
|
64617
|
+
return `rafa update ${action} is a feature in development, tracked in ${ISSUES_URL}/${String(issue5)}.` + " Nothing was changed.";
|
|
64618
|
+
}
|
|
64619
|
+
function createUpdateStub(spec) {
|
|
64620
|
+
const command = {
|
|
64621
|
+
name: `update ${spec.action}`,
|
|
64622
|
+
subject: "update",
|
|
64623
|
+
action: spec.action,
|
|
64624
|
+
summary: `${spec.summary} (in development, #${String(spec.issue)})`,
|
|
64625
|
+
description: `${spec.summary}. In development: it refuses with exit code 1, naming #${String(spec.issue)},` + " and changes nothing.",
|
|
64626
|
+
args: [],
|
|
64627
|
+
flags: [],
|
|
64628
|
+
examples: [{ cmd: `rafa update ${spec.action}`, note: `Refuses, naming #${String(spec.issue)}; changes nothing.` }],
|
|
64629
|
+
outputs: ["text", "json"],
|
|
64630
|
+
needsProject: false,
|
|
64631
|
+
...spec.hidden === true ? { hidden: true } : {},
|
|
64632
|
+
run: () => Promise.reject(new CommandExit(1, stubMessage(spec.action, spec.issue)))
|
|
64633
|
+
};
|
|
64634
|
+
return Object.freeze(command);
|
|
64635
|
+
}
|
|
64636
|
+
var ISSUES_URL = "https://github.com/open-tomato/rafa/issues";
|
|
64637
|
+
var init_stub = __esm(() => {
|
|
64638
|
+
init_command();
|
|
64639
|
+
});
|
|
64640
|
+
|
|
64641
|
+
// src/commands/update/board.ts
|
|
64642
|
+
var board_default;
|
|
64643
|
+
var init_board = __esm(() => {
|
|
64644
|
+
init_stub();
|
|
64645
|
+
board_default = createUpdateStub({ action: "board", summary: "apply the board's newest setup and its migrations", issue: 717 });
|
|
64646
|
+
});
|
|
64647
|
+
|
|
64648
|
+
// src/project/lock.ts
|
|
64649
|
+
import { existsSync as existsSync63, lstatSync as lstatSync3, readFileSync as readFileSync79, writeFileSync as writeFileSync31 } from "fs";
|
|
64650
|
+
import { join as join98 } from "path";
|
|
64651
|
+
function lockPath(root) {
|
|
64652
|
+
return join98(root, LOCK_FILE);
|
|
64653
|
+
}
|
|
64654
|
+
function projectLockText(version2) {
|
|
64655
|
+
const lock = { lockfileVersion: LOCKFILE_VERSION, rafa: version2 };
|
|
64656
|
+
return `${JSON.stringify(lock, null, 2)}
|
|
64657
|
+
`;
|
|
64658
|
+
}
|
|
64659
|
+
function isLink(path9) {
|
|
64660
|
+
try {
|
|
64661
|
+
return lstatSync3(path9).isSymbolicLink();
|
|
64662
|
+
} catch {
|
|
64663
|
+
return false;
|
|
64664
|
+
}
|
|
64665
|
+
}
|
|
64666
|
+
function refuse16(problem2) {
|
|
64667
|
+
throw new ProjectLockError(`${LOCK_FILE} ${problem2}`);
|
|
64668
|
+
}
|
|
64669
|
+
function lockOf(value) {
|
|
64670
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
64671
|
+
refuse16("holds no JSON object");
|
|
64672
|
+
const record = value;
|
|
64673
|
+
const format = record["lockfileVersion"];
|
|
64674
|
+
if (format !== LOCKFILE_VERSION) {
|
|
64675
|
+
refuse16(`is in lockfileVersion ${String(format)}, and this rafa reads ${String(LOCKFILE_VERSION)}: a newer rafa wrote it`);
|
|
64676
|
+
}
|
|
64677
|
+
const rafa = record["rafa"];
|
|
64678
|
+
if (typeof rafa !== "string" || parseSemanticVersion(rafa) === null) {
|
|
64679
|
+
refuse16(`names rafa ${JSON.stringify(rafa)}, which is no version`);
|
|
64680
|
+
}
|
|
64681
|
+
return { lockfileVersion: LOCKFILE_VERSION, rafa };
|
|
64682
|
+
}
|
|
64683
|
+
function readProjectLock(root) {
|
|
64684
|
+
const path9 = lockPath(root);
|
|
64685
|
+
if (!existsSync63(path9)) {
|
|
64686
|
+
if (isLink(path9))
|
|
64687
|
+
refuse16("is a link to nothing");
|
|
64688
|
+
return null;
|
|
64689
|
+
}
|
|
64690
|
+
let text2;
|
|
64691
|
+
try {
|
|
64692
|
+
text2 = readFileSync79(path9, "utf8");
|
|
64693
|
+
} catch (error) {
|
|
64694
|
+
refuse16(`could not be read: ${messageOf(error)}`);
|
|
64695
|
+
}
|
|
64696
|
+
let value;
|
|
64697
|
+
try {
|
|
64698
|
+
value = JSON.parse(text2);
|
|
64699
|
+
} catch {
|
|
64700
|
+
refuse16("is not JSON");
|
|
64701
|
+
}
|
|
64702
|
+
return lockOf(value);
|
|
64703
|
+
}
|
|
64704
|
+
function writeProjectLock(root, version2) {
|
|
64705
|
+
writeFileSync31(lockPath(root), projectLockText(version2), "utf8");
|
|
64706
|
+
}
|
|
64707
|
+
var LOCK_FILE = "rafa.lock", LOCKFILE_VERSION = 1, ProjectLockError;
|
|
64708
|
+
var init_lock = __esm(() => {
|
|
64709
|
+
init_config_sections();
|
|
64710
|
+
init_version2();
|
|
64711
|
+
ProjectLockError = class ProjectLockError extends Error {
|
|
64712
|
+
name = "ProjectLockError";
|
|
64713
|
+
};
|
|
64714
|
+
});
|
|
64715
|
+
|
|
64716
|
+
// src/project/update-current.ts
|
|
64717
|
+
import { existsSync as existsSync64 } from "fs";
|
|
64718
|
+
import { join as join99 } from "path";
|
|
64719
|
+
function missingFolders(root) {
|
|
64720
|
+
return PROJECT_TREE.map((name2) => join99(SCOPE_DIR, name2)).filter((relative21) => !existsSync64(join99(root, relative21)));
|
|
64721
|
+
}
|
|
64722
|
+
async function readBoard3(access) {
|
|
64723
|
+
if (access.gh === null)
|
|
64724
|
+
return { kind: "skipped", reason: access.reason };
|
|
64725
|
+
try {
|
|
64726
|
+
const held = await listBoardLabels(access.gh);
|
|
64727
|
+
return { kind: "labels", missing: missingBoardLabels(held).map((label) => label.name) };
|
|
64728
|
+
} catch (error) {
|
|
64729
|
+
return { kind: "skipped", reason: messageOf(error) };
|
|
64730
|
+
}
|
|
64731
|
+
}
|
|
64732
|
+
function lockChangeOf(range) {
|
|
64733
|
+
if (range.kind === "adopt")
|
|
64734
|
+
return "created";
|
|
64735
|
+
return range.kind === "patch" ? "updated" : "unchanged";
|
|
64736
|
+
}
|
|
64737
|
+
function fromOf(range) {
|
|
64738
|
+
if (range.kind === "patch")
|
|
64739
|
+
return range.from;
|
|
64740
|
+
if (range.kind === "same")
|
|
64741
|
+
return range.to;
|
|
64742
|
+
return null;
|
|
64743
|
+
}
|
|
64744
|
+
async function readUpdatePlan(roots, range, board) {
|
|
64745
|
+
const { root, lockRoot } = roots;
|
|
64746
|
+
return {
|
|
64747
|
+
root,
|
|
64748
|
+
lockRoot,
|
|
64749
|
+
from: fromOf(range),
|
|
64750
|
+
to: range.to,
|
|
64751
|
+
folders: missingFolders(root),
|
|
64752
|
+
board: await readBoard3(board),
|
|
64753
|
+
deprecations: DEPRECATIONS,
|
|
64754
|
+
lock: lockChangeOf(range)
|
|
64755
|
+
};
|
|
64756
|
+
}
|
|
64757
|
+
function planChanges(plan2) {
|
|
64758
|
+
const labels = plan2.board.kind === "labels" ? plan2.board.missing.length : 0;
|
|
64759
|
+
return plan2.folders.length > 0 || labels > 0 || plan2.deprecations.length > 0 || plan2.lock !== "unchanged";
|
|
64760
|
+
}
|
|
64761
|
+
function foldersNowThere(plan2) {
|
|
64762
|
+
return plan2.folders.filter((relative21) => existsSync64(join99(plan2.root, relative21)));
|
|
64763
|
+
}
|
|
64764
|
+
function writeFolders(plan2) {
|
|
64765
|
+
if (plan2.folders.length === 0)
|
|
64766
|
+
return [];
|
|
64767
|
+
try {
|
|
64768
|
+
return writeProjectScope(plan2.root).filter((write) => write.change === "created").map((write) => write.path);
|
|
64769
|
+
} catch (error) {
|
|
64770
|
+
throw new UpdateStepError("folders", messageOf(error), foldersNowThere(plan2));
|
|
64771
|
+
}
|
|
64772
|
+
}
|
|
64773
|
+
function createdLabels(parts) {
|
|
64774
|
+
return parts.filter((part) => part.outcome === "created").map((part) => `label ${part.name}`);
|
|
64775
|
+
}
|
|
64776
|
+
async function applyUpdatePlan(plan2, gh) {
|
|
64777
|
+
const folders = writeFolders(plan2);
|
|
64778
|
+
const labels = gh !== null && plan2.board.kind === "labels" && plan2.board.missing.length > 0 ? await setUpLabels(gh) : [];
|
|
64779
|
+
if (plan2.lock !== "unchanged") {
|
|
64780
|
+
try {
|
|
64781
|
+
writeProjectLock(plan2.lockRoot, plan2.to);
|
|
64782
|
+
} catch (error) {
|
|
64783
|
+
throw new UpdateStepError("lock", messageOf(error), [...folders, ...createdLabels(labels)]);
|
|
64784
|
+
}
|
|
64785
|
+
}
|
|
64786
|
+
return { folders, labels, lock: plan2.lock };
|
|
64787
|
+
}
|
|
64788
|
+
var DEPRECATIONS, UpdateStepError;
|
|
64789
|
+
var init_update_current = __esm(() => {
|
|
64790
|
+
init_setup();
|
|
64791
|
+
init_config_sections();
|
|
64792
|
+
init_lock();
|
|
64793
|
+
init_scaffold();
|
|
64794
|
+
init_scope();
|
|
64795
|
+
DEPRECATIONS = Object.freeze([]);
|
|
64796
|
+
UpdateStepError = class UpdateStepError extends Error {
|
|
64797
|
+
step;
|
|
64798
|
+
written;
|
|
64799
|
+
name = "UpdateStepError";
|
|
64800
|
+
constructor(step2, message, written3) {
|
|
64801
|
+
super(message);
|
|
64802
|
+
this.step = step2;
|
|
64803
|
+
this.written = written3;
|
|
64804
|
+
}
|
|
64805
|
+
};
|
|
64806
|
+
});
|
|
64807
|
+
|
|
64808
|
+
// src/project/update-range.ts
|
|
64809
|
+
function refused6(reason, message) {
|
|
64810
|
+
return { kind: "refused", reason, message };
|
|
64811
|
+
}
|
|
64812
|
+
function readCurrentRange(recorded, installed) {
|
|
64813
|
+
const to = parseSemanticVersion(installed);
|
|
64814
|
+
if (to === null)
|
|
64815
|
+
return refused6("unreadable", `the installed rafa answers "${installed}", which is no version`);
|
|
64816
|
+
if (recorded === null)
|
|
64817
|
+
return { kind: "adopt", to: installed };
|
|
64818
|
+
const from = parseSemanticVersion(recorded);
|
|
64819
|
+
if (from === null)
|
|
64820
|
+
return refused6("unreadable", `the project records rafa "${recorded}", which is no version`);
|
|
64821
|
+
const order = compareVersions(to, from);
|
|
64822
|
+
if (order < 0) {
|
|
64823
|
+
return refused6("older", `the installed rafa ${installed} is older than the project's ${recorded}, and no downgrade runs before 1.0.0`);
|
|
64824
|
+
}
|
|
64825
|
+
if (to.major !== from.major) {
|
|
64826
|
+
return refused6("newer-major", `the installed rafa ${installed} is a newer major than the project's ${recorded}; that move is rafa update latest`);
|
|
64827
|
+
}
|
|
64828
|
+
if (to.minor !== from.minor) {
|
|
64829
|
+
return refused6("newer-minor", `the installed rafa ${installed} is a newer minor than the project's ${recorded}; that move is rafa update next`);
|
|
64830
|
+
}
|
|
64831
|
+
return order === 0 ? { kind: "same", to: installed } : { kind: "patch", from: recorded, to: installed };
|
|
64832
|
+
}
|
|
64833
|
+
var init_update_range = __esm(() => {
|
|
64834
|
+
init_status();
|
|
64835
|
+
init_version2();
|
|
64836
|
+
});
|
|
64837
|
+
|
|
64838
|
+
// src/commands/update/current.ts
|
|
64839
|
+
function checkoutLockRoot(root, dir) {
|
|
64840
|
+
const run = Bun.spawnSync(["git", "rev-parse", "--show-toplevel"], { cwd: dir, stdout: "pipe", stderr: "pipe" });
|
|
64841
|
+
if (run.exitCode !== 0)
|
|
64842
|
+
return root;
|
|
64843
|
+
const top = run.stdout.toString().trim();
|
|
64844
|
+
return top !== "" && mainCheckoutOf(top) === root ? top : root;
|
|
64845
|
+
}
|
|
64846
|
+
function readSwitch4(context, name2) {
|
|
64847
|
+
const value = context.flags[name2];
|
|
64848
|
+
if (value === undefined || value === false || value === "false")
|
|
64849
|
+
return false;
|
|
64850
|
+
if (value === true || value === "true")
|
|
64851
|
+
return true;
|
|
64852
|
+
throw new CommandExit(1, `\u274C --${name2} takes no value, and read "${String(value)}" as one
|
|
64853
|
+
Usage: ${USAGE47}`);
|
|
64854
|
+
}
|
|
64855
|
+
function couldNotRun(problem2) {
|
|
64856
|
+
return new CommandExit(2, `FAIL \u2014 ${problem2}
|
|
64857
|
+
nothing was changed.`);
|
|
64858
|
+
}
|
|
64859
|
+
function projectOf17(context) {
|
|
64860
|
+
if (context.project === null)
|
|
64861
|
+
throw new Error("rafa update current runs inside a project, and was handed none");
|
|
64862
|
+
return context.project;
|
|
64863
|
+
}
|
|
64864
|
+
function boardAccess(project, seams) {
|
|
64865
|
+
let configured;
|
|
64866
|
+
try {
|
|
64867
|
+
configured = loadConfig({ root: project.root, home: project.home }, {}, () => {}).config.prProvider;
|
|
64868
|
+
} catch (error) {
|
|
64869
|
+
throw couldNotRun(`config: ${messageOf(error)}`);
|
|
64870
|
+
}
|
|
64871
|
+
const provider = resolvePrProvider({ configured, dir: project.root, readRemote: seams.readRemote }).provider;
|
|
64872
|
+
return provider === "gh" ? { gh: seams.openGh(project.root), reason: "" } : { gh: null, reason: `pr.provider is ${provider}, so there is no GitHub board` };
|
|
64873
|
+
}
|
|
64874
|
+
function foldersText(plan2) {
|
|
64875
|
+
if (plan2.folders.length === 0)
|
|
64876
|
+
return "nothing missing";
|
|
64877
|
+
return `create ${plan2.folders.join(", ")}`;
|
|
64878
|
+
}
|
|
64879
|
+
function boardText2(plan2) {
|
|
64880
|
+
if (plan2.board.kind === "skipped")
|
|
64881
|
+
return `skipped: ${plan2.board.reason}`;
|
|
64882
|
+
if (plan2.board.missing.length === 0)
|
|
64883
|
+
return "every label present";
|
|
64884
|
+
return `create labels ${plan2.board.missing.join(", ")}`;
|
|
64885
|
+
}
|
|
64886
|
+
function deprecationsText(plan2) {
|
|
64887
|
+
if (plan2.deprecations.length === 0)
|
|
64888
|
+
return "none registered yet (#718)";
|
|
64889
|
+
return `${String(plan2.deprecations.length)} to run`;
|
|
64890
|
+
}
|
|
64891
|
+
function lockText(plan2) {
|
|
64892
|
+
const where = plan2.lockRoot === plan2.root ? "" : ` in ${plan2.lockRoot}`;
|
|
64893
|
+
if (plan2.lock === "unchanged")
|
|
64894
|
+
return `unchanged at ${plan2.to}${where}`;
|
|
64895
|
+
if (plan2.lock === "created")
|
|
64896
|
+
return `create at ${plan2.to}${where}`;
|
|
64897
|
+
return `update ${String(plan2.from)} \u2192 ${plan2.to}${where}`;
|
|
64898
|
+
}
|
|
64899
|
+
function planLines2(plan2) {
|
|
64900
|
+
const from = plan2.from ?? `no ${LOCK_FILE}`;
|
|
64901
|
+
return [
|
|
64902
|
+
`rafa update current: ${plan2.root}, from ${from} to ${plan2.to}`,
|
|
64903
|
+
` folders ${foldersText(plan2)}`,
|
|
64904
|
+
` board ${boardText2(plan2)}`,
|
|
64905
|
+
` deprecations ${deprecationsText(plan2)}`,
|
|
64906
|
+
` ${LOCK_FILE} ${lockText(plan2)}`
|
|
64907
|
+
];
|
|
64908
|
+
}
|
|
64909
|
+
function appliedLines(applied, plan2, context) {
|
|
64910
|
+
for (const path9 of applied.folders)
|
|
64911
|
+
context.output.info(`created ${path9}`);
|
|
64912
|
+
for (const part of applied.labels) {
|
|
64913
|
+
if (part.outcome === "created")
|
|
64914
|
+
context.output.info(`created label ${part.name}`);
|
|
64915
|
+
if (part.outcome === "refused")
|
|
64916
|
+
context.output.warn(`label ${part.name} was not created: ${part.detail}`);
|
|
64917
|
+
}
|
|
64918
|
+
if (applied.lock !== "unchanged")
|
|
64919
|
+
context.output.info(`wrote ${LOCK_FILE} at ${plan2.to}`);
|
|
64920
|
+
}
|
|
64921
|
+
async function confirmed3(yes, seams) {
|
|
64922
|
+
if (yes)
|
|
64923
|
+
return true;
|
|
64924
|
+
if (!seams.isTerminal()) {
|
|
64925
|
+
throw new CommandExit(1, "REFUSED \u2014 rafa update current asks before it changes anything, and there is no" + " terminal to ask on. Run it with --dry-run to see the changes, then with --yes to apply them." + `
|
|
64926
|
+
nothing was changed.`);
|
|
64927
|
+
}
|
|
64928
|
+
const prompter = seams.openPrompter();
|
|
64929
|
+
try {
|
|
64930
|
+
const answer5 = await prompter.ask(APPLY_QUESTION);
|
|
64931
|
+
return answer5 !== null && YES_ANSWERS7.includes(answer5.trim().toLowerCase());
|
|
64932
|
+
} finally {
|
|
64933
|
+
prompter.close();
|
|
64934
|
+
}
|
|
64935
|
+
}
|
|
64936
|
+
function readRange2(root, installed) {
|
|
64937
|
+
let recorded;
|
|
64938
|
+
try {
|
|
64939
|
+
recorded = readProjectLock(root)?.rafa ?? null;
|
|
64940
|
+
} catch (error) {
|
|
64941
|
+
throw couldNotRun(messageOf(error));
|
|
64942
|
+
}
|
|
64943
|
+
const range = readCurrentRange(recorded, installed);
|
|
64944
|
+
if (range.kind === "refused")
|
|
64945
|
+
throw new CommandExit(1, `REFUSED \u2014 ${range.message}
|
|
64946
|
+
nothing was changed.`);
|
|
64947
|
+
return range;
|
|
64948
|
+
}
|
|
64949
|
+
function refuseConflicts(project) {
|
|
64950
|
+
const conflicts2 = scaffoldConflicts(project.root, project.home);
|
|
64951
|
+
if (conflicts2.length === 0)
|
|
64952
|
+
return;
|
|
64953
|
+
throw couldNotRun(`the project scope cannot be written:
|
|
64954
|
+
${conflicts2.map((conflict) => ` ${conflict}`).join(`
|
|
64955
|
+
`)}`);
|
|
64956
|
+
}
|
|
64957
|
+
function stoppedPartWay(error) {
|
|
64958
|
+
const kept = error.written.length === 0 ? "Nothing was written before it." : `Already written, and kept: ${error.written.join(", ")}.`;
|
|
64959
|
+
return new CommandExit(2, `FAIL \u2014 ${error.step}: ${error.message}
|
|
64960
|
+
stopped part-way. ${kept}` + `
|
|
64961
|
+
Fix the cause and run rafa update current again: each step writes only what is missing.`);
|
|
64962
|
+
}
|
|
64963
|
+
async function applyAndReport(plan2, gh, context) {
|
|
64964
|
+
let applied;
|
|
64965
|
+
try {
|
|
64966
|
+
applied = await applyUpdatePlan(plan2, gh);
|
|
64967
|
+
} catch (error) {
|
|
64968
|
+
if (error instanceof UpdateStepError)
|
|
64969
|
+
throw stoppedPartWay(error);
|
|
64970
|
+
throw error;
|
|
64971
|
+
}
|
|
64972
|
+
appliedLines(applied, plan2, context);
|
|
64973
|
+
return applied;
|
|
64974
|
+
}
|
|
64975
|
+
function refusedLabels(applied) {
|
|
64976
|
+
const refused7 = applied.labels.filter((part) => part.outcome === "refused");
|
|
64977
|
+
if (refused7.length === 0)
|
|
64978
|
+
return null;
|
|
64979
|
+
return new CommandExit(1, `${String(refused7.length)} board label(s) were not created; everything else was applied.` + " Run rafa update current again once gh can create them.");
|
|
64980
|
+
}
|
|
64981
|
+
function stopLine2(plan2, dryRun) {
|
|
64982
|
+
if (!planChanges(plan2))
|
|
64983
|
+
return "Nothing to change.";
|
|
64984
|
+
if (dryRun)
|
|
64985
|
+
return "Dry run: nothing was written. Run rafa update current to apply it.";
|
|
64986
|
+
return null;
|
|
64987
|
+
}
|
|
64988
|
+
async function runUpdateCurrent(context, seams) {
|
|
64989
|
+
expectNoArgument(context.args, USAGE47);
|
|
64990
|
+
const dryRun = readSwitch4(context, "dry-run");
|
|
64991
|
+
const yes = readSwitch4(context, "yes");
|
|
64992
|
+
const project = projectOf17(context);
|
|
64993
|
+
const lockRoot = seams.lockRootOf(project.root);
|
|
64994
|
+
const range = readRange2(lockRoot, seams.installed);
|
|
64995
|
+
refuseConflicts(project);
|
|
64996
|
+
const access = boardAccess(project, seams);
|
|
64997
|
+
const plan2 = await readUpdatePlan({ root: project.root, lockRoot }, range, access);
|
|
64998
|
+
for (const line of planLines2(plan2))
|
|
64999
|
+
context.output.info(line);
|
|
65000
|
+
const finish2 = (applied2) => {
|
|
65001
|
+
if (context.outputMode === "json")
|
|
65002
|
+
context.output.result({ plan: plan2, applied: applied2 });
|
|
65003
|
+
};
|
|
65004
|
+
const stop = stopLine2(plan2, dryRun);
|
|
65005
|
+
if (stop !== null) {
|
|
65006
|
+
context.output.info(stop);
|
|
65007
|
+
finish2(null);
|
|
65008
|
+
return;
|
|
65009
|
+
}
|
|
65010
|
+
context.output.warn("rafa cannot roll these changes back. Run it with --dry-run first to only see them.");
|
|
65011
|
+
if (!await confirmed3(yes, seams)) {
|
|
65012
|
+
context.output.info("Nothing was changed.");
|
|
65013
|
+
finish2(null);
|
|
65014
|
+
return;
|
|
65015
|
+
}
|
|
65016
|
+
const applied = await applyAndReport(plan2, access.gh, context);
|
|
65017
|
+
finish2(applied);
|
|
65018
|
+
const refusal16 = refusedLabels(applied);
|
|
65019
|
+
if (refusal16 !== null)
|
|
65020
|
+
throw refusal16;
|
|
65021
|
+
}
|
|
65022
|
+
function createUpdateCurrentCommand(seams = DEFAULT_UPDATE_CURRENT_SEAMS) {
|
|
65023
|
+
const command = {
|
|
65024
|
+
name: "update current",
|
|
65025
|
+
subject: "update",
|
|
65026
|
+
action: "current",
|
|
65027
|
+
summary: "bring this project to the installed rafa, within its patch range",
|
|
65028
|
+
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.` + " 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 or 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.",
|
|
65029
|
+
args: [],
|
|
65030
|
+
flags: [
|
|
65031
|
+
{ name: "dry-run", description: "Print every change and write nothing.", type: "boolean" },
|
|
65032
|
+
{ name: "yes", description: "Apply the changes without asking.", type: "boolean" }
|
|
65033
|
+
],
|
|
65034
|
+
examples: [
|
|
65035
|
+
{ cmd: "rafa update current --dry-run", note: "Lists the folders, labels and lock it would write, and writes nothing." },
|
|
65036
|
+
{ cmd: "rafa update current --yes", note: "Applies them without asking, as a script or a loop host runs it." }
|
|
65037
|
+
],
|
|
65038
|
+
outputs: ["text", "json"],
|
|
65039
|
+
run: async (context) => runUpdateCurrent(context, seams)
|
|
65040
|
+
};
|
|
65041
|
+
return Object.freeze(command);
|
|
65042
|
+
}
|
|
65043
|
+
var USAGE47 = "rafa update current [--dry-run] [--yes]", APPLY_QUESTION = "Apply these changes? [y/N] ", YES_ANSWERS7, DEFAULT_UPDATE_CURRENT_SEAMS, current_default2;
|
|
65044
|
+
var init_current2 = __esm(() => {
|
|
65045
|
+
init_github();
|
|
65046
|
+
init_command();
|
|
65047
|
+
init_confirm();
|
|
65048
|
+
init_version();
|
|
65049
|
+
init_config_load();
|
|
65050
|
+
init_config_sections();
|
|
65051
|
+
init_provider();
|
|
65052
|
+
init_lock();
|
|
65053
|
+
init_scaffold();
|
|
65054
|
+
init_update_current();
|
|
65055
|
+
init_update_range();
|
|
65056
|
+
init_worktree_root();
|
|
65057
|
+
init_project_id();
|
|
65058
|
+
init_plan_files();
|
|
65059
|
+
YES_ANSWERS7 = ["y", "yes"];
|
|
65060
|
+
DEFAULT_UPDATE_CURRENT_SEAMS = Object.freeze({
|
|
65061
|
+
installed: RAFA_VERSION,
|
|
65062
|
+
openGh: (root) => createGhRunner({ cwd: root }),
|
|
65063
|
+
readRemote: gitRemoteUrl,
|
|
65064
|
+
isTerminal: () => process.stdin.isTTY === true,
|
|
65065
|
+
openPrompter: () => createLinePrompter(process.stdin, process.stderr),
|
|
65066
|
+
lockRootOf: (root) => checkoutLockRoot(root, process.cwd())
|
|
65067
|
+
});
|
|
65068
|
+
current_default2 = createUpdateCurrentCommand();
|
|
65069
|
+
});
|
|
65070
|
+
|
|
65071
|
+
// src/commands/update/latest.ts
|
|
65072
|
+
var latest_default;
|
|
65073
|
+
var init_latest = __esm(() => {
|
|
65074
|
+
init_stub();
|
|
65075
|
+
latest_default = createUpdateStub({ action: "latest", summary: "move this project to the newest version", issue: 716 });
|
|
65076
|
+
});
|
|
65077
|
+
|
|
65078
|
+
// src/commands/update/next.ts
|
|
65079
|
+
var next_default2;
|
|
65080
|
+
var init_next2 = __esm(() => {
|
|
65081
|
+
init_stub();
|
|
65082
|
+
next_default2 = createUpdateStub({ action: "next", summary: "move this project to the newest minor of its major", issue: 716 });
|
|
65083
|
+
});
|
|
65084
|
+
|
|
65085
|
+
// src/commands/update/port.ts
|
|
65086
|
+
var port_default;
|
|
65087
|
+
var init_port = __esm(() => {
|
|
65088
|
+
init_stub();
|
|
65089
|
+
port_default = createUpdateStub({ action: "port", summary: "move this project to a version, as update project does", issue: 716, hidden: true });
|
|
65090
|
+
});
|
|
65091
|
+
|
|
65092
|
+
// src/commands/update/project.ts
|
|
65093
|
+
var project_default;
|
|
65094
|
+
var init_project = __esm(() => {
|
|
65095
|
+
init_stub();
|
|
65096
|
+
project_default = createUpdateStub({ action: "project", summary: "move this project to a version, with its migrations", issue: 716 });
|
|
65097
|
+
});
|
|
65098
|
+
|
|
65099
|
+
// src/commands/update/rafa.ts
|
|
65100
|
+
var rafa_default;
|
|
65101
|
+
var init_rafa = __esm(() => {
|
|
65102
|
+
init_stub();
|
|
65103
|
+
rafa_default = createUpdateStub({ action: "rafa", summary: "move this project to a version, as update project does", issue: 716, hidden: true });
|
|
65104
|
+
});
|
|
65105
|
+
|
|
65106
|
+
// src/commands/update/self.ts
|
|
65107
|
+
var self_default;
|
|
65108
|
+
var init_self = __esm(() => {
|
|
65109
|
+
init_stub();
|
|
65110
|
+
self_default = createUpdateStub({ action: "self", summary: "update rafa itself, from npm, a pinned version or another source", issue: 715 });
|
|
65111
|
+
});
|
|
65112
|
+
|
|
64615
65113
|
// src/usage.ts
|
|
64616
65114
|
async function usage(_args) {
|
|
64617
65115
|
const pct = await getClaudeUsagePercent();
|
|
@@ -64743,6 +65241,14 @@ var init_commands2 = __esm(() => {
|
|
|
64743
65241
|
init_show8();
|
|
64744
65242
|
init_status4();
|
|
64745
65243
|
init_switch();
|
|
65244
|
+
init_board();
|
|
65245
|
+
init_current2();
|
|
65246
|
+
init_latest();
|
|
65247
|
+
init_next2();
|
|
65248
|
+
init_port();
|
|
65249
|
+
init_project();
|
|
65250
|
+
init_rafa();
|
|
65251
|
+
init_self();
|
|
64746
65252
|
init_usage2();
|
|
64747
65253
|
CORE_SUBJECTS = Object.freeze([
|
|
64748
65254
|
{ name: "plan", summary: "create plans from specs; list, show and validate them; read their risk and needs" },
|
|
@@ -64757,7 +65263,8 @@ var init_commands2 = __esm(() => {
|
|
|
64757
65263
|
{ name: "release", summary: "read the release state of the project; settle the waiting fragments into a version; tag the commit that set it" },
|
|
64758
65264
|
{ name: "board", summary: "list the boards with their owner, epic count, and which is current and home" },
|
|
64759
65265
|
{ name: "epic", summary: "show one epic's issues as the Roadmap table; create an epic; defer or promote it; move an issue to it; close it through the gate or cancel it" },
|
|
64760
|
-
{ name: "claim", summary: "give up this device's claim on an issue; hand it to another store or withdraw the offer; accept a handover; take over a stale claim" }
|
|
65266
|
+
{ name: "claim", summary: "give up this device's claim on an issue; hand it to another store or withdraw the offer; accept a handover; take over a stale claim" },
|
|
65267
|
+
{ name: "update", summary: "bring this project to the installed rafa; the other updates are in development" }
|
|
64761
65268
|
]);
|
|
64762
65269
|
CORE_COMMANDS = Object.freeze([
|
|
64763
65270
|
create_default2,
|
|
@@ -64829,6 +65336,14 @@ var init_commands2 = __esm(() => {
|
|
|
64829
65336
|
hand_default,
|
|
64830
65337
|
accept_default,
|
|
64831
65338
|
take_default,
|
|
65339
|
+
current_default2,
|
|
65340
|
+
self_default,
|
|
65341
|
+
project_default,
|
|
65342
|
+
rafa_default,
|
|
65343
|
+
port_default,
|
|
65344
|
+
board_default,
|
|
65345
|
+
next_default2,
|
|
65346
|
+
latest_default,
|
|
64832
65347
|
status_default3,
|
|
64833
65348
|
next_default,
|
|
64834
65349
|
roadmap_default,
|
|
@@ -65459,12 +65974,12 @@ init_config_sections();
|
|
|
65459
65974
|
init_sessions();
|
|
65460
65975
|
init_scope();
|
|
65461
65976
|
init_sections2();
|
|
65462
|
-
import { mkdirSync as mkdirSync30, readFileSync as
|
|
65463
|
-
import { dirname as dirname39, join as
|
|
65977
|
+
import { mkdirSync as mkdirSync30, readFileSync as readFileSync80, renameSync as renameSync12, writeFileSync as writeFileSync32 } from "fs";
|
|
65978
|
+
import { dirname as dirname39, join as join100 } from "path";
|
|
65464
65979
|
var SEEN_FILE = "status-seen.json";
|
|
65465
65980
|
var SEEN_VERSION = 1;
|
|
65466
65981
|
function seenFilePath(root) {
|
|
65467
|
-
return
|
|
65982
|
+
return join100(scopeAt(root).dir, SEEN_FILE);
|
|
65468
65983
|
}
|
|
65469
65984
|
function readSeenSessions(root, isAlive) {
|
|
65470
65985
|
const sessions = {};
|
|
@@ -65519,7 +66034,7 @@ function asSnapshot(value) {
|
|
|
65519
66034
|
function readSeenFile(root) {
|
|
65520
66035
|
let text2;
|
|
65521
66036
|
try {
|
|
65522
|
-
text2 =
|
|
66037
|
+
text2 = readFileSync80(seenFilePath(root), "utf8");
|
|
65523
66038
|
} catch {
|
|
65524
66039
|
return null;
|
|
65525
66040
|
}
|
|
@@ -65533,7 +66048,7 @@ function writeSeenFile(root, snapshot) {
|
|
|
65533
66048
|
const file = seenFilePath(root);
|
|
65534
66049
|
mkdirSync30(dirname39(file), { recursive: true });
|
|
65535
66050
|
const temporary = `${file}.${String(process.pid)}.tmp`;
|
|
65536
|
-
|
|
66051
|
+
writeFileSync32(temporary, `${JSON.stringify(snapshot, null, 2)}
|
|
65537
66052
|
`);
|
|
65538
66053
|
renameSync12(temporary, file);
|
|
65539
66054
|
}
|
|
@@ -321,6 +321,7 @@ import {
|
|
|
321
321
|
sessionLine,
|
|
322
322
|
sessionLogDir,
|
|
323
323
|
setUpBoard,
|
|
324
|
+
setUpLabels,
|
|
324
325
|
severalRoadmapsMessage,
|
|
325
326
|
shellQuote,
|
|
326
327
|
show_default,
|
|
@@ -356,7 +357,7 @@ import {
|
|
|
356
357
|
worktreeAt,
|
|
357
358
|
writeSession,
|
|
358
359
|
writeShippedFile
|
|
359
|
-
} from "./index-
|
|
360
|
+
} from "./index-s8ff86xt.js";
|
|
360
361
|
import {
|
|
361
362
|
PROBE_TIMEOUT_MS,
|
|
362
363
|
loadPlanPrerequisites,
|
|
@@ -388,6 +389,7 @@ import {
|
|
|
388
389
|
MOVE_TO_SQLITE,
|
|
389
390
|
MergeRefusal,
|
|
390
391
|
POSITION_FILE,
|
|
392
|
+
RAFA_VERSION,
|
|
391
393
|
RebuildRefusal,
|
|
392
394
|
SCOPE_DIR,
|
|
393
395
|
SKILL_FILE,
|
|
@@ -421,6 +423,7 @@ import {
|
|
|
421
423
|
isFile,
|
|
422
424
|
issueLine,
|
|
423
425
|
loadConfig,
|
|
426
|
+
mainCheckoutOf,
|
|
424
427
|
mergeFrontmatter,
|
|
425
428
|
mergeStore,
|
|
426
429
|
migrateStore,
|
|
@@ -461,7 +464,7 @@ import {
|
|
|
461
464
|
versionLine,
|
|
462
465
|
writeFrontmatter,
|
|
463
466
|
writePositionFile
|
|
464
|
-
} from "./index-
|
|
467
|
+
} from "./index-bebv92ha.js";
|
|
465
468
|
import {
|
|
466
469
|
CONFIG_DEFAULTS,
|
|
467
470
|
CONFIG_FILE,
|
|
@@ -22078,6 +22081,445 @@ function createStatusCommand(seams = DEFAULT_STATUS_SEAMS) {
|
|
|
22078
22081
|
}
|
|
22079
22082
|
var status_default3 = createStatusCommand();
|
|
22080
22083
|
|
|
22084
|
+
// src/commands/update/stub.ts
|
|
22085
|
+
var ISSUES_URL = "https://github.com/open-tomato/rafa/issues";
|
|
22086
|
+
function stubMessage(action, issue2) {
|
|
22087
|
+
return `rafa update ${action} is a feature in development, tracked in ${ISSUES_URL}/${String(issue2)}.` + " Nothing was changed.";
|
|
22088
|
+
}
|
|
22089
|
+
function createUpdateStub(spec) {
|
|
22090
|
+
const command = {
|
|
22091
|
+
name: `update ${spec.action}`,
|
|
22092
|
+
subject: "update",
|
|
22093
|
+
action: spec.action,
|
|
22094
|
+
summary: `${spec.summary} (in development, #${String(spec.issue)})`,
|
|
22095
|
+
description: `${spec.summary}. In development: it refuses with exit code 1, naming #${String(spec.issue)},` + " and changes nothing.",
|
|
22096
|
+
args: [],
|
|
22097
|
+
flags: [],
|
|
22098
|
+
examples: [{ cmd: `rafa update ${spec.action}`, note: `Refuses, naming #${String(spec.issue)}; changes nothing.` }],
|
|
22099
|
+
outputs: ["text", "json"],
|
|
22100
|
+
needsProject: false,
|
|
22101
|
+
...spec.hidden === true ? { hidden: true } : {},
|
|
22102
|
+
run: () => Promise.reject(new CommandExit(1, stubMessage(spec.action, spec.issue)))
|
|
22103
|
+
};
|
|
22104
|
+
return Object.freeze(command);
|
|
22105
|
+
}
|
|
22106
|
+
|
|
22107
|
+
// src/commands/update/board.ts
|
|
22108
|
+
var board_default = createUpdateStub({ action: "board", summary: "apply the board's newest setup and its migrations", issue: 717 });
|
|
22109
|
+
|
|
22110
|
+
// src/project/lock.ts
|
|
22111
|
+
import { existsSync as existsSync15, lstatSync as lstatSync2, readFileSync as readFileSync28, writeFileSync as writeFileSync12 } from "fs";
|
|
22112
|
+
import { join as join40 } from "path";
|
|
22113
|
+
var LOCK_FILE = "rafa.lock";
|
|
22114
|
+
var LOCKFILE_VERSION = 1;
|
|
22115
|
+
|
|
22116
|
+
class ProjectLockError extends Error {
|
|
22117
|
+
name = "ProjectLockError";
|
|
22118
|
+
}
|
|
22119
|
+
function lockPath(root) {
|
|
22120
|
+
return join40(root, LOCK_FILE);
|
|
22121
|
+
}
|
|
22122
|
+
function projectLockText(version2) {
|
|
22123
|
+
const lock = { lockfileVersion: LOCKFILE_VERSION, rafa: version2 };
|
|
22124
|
+
return `${JSON.stringify(lock, null, 2)}
|
|
22125
|
+
`;
|
|
22126
|
+
}
|
|
22127
|
+
function isLink(path) {
|
|
22128
|
+
try {
|
|
22129
|
+
return lstatSync2(path).isSymbolicLink();
|
|
22130
|
+
} catch {
|
|
22131
|
+
return false;
|
|
22132
|
+
}
|
|
22133
|
+
}
|
|
22134
|
+
function refuse8(problem2) {
|
|
22135
|
+
throw new ProjectLockError(`${LOCK_FILE} ${problem2}`);
|
|
22136
|
+
}
|
|
22137
|
+
function lockOf(value) {
|
|
22138
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
22139
|
+
refuse8("holds no JSON object");
|
|
22140
|
+
const record = value;
|
|
22141
|
+
const format = record["lockfileVersion"];
|
|
22142
|
+
if (format !== LOCKFILE_VERSION) {
|
|
22143
|
+
refuse8(`is in lockfileVersion ${String(format)}, and this rafa reads ${String(LOCKFILE_VERSION)}: a newer rafa wrote it`);
|
|
22144
|
+
}
|
|
22145
|
+
const rafa = record["rafa"];
|
|
22146
|
+
if (typeof rafa !== "string" || parseSemanticVersion(rafa) === null) {
|
|
22147
|
+
refuse8(`names rafa ${JSON.stringify(rafa)}, which is no version`);
|
|
22148
|
+
}
|
|
22149
|
+
return { lockfileVersion: LOCKFILE_VERSION, rafa };
|
|
22150
|
+
}
|
|
22151
|
+
function readProjectLock(root) {
|
|
22152
|
+
const path = lockPath(root);
|
|
22153
|
+
if (!existsSync15(path)) {
|
|
22154
|
+
if (isLink(path))
|
|
22155
|
+
refuse8("is a link to nothing");
|
|
22156
|
+
return null;
|
|
22157
|
+
}
|
|
22158
|
+
let text;
|
|
22159
|
+
try {
|
|
22160
|
+
text = readFileSync28(path, "utf8");
|
|
22161
|
+
} catch (error) {
|
|
22162
|
+
refuse8(`could not be read: ${messageOf(error)}`);
|
|
22163
|
+
}
|
|
22164
|
+
let value;
|
|
22165
|
+
try {
|
|
22166
|
+
value = JSON.parse(text);
|
|
22167
|
+
} catch {
|
|
22168
|
+
refuse8("is not JSON");
|
|
22169
|
+
}
|
|
22170
|
+
return lockOf(value);
|
|
22171
|
+
}
|
|
22172
|
+
function writeProjectLock(root, version2) {
|
|
22173
|
+
writeFileSync12(lockPath(root), projectLockText(version2), "utf8");
|
|
22174
|
+
}
|
|
22175
|
+
|
|
22176
|
+
// src/project/update-current.ts
|
|
22177
|
+
import { existsSync as existsSync16 } from "fs";
|
|
22178
|
+
import { join as join41 } from "path";
|
|
22179
|
+
var DEPRECATIONS = Object.freeze([]);
|
|
22180
|
+
function missingFolders(root) {
|
|
22181
|
+
return PROJECT_TREE.map((name) => join41(SCOPE_DIR, name)).filter((relative9) => !existsSync16(join41(root, relative9)));
|
|
22182
|
+
}
|
|
22183
|
+
async function readBoard3(access) {
|
|
22184
|
+
if (access.gh === null)
|
|
22185
|
+
return { kind: "skipped", reason: access.reason };
|
|
22186
|
+
try {
|
|
22187
|
+
const held = await listBoardLabels(access.gh);
|
|
22188
|
+
return { kind: "labels", missing: missingBoardLabels(held).map((label) => label.name) };
|
|
22189
|
+
} catch (error) {
|
|
22190
|
+
return { kind: "skipped", reason: messageOf(error) };
|
|
22191
|
+
}
|
|
22192
|
+
}
|
|
22193
|
+
function lockChangeOf(range) {
|
|
22194
|
+
if (range.kind === "adopt")
|
|
22195
|
+
return "created";
|
|
22196
|
+
return range.kind === "patch" ? "updated" : "unchanged";
|
|
22197
|
+
}
|
|
22198
|
+
function fromOf(range) {
|
|
22199
|
+
if (range.kind === "patch")
|
|
22200
|
+
return range.from;
|
|
22201
|
+
if (range.kind === "same")
|
|
22202
|
+
return range.to;
|
|
22203
|
+
return null;
|
|
22204
|
+
}
|
|
22205
|
+
async function readUpdatePlan(roots, range, board) {
|
|
22206
|
+
const { root, lockRoot } = roots;
|
|
22207
|
+
return {
|
|
22208
|
+
root,
|
|
22209
|
+
lockRoot,
|
|
22210
|
+
from: fromOf(range),
|
|
22211
|
+
to: range.to,
|
|
22212
|
+
folders: missingFolders(root),
|
|
22213
|
+
board: await readBoard3(board),
|
|
22214
|
+
deprecations: DEPRECATIONS,
|
|
22215
|
+
lock: lockChangeOf(range)
|
|
22216
|
+
};
|
|
22217
|
+
}
|
|
22218
|
+
function planChanges(plan2) {
|
|
22219
|
+
const labels = plan2.board.kind === "labels" ? plan2.board.missing.length : 0;
|
|
22220
|
+
return plan2.folders.length > 0 || labels > 0 || plan2.deprecations.length > 0 || plan2.lock !== "unchanged";
|
|
22221
|
+
}
|
|
22222
|
+
|
|
22223
|
+
class UpdateStepError extends Error {
|
|
22224
|
+
step;
|
|
22225
|
+
written;
|
|
22226
|
+
name = "UpdateStepError";
|
|
22227
|
+
constructor(step, message, written) {
|
|
22228
|
+
super(message);
|
|
22229
|
+
this.step = step;
|
|
22230
|
+
this.written = written;
|
|
22231
|
+
}
|
|
22232
|
+
}
|
|
22233
|
+
function foldersNowThere(plan2) {
|
|
22234
|
+
return plan2.folders.filter((relative9) => existsSync16(join41(plan2.root, relative9)));
|
|
22235
|
+
}
|
|
22236
|
+
function writeFolders(plan2) {
|
|
22237
|
+
if (plan2.folders.length === 0)
|
|
22238
|
+
return [];
|
|
22239
|
+
try {
|
|
22240
|
+
return writeProjectScope(plan2.root).filter((write) => write.change === "created").map((write) => write.path);
|
|
22241
|
+
} catch (error) {
|
|
22242
|
+
throw new UpdateStepError("folders", messageOf(error), foldersNowThere(plan2));
|
|
22243
|
+
}
|
|
22244
|
+
}
|
|
22245
|
+
function createdLabels(parts) {
|
|
22246
|
+
return parts.filter((part) => part.outcome === "created").map((part) => `label ${part.name}`);
|
|
22247
|
+
}
|
|
22248
|
+
async function applyUpdatePlan(plan2, gh) {
|
|
22249
|
+
const folders = writeFolders(plan2);
|
|
22250
|
+
const labels = gh !== null && plan2.board.kind === "labels" && plan2.board.missing.length > 0 ? await setUpLabels(gh) : [];
|
|
22251
|
+
if (plan2.lock !== "unchanged") {
|
|
22252
|
+
try {
|
|
22253
|
+
writeProjectLock(plan2.lockRoot, plan2.to);
|
|
22254
|
+
} catch (error) {
|
|
22255
|
+
throw new UpdateStepError("lock", messageOf(error), [...folders, ...createdLabels(labels)]);
|
|
22256
|
+
}
|
|
22257
|
+
}
|
|
22258
|
+
return { folders, labels, lock: plan2.lock };
|
|
22259
|
+
}
|
|
22260
|
+
|
|
22261
|
+
// src/project/update-range.ts
|
|
22262
|
+
function refused2(reason, message) {
|
|
22263
|
+
return { kind: "refused", reason, message };
|
|
22264
|
+
}
|
|
22265
|
+
function readCurrentRange(recorded, installed) {
|
|
22266
|
+
const to = parseSemanticVersion(installed);
|
|
22267
|
+
if (to === null)
|
|
22268
|
+
return refused2("unreadable", `the installed rafa answers "${installed}", which is no version`);
|
|
22269
|
+
if (recorded === null)
|
|
22270
|
+
return { kind: "adopt", to: installed };
|
|
22271
|
+
const from = parseSemanticVersion(recorded);
|
|
22272
|
+
if (from === null)
|
|
22273
|
+
return refused2("unreadable", `the project records rafa "${recorded}", which is no version`);
|
|
22274
|
+
const order = compareVersions(to, from);
|
|
22275
|
+
if (order < 0) {
|
|
22276
|
+
return refused2("older", `the installed rafa ${installed} is older than the project's ${recorded}, and no downgrade runs before 1.0.0`);
|
|
22277
|
+
}
|
|
22278
|
+
if (to.major !== from.major) {
|
|
22279
|
+
return refused2("newer-major", `the installed rafa ${installed} is a newer major than the project's ${recorded}; that move is rafa update latest`);
|
|
22280
|
+
}
|
|
22281
|
+
if (to.minor !== from.minor) {
|
|
22282
|
+
return refused2("newer-minor", `the installed rafa ${installed} is a newer minor than the project's ${recorded}; that move is rafa update next`);
|
|
22283
|
+
}
|
|
22284
|
+
return order === 0 ? { kind: "same", to: installed } : { kind: "patch", from: recorded, to: installed };
|
|
22285
|
+
}
|
|
22286
|
+
|
|
22287
|
+
// src/commands/update/current.ts
|
|
22288
|
+
var USAGE42 = "rafa update current [--dry-run] [--yes]";
|
|
22289
|
+
var APPLY_QUESTION = "Apply these changes? [y/N] ";
|
|
22290
|
+
var YES_ANSWERS5 = ["y", "yes"];
|
|
22291
|
+
function checkoutLockRoot(root, dir) {
|
|
22292
|
+
const run = Bun.spawnSync(["git", "rev-parse", "--show-toplevel"], { cwd: dir, stdout: "pipe", stderr: "pipe" });
|
|
22293
|
+
if (run.exitCode !== 0)
|
|
22294
|
+
return root;
|
|
22295
|
+
const top = run.stdout.toString().trim();
|
|
22296
|
+
return top !== "" && mainCheckoutOf(top) === root ? top : root;
|
|
22297
|
+
}
|
|
22298
|
+
var DEFAULT_UPDATE_CURRENT_SEAMS = Object.freeze({
|
|
22299
|
+
installed: RAFA_VERSION,
|
|
22300
|
+
openGh: (root) => createGhRunner({ cwd: root }),
|
|
22301
|
+
readRemote: gitRemoteUrl,
|
|
22302
|
+
isTerminal: () => process.stdin.isTTY === true,
|
|
22303
|
+
openPrompter: () => createLinePrompter(process.stdin, process.stderr),
|
|
22304
|
+
lockRootOf: (root) => checkoutLockRoot(root, process.cwd())
|
|
22305
|
+
});
|
|
22306
|
+
function readSwitch4(context, name) {
|
|
22307
|
+
const value = context.flags[name];
|
|
22308
|
+
if (value === undefined || value === false || value === "false")
|
|
22309
|
+
return false;
|
|
22310
|
+
if (value === true || value === "true")
|
|
22311
|
+
return true;
|
|
22312
|
+
throw new CommandExit(1, `\u274C --${name} takes no value, and read "${String(value)}" as one
|
|
22313
|
+
Usage: ${USAGE42}`);
|
|
22314
|
+
}
|
|
22315
|
+
function couldNotRun(problem2) {
|
|
22316
|
+
return new CommandExit(2, `FAIL \u2014 ${problem2}
|
|
22317
|
+
nothing was changed.`);
|
|
22318
|
+
}
|
|
22319
|
+
function projectOf15(context) {
|
|
22320
|
+
if (context.project === null)
|
|
22321
|
+
throw new Error("rafa update current runs inside a project, and was handed none");
|
|
22322
|
+
return context.project;
|
|
22323
|
+
}
|
|
22324
|
+
function boardAccess(project, seams) {
|
|
22325
|
+
let configured;
|
|
22326
|
+
try {
|
|
22327
|
+
configured = loadConfig({ root: project.root, home: project.home }, {}, () => {}).config.prProvider;
|
|
22328
|
+
} catch (error) {
|
|
22329
|
+
throw couldNotRun(`config: ${messageOf(error)}`);
|
|
22330
|
+
}
|
|
22331
|
+
const provider = resolvePrProvider({ configured, dir: project.root, readRemote: seams.readRemote }).provider;
|
|
22332
|
+
return provider === "gh" ? { gh: seams.openGh(project.root), reason: "" } : { gh: null, reason: `pr.provider is ${provider}, so there is no GitHub board` };
|
|
22333
|
+
}
|
|
22334
|
+
function foldersText(plan2) {
|
|
22335
|
+
if (plan2.folders.length === 0)
|
|
22336
|
+
return "nothing missing";
|
|
22337
|
+
return `create ${plan2.folders.join(", ")}`;
|
|
22338
|
+
}
|
|
22339
|
+
function boardText2(plan2) {
|
|
22340
|
+
if (plan2.board.kind === "skipped")
|
|
22341
|
+
return `skipped: ${plan2.board.reason}`;
|
|
22342
|
+
if (plan2.board.missing.length === 0)
|
|
22343
|
+
return "every label present";
|
|
22344
|
+
return `create labels ${plan2.board.missing.join(", ")}`;
|
|
22345
|
+
}
|
|
22346
|
+
function deprecationsText(plan2) {
|
|
22347
|
+
if (plan2.deprecations.length === 0)
|
|
22348
|
+
return "none registered yet (#718)";
|
|
22349
|
+
return `${String(plan2.deprecations.length)} to run`;
|
|
22350
|
+
}
|
|
22351
|
+
function lockText(plan2) {
|
|
22352
|
+
const where = plan2.lockRoot === plan2.root ? "" : ` in ${plan2.lockRoot}`;
|
|
22353
|
+
if (plan2.lock === "unchanged")
|
|
22354
|
+
return `unchanged at ${plan2.to}${where}`;
|
|
22355
|
+
if (plan2.lock === "created")
|
|
22356
|
+
return `create at ${plan2.to}${where}`;
|
|
22357
|
+
return `update ${String(plan2.from)} \u2192 ${plan2.to}${where}`;
|
|
22358
|
+
}
|
|
22359
|
+
function planLines2(plan2) {
|
|
22360
|
+
const from = plan2.from ?? `no ${LOCK_FILE}`;
|
|
22361
|
+
return [
|
|
22362
|
+
`rafa update current: ${plan2.root}, from ${from} to ${plan2.to}`,
|
|
22363
|
+
` folders ${foldersText(plan2)}`,
|
|
22364
|
+
` board ${boardText2(plan2)}`,
|
|
22365
|
+
` deprecations ${deprecationsText(plan2)}`,
|
|
22366
|
+
` ${LOCK_FILE} ${lockText(plan2)}`
|
|
22367
|
+
];
|
|
22368
|
+
}
|
|
22369
|
+
function appliedLines(applied, plan2, context) {
|
|
22370
|
+
for (const path of applied.folders)
|
|
22371
|
+
context.output.info(`created ${path}`);
|
|
22372
|
+
for (const part of applied.labels) {
|
|
22373
|
+
if (part.outcome === "created")
|
|
22374
|
+
context.output.info(`created label ${part.name}`);
|
|
22375
|
+
if (part.outcome === "refused")
|
|
22376
|
+
context.output.warn(`label ${part.name} was not created: ${part.detail}`);
|
|
22377
|
+
}
|
|
22378
|
+
if (applied.lock !== "unchanged")
|
|
22379
|
+
context.output.info(`wrote ${LOCK_FILE} at ${plan2.to}`);
|
|
22380
|
+
}
|
|
22381
|
+
async function confirmed2(yes, seams) {
|
|
22382
|
+
if (yes)
|
|
22383
|
+
return true;
|
|
22384
|
+
if (!seams.isTerminal()) {
|
|
22385
|
+
throw new CommandExit(1, "REFUSED \u2014 rafa update current asks before it changes anything, and there is no" + " terminal to ask on. Run it with --dry-run to see the changes, then with --yes to apply them." + `
|
|
22386
|
+
nothing was changed.`);
|
|
22387
|
+
}
|
|
22388
|
+
const prompter = seams.openPrompter();
|
|
22389
|
+
try {
|
|
22390
|
+
const answer2 = await prompter.ask(APPLY_QUESTION);
|
|
22391
|
+
return answer2 !== null && YES_ANSWERS5.includes(answer2.trim().toLowerCase());
|
|
22392
|
+
} finally {
|
|
22393
|
+
prompter.close();
|
|
22394
|
+
}
|
|
22395
|
+
}
|
|
22396
|
+
function readRange(root, installed) {
|
|
22397
|
+
let recorded;
|
|
22398
|
+
try {
|
|
22399
|
+
recorded = readProjectLock(root)?.rafa ?? null;
|
|
22400
|
+
} catch (error) {
|
|
22401
|
+
throw couldNotRun(messageOf(error));
|
|
22402
|
+
}
|
|
22403
|
+
const range = readCurrentRange(recorded, installed);
|
|
22404
|
+
if (range.kind === "refused")
|
|
22405
|
+
throw new CommandExit(1, `REFUSED \u2014 ${range.message}
|
|
22406
|
+
nothing was changed.`);
|
|
22407
|
+
return range;
|
|
22408
|
+
}
|
|
22409
|
+
function refuseConflicts(project) {
|
|
22410
|
+
const conflicts2 = scaffoldConflicts(project.root, project.home);
|
|
22411
|
+
if (conflicts2.length === 0)
|
|
22412
|
+
return;
|
|
22413
|
+
throw couldNotRun(`the project scope cannot be written:
|
|
22414
|
+
${conflicts2.map((conflict) => ` ${conflict}`).join(`
|
|
22415
|
+
`)}`);
|
|
22416
|
+
}
|
|
22417
|
+
function stoppedPartWay(error) {
|
|
22418
|
+
const kept = error.written.length === 0 ? "Nothing was written before it." : `Already written, and kept: ${error.written.join(", ")}.`;
|
|
22419
|
+
return new CommandExit(2, `FAIL \u2014 ${error.step}: ${error.message}
|
|
22420
|
+
stopped part-way. ${kept}` + `
|
|
22421
|
+
Fix the cause and run rafa update current again: each step writes only what is missing.`);
|
|
22422
|
+
}
|
|
22423
|
+
async function applyAndReport(plan2, gh, context) {
|
|
22424
|
+
let applied;
|
|
22425
|
+
try {
|
|
22426
|
+
applied = await applyUpdatePlan(plan2, gh);
|
|
22427
|
+
} catch (error) {
|
|
22428
|
+
if (error instanceof UpdateStepError)
|
|
22429
|
+
throw stoppedPartWay(error);
|
|
22430
|
+
throw error;
|
|
22431
|
+
}
|
|
22432
|
+
appliedLines(applied, plan2, context);
|
|
22433
|
+
return applied;
|
|
22434
|
+
}
|
|
22435
|
+
function refusedLabels(applied) {
|
|
22436
|
+
const refused3 = applied.labels.filter((part) => part.outcome === "refused");
|
|
22437
|
+
if (refused3.length === 0)
|
|
22438
|
+
return null;
|
|
22439
|
+
return new CommandExit(1, `${String(refused3.length)} board label(s) were not created; everything else was applied.` + " Run rafa update current again once gh can create them.");
|
|
22440
|
+
}
|
|
22441
|
+
function stopLine2(plan2, dryRun) {
|
|
22442
|
+
if (!planChanges(plan2))
|
|
22443
|
+
return "Nothing to change.";
|
|
22444
|
+
if (dryRun)
|
|
22445
|
+
return "Dry run: nothing was written. Run rafa update current to apply it.";
|
|
22446
|
+
return null;
|
|
22447
|
+
}
|
|
22448
|
+
async function runUpdateCurrent(context, seams) {
|
|
22449
|
+
expectNoArgument(context.args, USAGE42);
|
|
22450
|
+
const dryRun = readSwitch4(context, "dry-run");
|
|
22451
|
+
const yes = readSwitch4(context, "yes");
|
|
22452
|
+
const project = projectOf15(context);
|
|
22453
|
+
const lockRoot = seams.lockRootOf(project.root);
|
|
22454
|
+
const range = readRange(lockRoot, seams.installed);
|
|
22455
|
+
refuseConflicts(project);
|
|
22456
|
+
const access = boardAccess(project, seams);
|
|
22457
|
+
const plan2 = await readUpdatePlan({ root: project.root, lockRoot }, range, access);
|
|
22458
|
+
for (const line of planLines2(plan2))
|
|
22459
|
+
context.output.info(line);
|
|
22460
|
+
const finish = (applied2) => {
|
|
22461
|
+
if (context.outputMode === "json")
|
|
22462
|
+
context.output.result({ plan: plan2, applied: applied2 });
|
|
22463
|
+
};
|
|
22464
|
+
const stop = stopLine2(plan2, dryRun);
|
|
22465
|
+
if (stop !== null) {
|
|
22466
|
+
context.output.info(stop);
|
|
22467
|
+
finish(null);
|
|
22468
|
+
return;
|
|
22469
|
+
}
|
|
22470
|
+
context.output.warn("rafa cannot roll these changes back. Run it with --dry-run first to only see them.");
|
|
22471
|
+
if (!await confirmed2(yes, seams)) {
|
|
22472
|
+
context.output.info("Nothing was changed.");
|
|
22473
|
+
finish(null);
|
|
22474
|
+
return;
|
|
22475
|
+
}
|
|
22476
|
+
const applied = await applyAndReport(plan2, access.gh, context);
|
|
22477
|
+
finish(applied);
|
|
22478
|
+
const refusal13 = refusedLabels(applied);
|
|
22479
|
+
if (refusal13 !== null)
|
|
22480
|
+
throw refusal13;
|
|
22481
|
+
}
|
|
22482
|
+
function createUpdateCurrentCommand(seams = DEFAULT_UPDATE_CURRENT_SEAMS) {
|
|
22483
|
+
const command = {
|
|
22484
|
+
name: "update current",
|
|
22485
|
+
subject: "update",
|
|
22486
|
+
action: "current",
|
|
22487
|
+
summary: "bring this project to the installed rafa, within its patch range",
|
|
22488
|
+
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.` + " 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 or 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.",
|
|
22489
|
+
args: [],
|
|
22490
|
+
flags: [
|
|
22491
|
+
{ name: "dry-run", description: "Print every change and write nothing.", type: "boolean" },
|
|
22492
|
+
{ name: "yes", description: "Apply the changes without asking.", type: "boolean" }
|
|
22493
|
+
],
|
|
22494
|
+
examples: [
|
|
22495
|
+
{ cmd: "rafa update current --dry-run", note: "Lists the folders, labels and lock it would write, and writes nothing." },
|
|
22496
|
+
{ cmd: "rafa update current --yes", note: "Applies them without asking, as a script or a loop host runs it." }
|
|
22497
|
+
],
|
|
22498
|
+
outputs: ["text", "json"],
|
|
22499
|
+
run: async (context) => runUpdateCurrent(context, seams)
|
|
22500
|
+
};
|
|
22501
|
+
return Object.freeze(command);
|
|
22502
|
+
}
|
|
22503
|
+
var current_default2 = createUpdateCurrentCommand();
|
|
22504
|
+
|
|
22505
|
+
// src/commands/update/latest.ts
|
|
22506
|
+
var latest_default = createUpdateStub({ action: "latest", summary: "move this project to the newest version", issue: 716 });
|
|
22507
|
+
|
|
22508
|
+
// src/commands/update/next.ts
|
|
22509
|
+
var next_default2 = createUpdateStub({ action: "next", summary: "move this project to the newest minor of its major", issue: 716 });
|
|
22510
|
+
|
|
22511
|
+
// src/commands/update/port.ts
|
|
22512
|
+
var port_default = createUpdateStub({ action: "port", summary: "move this project to a version, as update project does", issue: 716, hidden: true });
|
|
22513
|
+
|
|
22514
|
+
// src/commands/update/project.ts
|
|
22515
|
+
var project_default = createUpdateStub({ action: "project", summary: "move this project to a version, with its migrations", issue: 716 });
|
|
22516
|
+
|
|
22517
|
+
// src/commands/update/rafa.ts
|
|
22518
|
+
var rafa_default = createUpdateStub({ action: "rafa", summary: "move this project to a version, as update project does", issue: 716, hidden: true });
|
|
22519
|
+
|
|
22520
|
+
// src/commands/update/self.ts
|
|
22521
|
+
var self_default = createUpdateStub({ action: "self", summary: "update rafa itself, from npm, a pinned version or another source", issue: 715 });
|
|
22522
|
+
|
|
22081
22523
|
// src/commands/usage.ts
|
|
22082
22524
|
var usage_default = wrapPhaseZeroCommand({
|
|
22083
22525
|
name: "usage",
|
|
@@ -22110,7 +22552,8 @@ var CORE_SUBJECTS = Object.freeze([
|
|
|
22110
22552
|
{ name: "release", summary: "read the release state of the project; settle the waiting fragments into a version; tag the commit that set it" },
|
|
22111
22553
|
{ name: "board", summary: "list the boards with their owner, epic count, and which is current and home" },
|
|
22112
22554
|
{ name: "epic", summary: "show one epic's issues as the Roadmap table; create an epic; defer or promote it; move an issue to it; close it through the gate or cancel it" },
|
|
22113
|
-
{ name: "claim", summary: "give up this device's claim on an issue; hand it to another store or withdraw the offer; accept a handover; take over a stale claim" }
|
|
22555
|
+
{ name: "claim", summary: "give up this device's claim on an issue; hand it to another store or withdraw the offer; accept a handover; take over a stale claim" },
|
|
22556
|
+
{ name: "update", summary: "bring this project to the installed rafa; the other updates are in development" }
|
|
22114
22557
|
]);
|
|
22115
22558
|
var CORE_COMMANDS = Object.freeze([
|
|
22116
22559
|
create_default2,
|
|
@@ -22182,6 +22625,14 @@ var CORE_COMMANDS = Object.freeze([
|
|
|
22182
22625
|
hand_default,
|
|
22183
22626
|
accept_default,
|
|
22184
22627
|
take_default,
|
|
22628
|
+
current_default2,
|
|
22629
|
+
self_default,
|
|
22630
|
+
project_default,
|
|
22631
|
+
rafa_default,
|
|
22632
|
+
port_default,
|
|
22633
|
+
board_default,
|
|
22634
|
+
next_default2,
|
|
22635
|
+
latest_default,
|
|
22185
22636
|
status_default3,
|
|
22186
22637
|
next_default,
|
|
22187
22638
|
roadmap_default,
|
|
@@ -127,7 +127,7 @@ import {
|
|
|
127
127
|
writeNames,
|
|
128
128
|
writePositionFile,
|
|
129
129
|
writeSqliteStore
|
|
130
|
-
} from "./index-
|
|
130
|
+
} from "./index-bebv92ha.js";
|
|
131
131
|
import {
|
|
132
132
|
CHANGE_LEVELS,
|
|
133
133
|
CONFIG_DEFAULTS,
|
|
@@ -14334,7 +14334,7 @@ function withOutlineCache(outline, root) {
|
|
|
14334
14334
|
import path2 from "path";
|
|
14335
14335
|
async function coreRoster() {
|
|
14336
14336
|
const [{ CORE_REGISTRY }, { describeRegistry }] = await Promise.all([
|
|
14337
|
-
import("./index-
|
|
14337
|
+
import("./index-nr4hdb35.js"),
|
|
14338
14338
|
import("./describe-5hqfwbjc.js")
|
|
14339
14339
|
]);
|
|
14340
14340
|
return describeRegistry(CORE_REGISTRY, version);
|
|
@@ -31282,4 +31282,4 @@ async function plan(args, repoRoot, registry = CORE_ADAPTER_REGISTRY) {
|
|
|
31282
31282
|
}
|
|
31283
31283
|
}
|
|
31284
31284
|
|
|
31285
|
-
export { SERVE_CLI_VERSION, PROVENANCE_FIELD, SKILL_FILE2 as SKILL_FILE, provenanceBlock, serveVerdict, SKILL_USE_CLI_VERSION, MANIFEST_VERSION, FEATURE_TYPES, OUTPUT_CHANNELS, RUNNING_MANIFEST_SEAMS, validateManifest, loadModules, moduleSettings, pullBeforeRead, sessionLogDir, collectSessionRow, collect, AGENT_DEFINITION_DIR, VENDOR_COMMAND, readAgentDirectory, resolveAgentRoster, missingPlanAgents, isStackList, stackPaths, stacksFromEccSkillName, DESCRIPTION_LIMIT, LISTING_LIMIT, SKILL_SIGNALS, countCharacters, toolOf, pathDirectories, checkReferences, checkFile, checkDirectory, bundledAgentsDirectory, sourceItem, byName, skillItem, readTrees, parseReportArgs, formatCount, alignRows, verdictOf, failingRows, formatRows, waitForChecks, recordPlanCi, formatTokens, formatTrendSegment, formatLoopsSegment, readTrendInputs, trendReportOf, buildReport, readSkillsReport, report, SPEC_EXTENSION, boardId, notesFileName, shellQuote, ghMissingMessage, ghUnauthenticatedMessage, ghHostOf, ghPreflightItems, parseWorkingTree, parseWorktrees, readMergeRefusal, resolvePrProvider, requireGhProvider, createGhPullRequests, ghPullRequestsIn, REMOTE, BRANCH_PREFIX2 as BRANCH_PREFIX, parseBaseStanding, hasDiverged, parseClaimMessage, claimBranchIssue, makeOwnershipCommit, fetchClaimBranches, readClaimBranch, pushOwnershipCommit, readClaimState, idleText, ROADMAP_TITLE, ROADMAP_SETTING, parseRoadmapBody, createGhRoadmapSearch, severalRoadmapsMessage, createGhOpenPullRequests, closedIssuesIn, branchClaims, scanClaimBranches, readEpicBody, SPEC_BLOCKED_LABEL, hasSpecBlockedLabel, readBlockedBy, EPIC_LABEL_PREFIX, epicSlugsOf, isNotPlanned, groupByEpicLabel, localDay, readEpics, BOARD_LISTING_LIMIT, createGhBoardListing, validate_default, RefsBlockError, fingerprintText, PREVIOUS_COPY_WARN_ABOVE, previousDir, countPreviousCopies, createGhSpecIssueReader, readRoadmapSetting, ROADMAP_LABEL, BOARD_LABELS, LABEL_LIST_LIMIT, SPEC_TEMPLATE_PATH, TEMPLATES_DIRNAME, boardChanged, listBoardLabels, missingBoardLabels, anythingAt, writeShippedFile, setUpBoard, resolveDefaultBoard, unlabelledRoadmapMessage, createGhRoadmapBody, tickSentence, appendLine, tickLine, editChecklist, noBoardListsLine, epicTickSentence, tickRoadmapAfterMerge, createGhIssueBoard, createLinePrompter, readBlockedIssues, renderBlockedIssues, resolveTracker, DEFAULT_ISSUE_SEAMS, lineRefusal, expectTwoArguments, readTextFlag, readNonBlankFlag, readRequiredFlag, readChoice, readChoiceFlag, issueProject, issueSubjectConfig, resolveIssueTracker, issueRef, issueName, urlLines, onTracker, unblock_default, unblockAfterMerge, HORIZON_LABEL_PREFIX, readEpicProblems, epicProblemMessage, isWaiting, blockerToken, addBlockerToBody, labelsLineBlockersOf, LABELS_READS, createLabelsRelations, EPIC_TYPE_LABEL, STAGE_LABELS, unlabelReleased, readRefsText, readCopyRefs, restampCopyRefs, RefVerifyError, blockerArg, createNativeRelations, selectBoardRelations, NATIVE_MODE, NATIVE_RETRY_HINT, nativeEpicLeft, nativeAlreadyMessage, nativeParentLine, readBoardRepository, configuredMoveRelations, readConfiguredRelations, blockedLineSentence, readDoctorRefs, renderDoctorRefs, readEpicDependents, REASON_FLAG, renderHorizonComment, renderParkedPullRequestComment, renderMoveComment, renderCloseComment, renderCancelComment, cancelMoveReason, renderDependentComment, renderUnblockNote, readReason, unaskedReasonMessage, blankReasonMessage, HORIZONS, horizonOf, readListedEpics, invalidateRows, runIssueList, ISSUE_LIST_FLAGS, list_default, firstNowEpic, show_default, samePlace, resolvePlace, createPlanDirNames, hasPlanFor, memoiseVerifier, LEARNED_DIRECTORY, ORIGIN_FIELD, DEMOTION_VERDICTS, WHEN_TO_USE_HEADING, bodySections, classifySkill, firstSentence, convertToInstinct, rankCandidates, readRankCandidate, NO_NEXT_STEP, readSchemaReport, gateMeaning, unknownAdditive, unknownAdditiveWarning, developmentApplied, isFirstDispatch, createStartPreflightClaim, checkDrift, driftLines, readDoctorEffortSync, renderDoctorEffortSync, effortSyncRefusal, SESSION_ID_FLAG2 as SESSION_ID_FLAG, readBoardBody, openBoards, boardOfEpic, createOwnerResolver, resolveLoopSeams, sessionIdFlag, refusal3 as refusal, isLive, planLabel, sessionLine, projectRoot2 as projectRoot, readRecords, pickSession, writeSession, readSessionChecklist, phaseNote, phasedCounts, checkboxAt, estimateEta, readSessionFinishes, formatDuration, etaLine, RELEASE_REMOTE, RELEASE_BASE_BRANCH, parseSemanticVersion, readManifestVersion, replaceManifestVersion, gitPathOf, receiptProblem, readReceiptVerdict, FRAGMENT_PLAN_ID_PATTERN, serializeFragment, allocateFragmentName, directoryPrefix, releaseCommitSubject, readSettle, buildSettle, waitingSettingsOf, readWaiting, forecastPhrase, DEFAULT_RELEASE_SEAMS, compareVersions, changelogVersions, readTags, status_default, epicEndLines, watchDryEpic, nextOwnerGate, resolveReleaseEnabled, refuseMisplacedRuntime, readBinPath, self_update_default, versionTag, INDENT4 as INDENT, cleanUpAfterMerge, reportFollowUps, RELEASE_BLOCK_OPEN, RELEASE_BLOCK_CLOSE, localPlanNotes, readGuard, guardLines, mergeGuardSettings, readMergeGuard, guardReaction, followsMerge, readSettleAfterMerge, DEFAULT_BASE_BRANCH, ghNextBoard, openNextSources, WORKTREES_SUBDIR, resolveWorktreePath, crossRepositoryRefusal, addResolveWorktree, removeResolveWorktree, pushResolved, worktreeAt, cleanupSteps, dryRunLines, runCleanupSteps, defaultCleanupSeams, readCleanup, cleanupCounts, openNextRelations, list_default2 as list_default1, readBranch2 as readBranch, readPlans, readOpenPull, readBranchPlan, readNextState, readHomeAfterLoop, commandWords, nextQuestion, NEXT_COMMAND_ACTIONS, LABELS_ONLY_ACTIONS, actionInvocation, runAction, HINT_FLAG_SPEC, actionOutput, endWithNextStep, endingWith, lazyPrompter2 as lazyPrompter, ready_default, DEFAULT_PLAN_FILE, resolvePlanPath, assessPlanRisk, renderRiskText, announceRiskTotal, resolveCreateSpec, TRIAGE_MODULE, namedSecrets, triageReport, unresolvedTracker, DISK_ROOTS_FILE_SYSTEM, gitToplevel, rootRefusal, rootCandidates, DEFAULT_CI_TIMEOUT_MIN, CI_POLL_INTERVAL_MS, DEFAULT_CI_ATTEMPTS, MECHANICAL_CONFLICT_SENTENCE, start, usage, createPlanRefsVerifier, plan };
|
|
31285
|
+
export { SERVE_CLI_VERSION, PROVENANCE_FIELD, SKILL_FILE2 as SKILL_FILE, provenanceBlock, serveVerdict, SKILL_USE_CLI_VERSION, MANIFEST_VERSION, FEATURE_TYPES, OUTPUT_CHANNELS, RUNNING_MANIFEST_SEAMS, validateManifest, loadModules, moduleSettings, pullBeforeRead, sessionLogDir, collectSessionRow, collect, AGENT_DEFINITION_DIR, VENDOR_COMMAND, readAgentDirectory, resolveAgentRoster, missingPlanAgents, isStackList, stackPaths, stacksFromEccSkillName, DESCRIPTION_LIMIT, LISTING_LIMIT, SKILL_SIGNALS, countCharacters, toolOf, pathDirectories, checkReferences, checkFile, checkDirectory, bundledAgentsDirectory, sourceItem, byName, skillItem, readTrees, parseReportArgs, formatCount, alignRows, verdictOf, failingRows, formatRows, waitForChecks, recordPlanCi, formatTokens, formatTrendSegment, formatLoopsSegment, readTrendInputs, trendReportOf, buildReport, readSkillsReport, report, SPEC_EXTENSION, boardId, notesFileName, shellQuote, ghMissingMessage, ghUnauthenticatedMessage, ghHostOf, ghPreflightItems, parseWorkingTree, parseWorktrees, readMergeRefusal, resolvePrProvider, requireGhProvider, createGhPullRequests, ghPullRequestsIn, REMOTE, BRANCH_PREFIX2 as BRANCH_PREFIX, parseBaseStanding, hasDiverged, parseClaimMessage, claimBranchIssue, makeOwnershipCommit, fetchClaimBranches, readClaimBranch, pushOwnershipCommit, readClaimState, idleText, ROADMAP_TITLE, ROADMAP_SETTING, parseRoadmapBody, createGhRoadmapSearch, severalRoadmapsMessage, createGhOpenPullRequests, closedIssuesIn, branchClaims, scanClaimBranches, readEpicBody, SPEC_BLOCKED_LABEL, hasSpecBlockedLabel, readBlockedBy, EPIC_LABEL_PREFIX, epicSlugsOf, isNotPlanned, groupByEpicLabel, localDay, readEpics, BOARD_LISTING_LIMIT, createGhBoardListing, validate_default, RefsBlockError, fingerprintText, PREVIOUS_COPY_WARN_ABOVE, previousDir, countPreviousCopies, createGhSpecIssueReader, readRoadmapSetting, ROADMAP_LABEL, BOARD_LABELS, LABEL_LIST_LIMIT, SPEC_TEMPLATE_PATH, TEMPLATES_DIRNAME, boardChanged, listBoardLabels, missingBoardLabels, setUpLabels, anythingAt, writeShippedFile, setUpBoard, resolveDefaultBoard, unlabelledRoadmapMessage, createGhRoadmapBody, tickSentence, appendLine, tickLine, editChecklist, noBoardListsLine, epicTickSentence, tickRoadmapAfterMerge, createGhIssueBoard, createLinePrompter, readBlockedIssues, renderBlockedIssues, resolveTracker, DEFAULT_ISSUE_SEAMS, lineRefusal, expectTwoArguments, readTextFlag, readNonBlankFlag, readRequiredFlag, readChoice, readChoiceFlag, issueProject, issueSubjectConfig, resolveIssueTracker, issueRef, issueName, urlLines, onTracker, unblock_default, unblockAfterMerge, HORIZON_LABEL_PREFIX, readEpicProblems, epicProblemMessage, isWaiting, blockerToken, addBlockerToBody, labelsLineBlockersOf, LABELS_READS, createLabelsRelations, EPIC_TYPE_LABEL, STAGE_LABELS, unlabelReleased, readRefsText, readCopyRefs, restampCopyRefs, RefVerifyError, blockerArg, createNativeRelations, selectBoardRelations, NATIVE_MODE, NATIVE_RETRY_HINT, nativeEpicLeft, nativeAlreadyMessage, nativeParentLine, readBoardRepository, configuredMoveRelations, readConfiguredRelations, blockedLineSentence, readDoctorRefs, renderDoctorRefs, readEpicDependents, REASON_FLAG, renderHorizonComment, renderParkedPullRequestComment, renderMoveComment, renderCloseComment, renderCancelComment, cancelMoveReason, renderDependentComment, renderUnblockNote, readReason, unaskedReasonMessage, blankReasonMessage, HORIZONS, horizonOf, readListedEpics, invalidateRows, runIssueList, ISSUE_LIST_FLAGS, list_default, firstNowEpic, show_default, samePlace, resolvePlace, createPlanDirNames, hasPlanFor, memoiseVerifier, LEARNED_DIRECTORY, ORIGIN_FIELD, DEMOTION_VERDICTS, WHEN_TO_USE_HEADING, bodySections, classifySkill, firstSentence, convertToInstinct, rankCandidates, readRankCandidate, NO_NEXT_STEP, readSchemaReport, gateMeaning, unknownAdditive, unknownAdditiveWarning, developmentApplied, isFirstDispatch, createStartPreflightClaim, checkDrift, driftLines, readDoctorEffortSync, renderDoctorEffortSync, effortSyncRefusal, SESSION_ID_FLAG2 as SESSION_ID_FLAG, readBoardBody, openBoards, boardOfEpic, createOwnerResolver, resolveLoopSeams, sessionIdFlag, refusal3 as refusal, isLive, planLabel, sessionLine, projectRoot2 as projectRoot, readRecords, pickSession, writeSession, readSessionChecklist, phaseNote, phasedCounts, checkboxAt, estimateEta, readSessionFinishes, formatDuration, etaLine, RELEASE_REMOTE, RELEASE_BASE_BRANCH, parseSemanticVersion, readManifestVersion, replaceManifestVersion, gitPathOf, receiptProblem, readReceiptVerdict, FRAGMENT_PLAN_ID_PATTERN, serializeFragment, allocateFragmentName, directoryPrefix, releaseCommitSubject, readSettle, buildSettle, waitingSettingsOf, readWaiting, forecastPhrase, DEFAULT_RELEASE_SEAMS, compareVersions, changelogVersions, readTags, status_default, epicEndLines, watchDryEpic, nextOwnerGate, resolveReleaseEnabled, refuseMisplacedRuntime, readBinPath, self_update_default, versionTag, INDENT4 as INDENT, cleanUpAfterMerge, reportFollowUps, RELEASE_BLOCK_OPEN, RELEASE_BLOCK_CLOSE, localPlanNotes, readGuard, guardLines, mergeGuardSettings, readMergeGuard, guardReaction, followsMerge, readSettleAfterMerge, DEFAULT_BASE_BRANCH, ghNextBoard, openNextSources, WORKTREES_SUBDIR, resolveWorktreePath, crossRepositoryRefusal, addResolveWorktree, removeResolveWorktree, pushResolved, worktreeAt, cleanupSteps, dryRunLines, runCleanupSteps, defaultCleanupSeams, readCleanup, cleanupCounts, openNextRelations, list_default2 as list_default1, readBranch2 as readBranch, readPlans, readOpenPull, readBranchPlan, readNextState, readHomeAfterLoop, commandWords, nextQuestion, NEXT_COMMAND_ACTIONS, LABELS_ONLY_ACTIONS, actionInvocation, runAction, HINT_FLAG_SPEC, actionOutput, endWithNextStep, endingWith, lazyPrompter2 as lazyPrompter, ready_default, DEFAULT_PLAN_FILE, resolvePlanPath, assessPlanRisk, renderRiskText, announceRiskTotal, resolveCreateSpec, TRIAGE_MODULE, namedSecrets, triageReport, unresolvedTracker, DISK_ROOTS_FILE_SYSTEM, gitToplevel, rootRefusal, rootCandidates, DEFAULT_CI_TIMEOUT_MIN, CI_POLL_INTERVAL_MS, DEFAULT_CI_ATTEMPTS, MECHANICAL_CONFLICT_SENTENCE, start, usage, createPlanRefsVerifier, plan };
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
start,
|
|
11
11
|
usage,
|
|
12
12
|
validateManifest
|
|
13
|
-
} from "./index-
|
|
13
|
+
} from "./index-s8ff86xt.js";
|
|
14
14
|
import {
|
|
15
15
|
PLAN_BLOCK_KINDS,
|
|
16
16
|
PLAN_HEADER_FIELDS,
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
scopeAt,
|
|
54
54
|
selectEffortStore,
|
|
55
55
|
selfAndAncestors
|
|
56
|
-
} from "./index-
|
|
56
|
+
} from "./index-bebv92ha.js";
|
|
57
57
|
import {
|
|
58
58
|
CONFIG_DEFAULTS,
|
|
59
59
|
CONFIG_FILE,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-tomato/rafa",
|
|
3
|
-
"version": "0.34.
|
|
3
|
+
"version": "0.34.1",
|
|
4
4
|
"description": "Alpha. Runs a plan through the ralph loop: one Claude Code session per task, one commit per task, then a pull request and a CI wait.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -57,7 +57,9 @@
|
|
|
57
57
|
"lint": "eslint .",
|
|
58
58
|
"check-types": "tsc --noEmit && bun run --filter './packages/*' check-types",
|
|
59
59
|
"gate:control-bytes": "bun scripts/control-byte-gate/control-byte-gate.ts",
|
|
60
|
-
"snapshot": "bun scripts/snapshot-runtime.ts"
|
|
60
|
+
"snapshot": "bun scripts/snapshot-runtime.ts",
|
|
61
|
+
"stretch": "bash scripts/stretch/stretch.sh",
|
|
62
|
+
"device:check": "bash scripts/device/check.sh"
|
|
61
63
|
},
|
|
62
64
|
"devDependencies": {
|
|
63
65
|
"@eslint/js": "^9.39.4",
|