@rness/cli 0.21.0 → 0.22.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 +161 -95
- package/dist/bin/rness.js +2 -2
- package/dist/{chunk-D3D2WCGW.js → chunk-OUZQGG6V.js} +464 -399
- package/dist/chunk-OUZQGG6V.js.map +1 -0
- package/dist/{chunk-4BM4FUWO.js → chunk-PW5RMU2G.js} +8 -8
- package/dist/chunk-PW5RMU2G.js.map +1 -0
- package/dist/{chunk-T5PINUCP.js → chunk-SX7D5W43.js} +131 -114
- package/dist/chunk-SX7D5W43.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/{note-RBG7OXVI.js → note-MKUG7GOT.js} +5 -5
- package/dist/{summary-UCMFESSA.js → summary-5DVUIOJM.js} +4 -4
- package/dist/summary-5DVUIOJM.js.map +1 -0
- package/package.json +1 -1
- package/scaffold/README.md +3 -3
- package/scaffold/WORKSPACE.md +2 -2
- package/scaffold/adr/0000-template.md +5 -5
- package/dist/chunk-4BM4FUWO.js.map +0 -1
- package/dist/chunk-D3D2WCGW.js.map +0 -1
- package/dist/chunk-T5PINUCP.js.map +0 -1
- package/dist/summary-UCMFESSA.js.map +0 -1
- /package/dist/{note-RBG7OXVI.js.map → note-MKUG7GOT.js.map} +0 -0
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
approvalUrl,
|
|
18
18
|
assembleContext,
|
|
19
19
|
banner,
|
|
20
|
+
boardPushCommand,
|
|
21
|
+
boardRunCommand,
|
|
20
22
|
boardUrl,
|
|
21
23
|
bold,
|
|
22
24
|
canOpenBrowser,
|
|
@@ -75,9 +77,6 @@ import {
|
|
|
75
77
|
publish,
|
|
76
78
|
pullFastForward,
|
|
77
79
|
pulseCreateCommand,
|
|
78
|
-
pulseMarkCommand,
|
|
79
|
-
pulseRunCommand,
|
|
80
|
-
pulseSyncCommand,
|
|
81
80
|
readAuth,
|
|
82
81
|
readBoards,
|
|
83
82
|
readOrNull,
|
|
@@ -103,7 +102,7 @@ import {
|
|
|
103
102
|
workspaceName,
|
|
104
103
|
writeFileAtomic,
|
|
105
104
|
writeManifest
|
|
106
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-OUZQGG6V.js";
|
|
107
106
|
|
|
108
107
|
// src/core/transport.ts
|
|
109
108
|
import { spawn } from "child_process";
|
|
@@ -184,7 +183,7 @@ async function testGithubSsh(transport, interactive, announce) {
|
|
|
184
183
|
}
|
|
185
184
|
var loggedInAs = (login) => login === void 0 || login === null ? "" : `, logged in as ${login}`;
|
|
186
185
|
function usingSentence(access, login) {
|
|
187
|
-
return access.ok ? `SSH works for github.com (as ${access.login})
|
|
186
|
+
return access.ok ? `SSH works for github.com (as ${access.login}): repositories are cloned over SSH` : `No SSH access to github.com (${access.reason}): repositories are cloned over HTTPS${loggedInAs(login)}`;
|
|
188
187
|
}
|
|
189
188
|
function isSshUrl(url, hosts) {
|
|
190
189
|
return url.startsWith(hosts.ssh);
|
|
@@ -193,7 +192,7 @@ var CHECKING_LINE = status("checking", "ssh access to github.com\u2026");
|
|
|
193
192
|
var CHECKING = [
|
|
194
193
|
"checking",
|
|
195
194
|
"ssh access to github.com\u2026",
|
|
196
|
-
"Checking SSH access to github.com
|
|
195
|
+
"Checking SSH access to github.com: ssh may ask for your passphrase"
|
|
197
196
|
];
|
|
198
197
|
function usingRest(access, login) {
|
|
199
198
|
return access.ok ? `ssh (github.com as ${access.login})` : `https (ssh to github.com unavailable: ${access.reason}${loggedInAs(login)})`;
|
|
@@ -289,7 +288,7 @@ function blockHash(body) {
|
|
|
289
288
|
function intro(scope, org, depth) {
|
|
290
289
|
if (scope === null) {
|
|
291
290
|
return [
|
|
292
|
-
`This is the root of rness workspace \`${org}\`. Full context lives in \`.rness
|
|
291
|
+
`This is the root of rness workspace \`${org}\`. Full context lives in \`.rness/\`:`,
|
|
293
292
|
"start at its `AGENTS.md`, then task-relevant `adr/`, `specs/`, `plans/`; live: `rness context`.",
|
|
294
293
|
"Every `org/<repo>/` carries its own block with the rules that apply there."
|
|
295
294
|
].join("\n");
|
|
@@ -297,7 +296,7 @@ function intro(scope, org, depth) {
|
|
|
297
296
|
const rel = `${"../".repeat(depth)}.rness/`;
|
|
298
297
|
return [
|
|
299
298
|
`This directory is scope \`${scope}\` of rness workspace \`${org}\`. Full context lives in`,
|
|
300
|
-
`\`${rel}
|
|
299
|
+
`\`${rel}\`: start at its \`AGENTS.md\`, then task-relevant \`adr/\`, \`specs/\`, \`plans/\`;`,
|
|
301
300
|
`live: \`rness context --scope ${scope}\`. If \`.rness/\` is not reachable, this is a`,
|
|
302
301
|
"standalone clone: the rules below are all you have."
|
|
303
302
|
].join("\n");
|
|
@@ -491,13 +490,13 @@ var allocateStep = (allocate, collection) => `Allocate the file: run \`${allocat
|
|
|
491
490
|
\`${collection}/NNNN-untitled.md\` with the next number, the front matter
|
|
492
491
|
and the opening sections, and prints the path. Rename it to
|
|
493
492
|
\`NNNN-<slug>.md\`, the slug a few lowercase words of the title joined by
|
|
494
|
-
hyphens, and write the title as \`# NNNN
|
|
493
|
+
hyphens, and write the title as \`# NNNN - <title>\`. Never choose the
|
|
495
494
|
number yourself.`;
|
|
496
495
|
var HOOK_LINE = (rness) => `The rness hook checks every edit under \`${rness}/\`: fix what it reports.`;
|
|
497
496
|
var LIFECYCLE = [
|
|
498
497
|
{
|
|
499
498
|
name: "adr",
|
|
500
|
-
description: "Record a decision of the rness workspace as an ADR in .rness/adr/
|
|
499
|
+
description: "Record a decision of the rness workspace as an ADR in .rness/adr/ - a choice expensive to reverse or that creates a lasting constraint - or reopen one. Use when the developer asks for an ADR, or when the conversation reaches such a decision.",
|
|
501
500
|
hint: "[create <subject> | open NNNN]",
|
|
502
501
|
tab: "adr",
|
|
503
502
|
body: (rness, allocate) => `You keep the decisions of this workspace: the ADRs in \`${rness}/adr/\`. The table
|
|
@@ -514,7 +513,7 @@ it; a bare reference is \`open\`; any other words are the subject of a
|
|
|
514
513
|
Creating:
|
|
515
514
|
|
|
516
515
|
1. If the developer did not ask for an ADR in so many words, propose one in
|
|
517
|
-
a single line
|
|
516
|
+
a single line - its title, and why the choice is hard to reverse - and
|
|
518
517
|
wait for a yes.
|
|
519
518
|
2. Read \`${rness}/CONVENTIONS.md\` and \`${rness}/adr/0000-template.md\`: they hold the
|
|
520
519
|
rules and the sections; this skill is only the procedure.
|
|
@@ -524,7 +523,7 @@ Creating:
|
|
|
524
523
|
4. ${allocateStep(allocate, "adr")}
|
|
525
524
|
5. Fill it: \`repo\` the repositories under \`org/\` it affects; the template's
|
|
526
525
|
sections, their guidance lines removed; an ADR it replaces named in
|
|
527
|
-
Context
|
|
526
|
+
Context - that one becomes \`Superseded\`, with \`superseded_by:\`, only once
|
|
528
527
|
the new ADR is \`Accepted\`. Add ${SESSION_LINE}.
|
|
529
528
|
6. ${HOOK_LINE(rness)}
|
|
530
529
|
|
|
@@ -542,7 +541,7 @@ ${COMMIT_RULE}
|
|
|
542
541
|
},
|
|
543
542
|
{
|
|
544
543
|
name: "spec",
|
|
545
|
-
description: "Write a specification of the rness workspace in .rness/specs/
|
|
544
|
+
description: "Write a specification of the rness workspace in .rness/specs/ - the outcome wanted and its scope, before any plan - or reopen one. Use when the developer asks for a spec, or when agreed work is too large to start without one.",
|
|
546
545
|
hint: "[create <subject> | open NNNN]",
|
|
547
546
|
tab: "specs",
|
|
548
547
|
body: (rness, allocate) => `You keep the specifications of this workspace, in \`${rness}/specs/\`. The table
|
|
@@ -566,7 +565,7 @@ Creating:
|
|
|
566
565
|
what is in and out of scope, the ADRs it rests on: ask what the
|
|
567
566
|
conversation does not say, one question at a time.
|
|
568
567
|
4. ${allocateStep(allocate, "specs")}
|
|
569
|
-
5. Fill it: \`repo\`, and \`adr:\` linking the decisions it rests on
|
|
568
|
+
5. Fill it: \`repo\`, and \`adr:\` linking the decisions it rests on - or the
|
|
570
569
|
rationale in the body when none does; the sections it opened with
|
|
571
570
|
(Summary, Scope, Out of scope, Alternatives considered, To verify,
|
|
572
571
|
Tests), or the most recent specification's when the team's differ. What
|
|
@@ -575,8 +574,8 @@ Creating:
|
|
|
575
574
|
question. Add ${SESSION_LINE}.
|
|
576
575
|
6. ${HOOK_LINE(rness)}
|
|
577
576
|
|
|
578
|
-
Opening: read the specification and amend what the developer asks
|
|
579
|
-
section, a scope, an open question answered
|
|
577
|
+
Opening: read the specification and amend what the developer asks - a
|
|
578
|
+
section, a scope, an open question answered - \`updated\` today, the session
|
|
580
579
|
line added. A status moves only as the developer says, or by
|
|
581
580
|
\`/rness:plan from\`.
|
|
582
581
|
|
|
@@ -591,14 +590,14 @@ ${COMMIT_RULE}
|
|
|
591
590
|
},
|
|
592
591
|
{
|
|
593
592
|
name: "plan",
|
|
594
|
-
description: "The plans of the rness workspace in .rness/plans/
|
|
593
|
+
description: "The plans of the rness workspace in .rness/plans/ - a plan from a specification (from, which approves it), from the conversation (create), reopened (open), or closed on evidence (check). Use when the developer asks for a plan, to approve a specification, or to check the work of a plan.",
|
|
595
594
|
hint: "[create <subject> | from <spec> | open NNNN | check NNNN]",
|
|
596
595
|
tab: "plans",
|
|
597
596
|
body: (rness, allocate) => `You keep the plans of this workspace, in \`${rness}/plans/\`. The table above
|
|
598
597
|
lists the existing ones, newest first. Arguments: \`$ARGUMENTS\`.
|
|
599
598
|
|
|
600
599
|
The first word is the verb, when a reference (\`0037\`, or a path) follows
|
|
601
|
-
it
|
|
600
|
+
it - \`check\` alone means the plan \`In progress\`; a bare reference is
|
|
602
601
|
\`open\`; any other words are the subject of a \`create\`:
|
|
603
602
|
|
|
604
603
|
- \`from NNNN\`: a plan from specification NNNN, which this approves.
|
|
@@ -616,7 +615,7 @@ it \u2014 \`check\` alone means the plan \`In progress\`; a bare reference is
|
|
|
616
615
|
reopen it rather than write a second.
|
|
617
616
|
2. The developer typed this command: that is their approval, and the
|
|
618
617
|
specification moves from \`Draft\` or \`Proposed\` to \`Approved\`, \`updated\`
|
|
619
|
-
today, in the same commit as the plan
|
|
618
|
+
today, in the same commit as the plan - no confirmation question. If
|
|
620
619
|
you are proposing it yourself, propose it in a single line and wait for
|
|
621
620
|
a yes first: the approval is theirs, never yours.
|
|
622
621
|
3. Read the code and the repositories the specification touches: every
|
|
@@ -624,7 +623,7 @@ it \u2014 \`check\` alone means the plan \`In progress\`; a bare reference is
|
|
|
624
623
|
4. ${allocateStep(allocate, "plans")}
|
|
625
624
|
5. Fill it: \`spec:\` linking the specification; tasks in order, as
|
|
626
625
|
checkboxes, each with the files, what changes, and the command that
|
|
627
|
-
proves it (a test, a build, a run)
|
|
626
|
+
proves it (a test, a build, a run) - the last tasks the documentation
|
|
628
627
|
the work makes inaccurate, then the release when the repository has
|
|
629
628
|
one; where the plan decides something the specification leaves open, the
|
|
630
629
|
section it opened with says so. Add ${SESSION_LINE}.
|
|
@@ -635,7 +634,7 @@ for a plan in so many words, propose one in a single line and wait for a
|
|
|
635
634
|
yes. The body says what the work is and why it needs no specification.
|
|
636
635
|
|
|
637
636
|
\`open\`: read the plan and its specification; amend what the developer
|
|
638
|
-
asks
|
|
637
|
+
asks - a task added, split or reworded, a blocker recorded - \`updated\`
|
|
639
638
|
today, the session line added; move \`Draft\` to \`Ready\` or \`Blocked\` as they
|
|
640
639
|
say. A \`Completed\` or \`Abandoned\` plan is not reopened: offer a new plan of
|
|
641
640
|
the same specification.
|
|
@@ -653,7 +652,7 @@ the same specification.
|
|
|
653
652
|
check has no cache: run twice, it proves twice.
|
|
654
653
|
5. Every task proven:
|
|
655
654
|
- the plan: \`status: Completed\`, \`updated\` today, the checkboxes of the
|
|
656
|
-
proven tasks ticked, and a section \`Verification (YYYY-MM-DD)\`
|
|
655
|
+
proven tasks ticked, and a section \`Verification (YYYY-MM-DD)\` - what
|
|
657
656
|
ran, what it showed, what could not run and why;
|
|
658
657
|
- the specification: \`Implemented\` once every plan of it is
|
|
659
658
|
\`Completed\`; \`updated\` today;
|
|
@@ -1089,7 +1088,7 @@ async function driftWarning(cwd) {
|
|
|
1089
1088
|
if (drift === null) return null;
|
|
1090
1089
|
const pm = await workspacePackageManager(rnessDir);
|
|
1091
1090
|
return warn(
|
|
1092
|
-
`${basename(root)}/.rness pins @rness/cli ${drift.pin} but ${drift.installed ?? "nothing"} is installed
|
|
1091
|
+
`${basename(root)}/.rness pins @rness/cli ${drift.pin} but ${drift.installed ?? "nothing"} is installed: run ${pm} install in .rness`
|
|
1093
1092
|
);
|
|
1094
1093
|
}
|
|
1095
1094
|
var CHILD_DEADLINE_MS = 12e4;
|
|
@@ -1522,7 +1521,7 @@ async function syncCommand(opts, deps = {}) {
|
|
|
1522
1521
|
if (!check && opts.scope === void 0) {
|
|
1523
1522
|
const boards = await migrateBoards(ws.rnessDir, manifest);
|
|
1524
1523
|
if (boards.changed) {
|
|
1525
|
-
manifest.
|
|
1524
|
+
manifest.boards = boards.boards;
|
|
1526
1525
|
await writeManifest(ws.rnessDir, manifest);
|
|
1527
1526
|
for (const [rel, text] of boards.readmes)
|
|
1528
1527
|
await writeFileAtomic(join6(ws.rnessDir, ...rel.split("/")), text);
|
|
@@ -1689,7 +1688,7 @@ async function syncCommand(opts, deps = {}) {
|
|
|
1689
1688
|
}
|
|
1690
1689
|
if (check && differences > 0)
|
|
1691
1690
|
problems.push(
|
|
1692
|
-
`${differences} block(s) out of date
|
|
1691
|
+
`${differences} block(s) out of date: run ${rnessCommand()} sync`
|
|
1693
1692
|
);
|
|
1694
1693
|
if (opts.scope === void 0) {
|
|
1695
1694
|
let stale = 0;
|
|
@@ -1705,7 +1704,7 @@ async function syncCommand(opts, deps = {}) {
|
|
|
1705
1704
|
}
|
|
1706
1705
|
if (stale > 0)
|
|
1707
1706
|
problems.push(
|
|
1708
|
-
`${stale} agent file(s) out of date
|
|
1707
|
+
`${stale} agent file(s) out of date: run ${rnessCommand()} sync`
|
|
1709
1708
|
);
|
|
1710
1709
|
if (!check)
|
|
1711
1710
|
for (const label of await leftoverTargets(ws.root, manifest))
|
|
@@ -1767,7 +1766,7 @@ async function addCommand(spec, opts, deps = {}) {
|
|
|
1767
1766
|
}
|
|
1768
1767
|
if (parsed.name === CONTEXT_REPO) {
|
|
1769
1768
|
process.stderr.write(
|
|
1770
|
-
`${CONTEXT_REPO} is the workspace context, not a member repository
|
|
1769
|
+
`${CONTEXT_REPO} is the workspace context, not a member repository: it is already cloned at ${basename2(ws.root)}/${CONTEXT_REPO}
|
|
1771
1770
|
`
|
|
1772
1771
|
);
|
|
1773
1772
|
return 2;
|
|
@@ -2414,7 +2413,7 @@ async function commitContext(input) {
|
|
|
2414
2413
|
ui.line("committed", `${shown}/.rness`);
|
|
2415
2414
|
} catch (e) {
|
|
2416
2415
|
ui.warn(
|
|
2417
|
-
`${e instanceof Error ? e.message : String(e)}
|
|
2416
|
+
`${e instanceof Error ? e.message : String(e)}: commit ${shown}/.rness yourself`
|
|
2418
2417
|
);
|
|
2419
2418
|
}
|
|
2420
2419
|
}
|
|
@@ -2527,7 +2526,7 @@ async function createBlank(input) {
|
|
|
2527
2526
|
provider: null,
|
|
2528
2527
|
org: null,
|
|
2529
2528
|
agents,
|
|
2530
|
-
|
|
2529
|
+
boards: null,
|
|
2531
2530
|
repos: {},
|
|
2532
2531
|
scopes: {}
|
|
2533
2532
|
},
|
|
@@ -3025,21 +3024,21 @@ async function createCommand(opts, deps = {}) {
|
|
|
3025
3024
|
if (joining)
|
|
3026
3025
|
ui.line(
|
|
3027
3026
|
"found",
|
|
3028
|
-
`${org}/.rness
|
|
3029
|
-
`${org} has a workspace
|
|
3027
|
+
`${org}/.rness - joining`,
|
|
3028
|
+
`${org} has a workspace - joining it`
|
|
3030
3029
|
);
|
|
3031
3030
|
else
|
|
3032
3031
|
ui.line(
|
|
3033
3032
|
"not found",
|
|
3034
|
-
`${org}/.rness (or not visible to you)
|
|
3035
|
-
`${org} has no workspace yet (or none you can see)
|
|
3033
|
+
`${org}/.rness (or not visible to you) - starting a new workspace`,
|
|
3034
|
+
`${org} has no workspace yet (or none you can see) - starting one`
|
|
3036
3035
|
);
|
|
3037
3036
|
let catalogue = {
|
|
3038
3037
|
contract: 1,
|
|
3039
3038
|
provider: chosenProvider,
|
|
3040
3039
|
org,
|
|
3041
3040
|
agents: null,
|
|
3042
|
-
|
|
3041
|
+
boards: null,
|
|
3043
3042
|
repos: {},
|
|
3044
3043
|
scopes: {}
|
|
3045
3044
|
};
|
|
@@ -3160,7 +3159,7 @@ async function createCommand(opts, deps = {}) {
|
|
|
3160
3159
|
else process.stdout.write(`
|
|
3161
3160
|
${next2.map((l) => ` ${l}`).join("\n")}
|
|
3162
3161
|
`);
|
|
3163
|
-
ui.outro(`You joined ${org}
|
|
3162
|
+
ui.outro(`You joined ${org}: your workspace is in ${shown}/`);
|
|
3164
3163
|
return failures2.length > 0 ? 1 : 0;
|
|
3165
3164
|
}
|
|
3166
3165
|
const built = await buildContext({
|
|
@@ -3462,7 +3461,7 @@ function finish(ui, cwd, rnessDir, label, target, ending) {
|
|
|
3462
3461
|
`git -C ${c.dir} add ${c.paths.join(" ")} && git -C ${c.dir} commit -m "${message3}"`
|
|
3463
3462
|
);
|
|
3464
3463
|
if (ending.commit !== "nothing")
|
|
3465
|
-
next.push("# teammates: git pull
|
|
3464
|
+
next.push("# teammates: git pull - the next rness command installs it");
|
|
3466
3465
|
if (ui.session) {
|
|
3467
3466
|
if (next.length > 0) ui.note("Next steps", next);
|
|
3468
3467
|
ui.outro(`${label} runs @rness/cli ${target}`);
|
|
@@ -3558,18 +3557,18 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal, deps =
|
|
|
3558
3557
|
if (pin.spec === target && installed === target)
|
|
3559
3558
|
ui.line(
|
|
3560
3559
|
"scaffold",
|
|
3561
|
-
`@rness/cli ${target}
|
|
3560
|
+
`@rness/cli ${target}: merging it into ${label}`,
|
|
3562
3561
|
`Merging the @rness/cli ${target} scaffold into ${label}`
|
|
3563
3562
|
);
|
|
3564
3563
|
else if (pin.spec === target)
|
|
3565
3564
|
ui.line(
|
|
3566
3565
|
"install",
|
|
3567
|
-
`@rness/cli ${target} in ${label} (${pm})
|
|
3566
|
+
`@rness/cli ${target} in ${label} (${pm}): ${installed ?? "nothing"} is installed`
|
|
3568
3567
|
);
|
|
3569
3568
|
else {
|
|
3570
3569
|
ui.line(
|
|
3571
3570
|
"upgrade",
|
|
3572
|
-
`@rness/cli ${pin.spec} \u2192 ${target} in ${label} (${pm})${downgrading ? "
|
|
3571
|
+
`@rness/cli ${pin.spec} \u2192 ${target} in ${label} (${pm})${downgrading ? ", downgrading" : ""}`
|
|
3573
3572
|
);
|
|
3574
3573
|
ui.line("notes", NOTES, `Release notes: ${NOTES}`);
|
|
3575
3574
|
}
|
|
@@ -3598,7 +3597,7 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal, deps =
|
|
|
3598
3597
|
ui.line(
|
|
3599
3598
|
"adopting",
|
|
3600
3599
|
`the @rness/cli ${target} scaffold (no scaffold commit in ${label} yet)`,
|
|
3601
|
-
`Adopting the @rness/cli ${target} scaffold
|
|
3600
|
+
`Adopting the @rness/cli ${target} scaffold: ${label} has no scaffold commit yet`
|
|
3602
3601
|
);
|
|
3603
3602
|
else
|
|
3604
3603
|
ui.line(
|
|
@@ -3686,12 +3685,12 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal, deps =
|
|
|
3686
3685
|
if (committed.kind === "committed")
|
|
3687
3686
|
ui.line(
|
|
3688
3687
|
"committed",
|
|
3689
|
-
`${label}
|
|
3688
|
+
`${label}: ${message3}`,
|
|
3690
3689
|
`Committed ${label}: ${message3}`
|
|
3691
3690
|
);
|
|
3692
3691
|
if (committed.kind === "refused") {
|
|
3693
3692
|
ui.error(
|
|
3694
|
-
`the commit of ${label} was refused; everything is staged
|
|
3693
|
+
`the commit of ${label} was refused; everything is staged: deal with what git said, then commit`
|
|
3695
3694
|
);
|
|
3696
3695
|
for (const line3 of committed.output.split("\n"))
|
|
3697
3696
|
if (line3.trim() !== "") ui.hint(line3, "stderr");
|
|
@@ -3728,9 +3727,19 @@ async function checkBoards(rnessDir, manifest) {
|
|
|
3728
3727
|
const problems = (manifest.refused ?? []).map((r) => r.reason);
|
|
3729
3728
|
const holders = /* @__PURE__ */ new Map();
|
|
3730
3729
|
const all = [];
|
|
3731
|
-
|
|
3730
|
+
const isCollection2 = async (dir) => !NEVER.has(dir) && (contractOf(dir) !== void 0 || await isDirectory(join16(rnessDir, dir)));
|
|
3731
|
+
for (const [name, entry] of Object.entries(manifest.boards ?? {})) {
|
|
3732
3732
|
if (typeof entry === "number") continue;
|
|
3733
|
-
const at = `
|
|
3733
|
+
const at = `boards.${name}`;
|
|
3734
|
+
if (typeof entry === "string") {
|
|
3735
|
+
if (name === PULSE) all.push(name);
|
|
3736
|
+
else if (!await isCollection2(name))
|
|
3737
|
+
problems.push(
|
|
3738
|
+
`"${at}" names no collection of .rness: a collection's board is named after its directory`
|
|
3739
|
+
);
|
|
3740
|
+
else holders.set(name, name);
|
|
3741
|
+
continue;
|
|
3742
|
+
}
|
|
3734
3743
|
if (entry.collections === "all") all.push(name);
|
|
3735
3744
|
else
|
|
3736
3745
|
for (const collection of Object.keys(entry.collections)) {
|
|
@@ -3751,7 +3760,7 @@ async function checkBoards(rnessDir, manifest) {
|
|
|
3751
3760
|
await readmeDeclarations(rnessDir, collection).catch(() => ({}))
|
|
3752
3761
|
))
|
|
3753
3762
|
problems.push(
|
|
3754
|
-
`${collection}/README.md: "${k}" is declared in rness.json now
|
|
3763
|
+
`${collection}/README.md: "${k}" is declared in rness.json now: rness sync moves it`
|
|
3755
3764
|
);
|
|
3756
3765
|
}
|
|
3757
3766
|
for (const key of ["readme", "updates"]) {
|
|
@@ -3768,7 +3777,7 @@ async function checkBoards(rnessDir, manifest) {
|
|
|
3768
3777
|
}
|
|
3769
3778
|
if (all.length > 1)
|
|
3770
3779
|
problems.push(
|
|
3771
|
-
`${all.map((n) => `"
|
|
3780
|
+
`${all.map((n) => `"boards.${n}"`).join(" and ")} each take every collection ("all"): a collection is on one board at most`
|
|
3772
3781
|
);
|
|
3773
3782
|
return problems;
|
|
3774
3783
|
}
|
|
@@ -3945,7 +3954,7 @@ async function docNewCommand(collection, opts) {
|
|
|
3945
3954
|
];
|
|
3946
3955
|
const sections = name === "adr" ? await adrSections(ws.rnessDir) : SECTIONS[name] ?? [];
|
|
3947
3956
|
const body = [
|
|
3948
|
-
`# ${number}
|
|
3957
|
+
`# ${number} - ${title}`,
|
|
3949
3958
|
// The rule under the title, as the ADR and specification templates draw it.
|
|
3950
3959
|
...name === "plans" ? [] : ["", "---"],
|
|
3951
3960
|
...sections.flatMap((s) => ["", `## ${s}`])
|
|
@@ -4028,7 +4037,7 @@ async function takeModNotice(env) {
|
|
|
4028
4037
|
);
|
|
4029
4038
|
} catch {
|
|
4030
4039
|
}
|
|
4031
|
-
return `rness: Claude Code ${version} shows no rness band, footer label or pane; ${MOD_FLOOR} or later does
|
|
4040
|
+
return `rness: Claude Code ${version} shows no rness band, footer label or pane; ${MOD_FLOOR} or later does: claude update`;
|
|
4032
4041
|
}
|
|
4033
4042
|
|
|
4034
4043
|
// src/core/edit-guard.ts
|
|
@@ -4136,13 +4145,13 @@ async function safetyNet(ws, manifest) {
|
|
|
4136
4145
|
const drift = await pinDrift(ws.rnessDir);
|
|
4137
4146
|
if (drift !== null)
|
|
4138
4147
|
notes.push(
|
|
4139
|
-
`.rness pins @rness/cli ${drift.pin} but ${drift.installed ?? "nothing"} is installed
|
|
4148
|
+
`.rness pins @rness/cli ${drift.pin} but ${drift.installed ?? "nothing"} is installed: run ${await workspacePackageManager(ws.rnessDir)} install in .rness`
|
|
4140
4149
|
);
|
|
4141
4150
|
try {
|
|
4142
4151
|
const { problems } = await checkWorkspace(ws, manifest);
|
|
4143
4152
|
if (problems.length > 0)
|
|
4144
4153
|
notes.push(
|
|
4145
|
-
`${count(problems.length, ["problem", "problems"])} in the workspace context
|
|
4154
|
+
`${count(problems.length, ["problem", "problems"])} in the workspace context: run rness validate`,
|
|
4146
4155
|
...problems.slice(0, SHOWN_PROBLEMS).map((p) => ` ${p}`)
|
|
4147
4156
|
);
|
|
4148
4157
|
} catch (e) {
|
|
@@ -4202,7 +4211,7 @@ async function documents(rnessDir, only) {
|
|
|
4202
4211
|
}
|
|
4203
4212
|
function line(d, withScope = false) {
|
|
4204
4213
|
const head = [d.id, d.status].filter((x) => x !== null).join(" ");
|
|
4205
|
-
return `- ${head === "" ? "" : `${head}
|
|
4214
|
+
return `- ${head === "" ? "" : `${head} - `}${d.title}${withScope ? ` \xB7 ${d.scope ?? "global"}` : ""} \xB7 ${d.path}`;
|
|
4206
4215
|
}
|
|
4207
4216
|
function isCollection(value) {
|
|
4208
4217
|
return COLLECTIONS.includes(value);
|
|
@@ -4344,7 +4353,7 @@ function mcpTools(cwd) {
|
|
|
4344
4353
|
{
|
|
4345
4354
|
name: "rness_context",
|
|
4346
4355
|
title: "rness: what applies here",
|
|
4347
|
-
description: "The rness scope of the current repository (or the one named) and what applies to it: the standards, decisions (ADRs), specifications and plans of that scope and of the scopes it extends
|
|
4356
|
+
description: "The rness scope of the current repository (or the one named) and what applies to it: the standards, decisions (ADRs), specifications and plans of that scope and of the scopes it extends: ids, statuses, titles and paths, no bodies. Start here, then read a document with rness_read.",
|
|
4348
4357
|
inputSchema: {
|
|
4349
4358
|
type: "object",
|
|
4350
4359
|
properties: {
|
|
@@ -4440,7 +4449,7 @@ function noteTool(cwd, githubApi) {
|
|
|
4440
4449
|
additionalProperties: false
|
|
4441
4450
|
},
|
|
4442
4451
|
call: (args) => guard(async () => {
|
|
4443
|
-
const { postNote } = await import("./note-
|
|
4452
|
+
const { postNote } = await import("./note-MKUG7GOT.js");
|
|
4444
4453
|
const given = (key) => {
|
|
4445
4454
|
const value = args[key];
|
|
4446
4455
|
return typeof value === "string" ? value : void 0;
|
|
@@ -4489,7 +4498,7 @@ async function scopeBanner(ws, manifest, scope) {
|
|
|
4489
4498
|
const n = summary.counts[c];
|
|
4490
4499
|
return n === void 0 ? [] : [count(n, NOUNS[c])];
|
|
4491
4500
|
});
|
|
4492
|
-
const banner2 = `rness ${VERSION} \xB7 ${workspaceName(manifest, ws.root)} \xB7 ${scope === null ? "global scope" : `scope ${scope}`} \
|
|
4501
|
+
const banner2 = `rness ${VERSION} \xB7 ${workspaceName(manifest, ws.root)} \xB7 ${scope === null ? "global scope" : `scope ${scope}`} \xB7 ${counts.length === 0 ? "nothing applies yet" : counts.join(", ")}`;
|
|
4493
4502
|
return { banner: banner2, lines: summary.lines };
|
|
4494
4503
|
}
|
|
4495
4504
|
var noteLines = (notes) => notes.map((n) => `rness: ${n}`);
|
|
@@ -4499,7 +4508,7 @@ function statusLine(scope, inProgress, notes) {
|
|
|
4499
4508
|
}
|
|
4500
4509
|
async function boardsOf(manifest, rnessDir) {
|
|
4501
4510
|
const boards = [];
|
|
4502
|
-
for (const [name, entry] of Object.entries(manifest.
|
|
4511
|
+
for (const [name, entry] of Object.entries(manifest.boards ?? {}))
|
|
4503
4512
|
try {
|
|
4504
4513
|
boards.push({
|
|
4505
4514
|
name,
|
|
@@ -4516,8 +4525,9 @@ var SHIPPED_COLORS = presetTemplate(currentPreset("agent-pulse"), {
|
|
|
4516
4525
|
collection: PULSE
|
|
4517
4526
|
})["colors"];
|
|
4518
4527
|
function pulseOf(org, boards) {
|
|
4519
|
-
const
|
|
4520
|
-
|
|
4528
|
+
const created = boards.filter((b) => b.declaration.number !== null);
|
|
4529
|
+
const main = created.find((b) => b.declaration.collections === "all") ?? created[0];
|
|
4530
|
+
return org === null || main?.declaration.number == null ? null : boardUrl(org, main.declaration.number);
|
|
4521
4531
|
}
|
|
4522
4532
|
function snapshotTabs(tabs, org, boards) {
|
|
4523
4533
|
return tabs.map((tab) => {
|
|
@@ -4529,7 +4539,7 @@ function snapshotTabs(tabs, org, boards) {
|
|
|
4529
4539
|
rows: tab.rows.map((row) => ({
|
|
4530
4540
|
...row,
|
|
4531
4541
|
color: row.status === null ? "red" : optionColor(colors, "status", row.status) ?? "gray",
|
|
4532
|
-
link: org === null || holder
|
|
4542
|
+
link: org === null || holder?.declaration.number == null ? null : itemUrl(org, holder.declaration.number, row.path)
|
|
4533
4543
|
}))
|
|
4534
4544
|
};
|
|
4535
4545
|
});
|
|
@@ -4593,7 +4603,7 @@ async function runDetached(ws, input, io, event, rest) {
|
|
|
4593
4603
|
if (boards.length === 0) return;
|
|
4594
4604
|
const args = await rest(session, boards);
|
|
4595
4605
|
if (args !== null)
|
|
4596
|
-
(io.spawn ?? detached)(["
|
|
4606
|
+
(io.spawn ?? detached)(["board", "run", event, ...args], ws.root);
|
|
4597
4607
|
} catch {
|
|
4598
4608
|
}
|
|
4599
4609
|
}
|
|
@@ -4615,7 +4625,7 @@ async function journalStart(ws, manifest, scope, cwd, input) {
|
|
|
4615
4625
|
const which = plans.length === 1 ? plans.join("") : `${plans.join(" or ")} (pass --plan)`;
|
|
4616
4626
|
return [
|
|
4617
4627
|
[
|
|
4618
|
-
`Journal: post a note with \`rness
|
|
4628
|
+
`Journal: post a note with \`rness note\` (or ${tool}) when you choose an approach, deviate from plan ${which}, are blocked, and when done.`,
|
|
4619
4629
|
`At most ${a.limit}: decisions and their reasons, not steps.`,
|
|
4620
4630
|
...a.to === "repo" ? [
|
|
4621
4631
|
"The first note prints the issue to reference; the pull request that completes this plan here carries `Closes <issue>`, an earlier one `Refs <issue>`."
|
|
@@ -4672,7 +4682,7 @@ async function sessionStart(input, io) {
|
|
|
4672
4682
|
notes = [message2(e)];
|
|
4673
4683
|
}
|
|
4674
4684
|
const failure = await takeFailure();
|
|
4675
|
-
if (failure !== null) notes.push(`
|
|
4685
|
+
if (failure !== null) notes.push(`board not updated: ${failure}`);
|
|
4676
4686
|
notes.push(...await takeNotices());
|
|
4677
4687
|
const warnings = noteLines(notes);
|
|
4678
4688
|
const compact = input["source"] === "compact";
|
|
@@ -5286,6 +5296,44 @@ async function writtenFilesCommand(opts) {
|
|
|
5286
5296
|
}
|
|
5287
5297
|
|
|
5288
5298
|
// src/cli.ts
|
|
5299
|
+
function formerly(was, now) {
|
|
5300
|
+
process.stderr.write(`${was} is now ${now}
|
|
5301
|
+
`);
|
|
5302
|
+
}
|
|
5303
|
+
function noteCommandOf(parent, state, former) {
|
|
5304
|
+
parent.command("note [text]").description(
|
|
5305
|
+
"A note on the plan in progress: an approach, a deviation, a blocker, done (the text, or stdin)"
|
|
5306
|
+
).option("--plan <path>", "the plan, when several are in progress").option("--kind <kind>", "approach, deviation, blocker or done").option(
|
|
5307
|
+
"--session <session>",
|
|
5308
|
+
"the session, when CLAUDE_CODE_SESSION_ID is not set"
|
|
5309
|
+
).addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(
|
|
5310
|
+
async (text, opts) => {
|
|
5311
|
+
if (former !== void 0) formerly(former, "rness note");
|
|
5312
|
+
const { noteCommand } = await import("./note-MKUG7GOT.js");
|
|
5313
|
+
state.code = await noteCommand({
|
|
5314
|
+
...opts,
|
|
5315
|
+
...text === void 0 ? {} : { text }
|
|
5316
|
+
});
|
|
5317
|
+
}
|
|
5318
|
+
);
|
|
5319
|
+
}
|
|
5320
|
+
function runCommand(parent, state, former) {
|
|
5321
|
+
parent.command("run <event>", { hidden: true }).requiredOption("--session <id>").option(
|
|
5322
|
+
"--path <path>",
|
|
5323
|
+
"the document edited (repeatable)",
|
|
5324
|
+
(value, previous = []) => [...previous, value]
|
|
5325
|
+
).option("--scope <scope>", "the session's scope; absent, the root's").option("--clone <name>", "the clone the session worked in").addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(
|
|
5326
|
+
async (event, opts) => {
|
|
5327
|
+
if (former !== void 0) formerly(former, "rness board run");
|
|
5328
|
+
const { path, ...rest } = opts;
|
|
5329
|
+
state.code = await boardRunCommand({
|
|
5330
|
+
...rest,
|
|
5331
|
+
event,
|
|
5332
|
+
paths: path ?? []
|
|
5333
|
+
});
|
|
5334
|
+
}
|
|
5335
|
+
);
|
|
5336
|
+
}
|
|
5289
5337
|
function buildProgram(state) {
|
|
5290
5338
|
const program = new Command().name("rness").description("Configuration-plane CLI for rness workspaces").version(VERSION, "-v, --version", "print the version").exitOverride().showHelpAfterError().configureOutput({
|
|
5291
5339
|
writeOut: (s) => {
|
|
@@ -5342,60 +5390,29 @@ function buildProgram(state) {
|
|
|
5342
5390
|
).option("-y, --yes", "do not ask for confirmation").addOption(new Option("--cwd <dir>").hideHelp()).action(async (opts) => {
|
|
5343
5391
|
state.code = await syncCommand(opts);
|
|
5344
5392
|
});
|
|
5345
|
-
const
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
).
|
|
5349
|
-
"
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
state.code = await pulseCreateCommand(
|
|
5353
|
-
collection === void 0 ? opts : { ...opts, collection }
|
|
5354
|
-
);
|
|
5393
|
+
const board = program.command("board").description(
|
|
5394
|
+
"The boards of rness.json: the documents of .rness/ on the provider"
|
|
5395
|
+
);
|
|
5396
|
+
board.command("push").description(
|
|
5397
|
+
"Create the boards rness.json declares and the provider lacks, then bring every board up to date with .rness/"
|
|
5398
|
+
).option("-y, --yes", "create the boards not created yet without asking").addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(async (opts) => {
|
|
5399
|
+
state.code = await boardPushCommand(opts);
|
|
5355
5400
|
});
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5401
|
+
runCommand(board, state);
|
|
5402
|
+
noteCommandOf(program, state);
|
|
5403
|
+
const pulse = program.command("pulse", { hidden: true });
|
|
5404
|
+
pulse.command("create").argument("[collection]").option("-y, --yes").addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(async (collection, opts) => {
|
|
5405
|
+
state.code = await pulseCreateCommand(collection, opts);
|
|
5406
|
+
});
|
|
5407
|
+
pulse.command("sync").addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(async (opts) => {
|
|
5408
|
+
formerly("rness pulse sync", "rness board push");
|
|
5409
|
+
state.code = await boardPushCommand(opts);
|
|
5410
|
+
});
|
|
5411
|
+
noteCommandOf(pulse, state, "rness pulse note");
|
|
5412
|
+
runCommand(pulse, state, "rness pulse run");
|
|
5413
|
+
pulse.command("mark").allowUnknownOption().allowExcessArguments().action(() => {
|
|
5414
|
+
state.code = 0;
|
|
5360
5415
|
});
|
|
5361
|
-
pulse.command("mark", { hidden: true }).requiredOption("--session <id>").option(
|
|
5362
|
-
"--path <path>",
|
|
5363
|
-
"a document of .rness/ (repeatable)",
|
|
5364
|
-
(value, previous = []) => [...previous, value]
|
|
5365
|
-
).option("--end", "clear the marks of the session, then sync").addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(
|
|
5366
|
-
async (opts) => {
|
|
5367
|
-
const { path, ...rest } = opts;
|
|
5368
|
-
state.code = await pulseMarkCommand({ ...rest, paths: path ?? [] });
|
|
5369
|
-
}
|
|
5370
|
-
);
|
|
5371
|
-
pulse.command("note [text]").description(
|
|
5372
|
-
"a note on the plan in progress: an approach, a deviation, a blocker, done (the text, or stdin)"
|
|
5373
|
-
).option("--plan <path>", "the plan, when several are in progress").option("--kind <kind>", "approach, deviation, blocker or done").option(
|
|
5374
|
-
"--session <session>",
|
|
5375
|
-
"the session, when CLAUDE_CODE_SESSION_ID is not set"
|
|
5376
|
-
).addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(
|
|
5377
|
-
async (text, opts) => {
|
|
5378
|
-
const { pulseNoteCommand } = await import("./note-RBG7OXVI.js");
|
|
5379
|
-
state.code = await pulseNoteCommand({
|
|
5380
|
-
...opts,
|
|
5381
|
-
...text === void 0 ? {} : { text }
|
|
5382
|
-
});
|
|
5383
|
-
}
|
|
5384
|
-
);
|
|
5385
|
-
pulse.command("run <event>", { hidden: true }).requiredOption("--session <id>").option(
|
|
5386
|
-
"--path <path>",
|
|
5387
|
-
"the document edited (repeatable)",
|
|
5388
|
-
(value, previous = []) => [...previous, value]
|
|
5389
|
-
).option("--scope <scope>", "the session's scope; absent, the root's").option("--clone <name>", "the clone the session worked in").addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(
|
|
5390
|
-
async (event, opts) => {
|
|
5391
|
-
const { path, ...rest } = opts;
|
|
5392
|
-
state.code = await pulseRunCommand({
|
|
5393
|
-
...rest,
|
|
5394
|
-
event,
|
|
5395
|
-
paths: path ?? []
|
|
5396
|
-
});
|
|
5397
|
-
}
|
|
5398
|
-
);
|
|
5399
5416
|
program.command("mcp").description(
|
|
5400
5417
|
"Serve the workspace context to agents over MCP (stdio; read-only but for rness_note, when a board keeps a journal)"
|
|
5401
5418
|
).addOption(new Option("--cwd <dir>").hideHelp()).action(async (opts) => {
|
|
@@ -5579,4 +5596,4 @@ export {
|
|
|
5579
5596
|
OWN_COMMANDS,
|
|
5580
5597
|
catchUp
|
|
5581
5598
|
};
|
|
5582
|
-
//# sourceMappingURL=chunk-
|
|
5599
|
+
//# sourceMappingURL=chunk-SX7D5W43.js.map
|