@rness/cli 0.14.0 → 0.15.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 +51 -5
- package/dist/bin/rness.js +1 -1
- package/dist/{chunk-AXTFDXN2.js → chunk-7IVHL744.js} +301 -139
- package/dist/chunk-7IVHL744.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-AXTFDXN2.js.map +0 -1
|
@@ -486,7 +486,7 @@ function parseRepoSpec(spec, org, host) {
|
|
|
486
486
|
}
|
|
487
487
|
|
|
488
488
|
// src/version.ts
|
|
489
|
-
var VERSION = "0.
|
|
489
|
+
var VERSION = "0.15.1";
|
|
490
490
|
|
|
491
491
|
// src/core/pm.ts
|
|
492
492
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -1070,15 +1070,25 @@ function statusOf(item) {
|
|
|
1070
1070
|
const status2 = item.fields?.["status"];
|
|
1071
1071
|
return typeof status2 === "string" && status2 !== "" ? status2 : null;
|
|
1072
1072
|
}
|
|
1073
|
+
function sessionsOf(item) {
|
|
1074
|
+
const listed = item.fields?.["sessions"];
|
|
1075
|
+
if (!Array.isArray(listed)) return [];
|
|
1076
|
+
const ids = listed.filter(
|
|
1077
|
+
(s) => typeof s === "string" && s !== ""
|
|
1078
|
+
);
|
|
1079
|
+
return [...new Set(ids)];
|
|
1080
|
+
}
|
|
1073
1081
|
function rowOf(dir, item) {
|
|
1074
1082
|
const base = posix3.basename(item.rel, ".md");
|
|
1075
1083
|
const date = /^(\d{4}-\d{2}-\d{2})-/.exec(base)?.[1] ?? null;
|
|
1076
1084
|
const number = date === null ? documentNumber(item.rel) : null;
|
|
1085
|
+
const sessions = sessionsOf(item);
|
|
1077
1086
|
return {
|
|
1078
1087
|
id: date ?? number ?? base,
|
|
1079
1088
|
title: documentTitle(item.title ?? base, number),
|
|
1080
1089
|
status: statusOf(item),
|
|
1081
|
-
path: `${dir}/${item.rel}
|
|
1090
|
+
path: `${dir}/${item.rel}`,
|
|
1091
|
+
...sessions.length > 0 ? { sessions } : {}
|
|
1082
1092
|
};
|
|
1083
1093
|
}
|
|
1084
1094
|
function newestFirst(a, b) {
|
|
@@ -1399,11 +1409,120 @@ function desiredOf(tabs, org) {
|
|
|
1399
1409
|
body: headerOf(row.path, org),
|
|
1400
1410
|
status: statusOf2(row.status),
|
|
1401
1411
|
type: tab.label,
|
|
1402
|
-
statusField: fields2.get(tab.label)?.name ?? null
|
|
1412
|
+
statusField: fields2.get(tab.label)?.name ?? null,
|
|
1413
|
+
sessions: row.sessions?.join(", ") ?? null
|
|
1403
1414
|
}))
|
|
1404
1415
|
);
|
|
1405
1416
|
}
|
|
1406
1417
|
|
|
1418
|
+
// src/pulse/plan.ts
|
|
1419
|
+
var differs = (item, w) => item.title !== w.title || item.status !== w.status || w.statusField !== null && item.collectionStatus !== w.status || item.type !== w.type || item.sessions !== w.sessions;
|
|
1420
|
+
var rank = (i) => i.issue === null ? 2 : i.issue.open ? 0 : 1;
|
|
1421
|
+
var keptFirst = (a, b) => rank(a) - rank(b) || (a.issue?.number ?? 0) - (b.issue?.number ?? 0);
|
|
1422
|
+
var gone = (item) => item.issue === null ? { kind: "archive", id: item.id } : { kind: "close", id: item.id };
|
|
1423
|
+
var firstLine3 = (body) => body.split(/\r\n?|\n/, 1)[0] ?? "";
|
|
1424
|
+
function strays(have) {
|
|
1425
|
+
const byLine = /* @__PURE__ */ new Map();
|
|
1426
|
+
for (const item of have) {
|
|
1427
|
+
if (item.path !== null || item.issue === null || item.issue.body === null || !item.issue.labelled)
|
|
1428
|
+
continue;
|
|
1429
|
+
const line3 = firstLine3(item.issue.body);
|
|
1430
|
+
byLine.set(line3, [...byLine.get(line3) ?? [], item]);
|
|
1431
|
+
}
|
|
1432
|
+
for (const items of byLine.values()) items.sort(keptFirst);
|
|
1433
|
+
return byLine;
|
|
1434
|
+
}
|
|
1435
|
+
function unwantedPaths(want, have) {
|
|
1436
|
+
const wanted = new Set(want.map((w) => w.path));
|
|
1437
|
+
const paths = /* @__PURE__ */ new Set();
|
|
1438
|
+
for (const item of have)
|
|
1439
|
+
if (item.path !== null && !wanted.has(item.path)) paths.add(item.path);
|
|
1440
|
+
return [...paths];
|
|
1441
|
+
}
|
|
1442
|
+
function isGone(path, item, seen, opened) {
|
|
1443
|
+
return seen.has(path) || item.issue !== null && opened.get(item.issue.number) === path;
|
|
1444
|
+
}
|
|
1445
|
+
function planSync(want, have, seen = /* @__PURE__ */ new Set(), opened = /* @__PURE__ */ new Map()) {
|
|
1446
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
1447
|
+
for (const item of have)
|
|
1448
|
+
if (item.path !== null)
|
|
1449
|
+
byPath.set(item.path, [...byPath.get(item.path) ?? [], item]);
|
|
1450
|
+
const kept = /* @__PURE__ */ new Map();
|
|
1451
|
+
const surplus = [];
|
|
1452
|
+
for (const [path, items] of byPath) {
|
|
1453
|
+
const [keep, ...rest] = [...items].sort(keptFirst);
|
|
1454
|
+
if (keep !== void 0) kept.set(path, keep);
|
|
1455
|
+
surplus.push(...rest.map(gone));
|
|
1456
|
+
}
|
|
1457
|
+
const left = strays(have);
|
|
1458
|
+
const steps = [];
|
|
1459
|
+
const wanted = /* @__PURE__ */ new Set();
|
|
1460
|
+
for (const w of want) {
|
|
1461
|
+
wanted.add(w.path);
|
|
1462
|
+
const item = kept.get(w.path) ?? left.get(w.body)?.[0];
|
|
1463
|
+
if (item === void 0) steps.push({ kind: "create", want: w });
|
|
1464
|
+
else if (item.issue === null)
|
|
1465
|
+
steps.push({ kind: "convert", id: item.id, want: w });
|
|
1466
|
+
else if (item.path === null || !item.issue.open || !item.issue.labelled || differs(item, w))
|
|
1467
|
+
steps.push({
|
|
1468
|
+
kind: "update",
|
|
1469
|
+
id: item.id,
|
|
1470
|
+
want: w,
|
|
1471
|
+
reopen: !item.issue.open
|
|
1472
|
+
});
|
|
1473
|
+
else steps.push({ kind: "unchanged", id: item.id });
|
|
1474
|
+
}
|
|
1475
|
+
for (const [path, item] of kept)
|
|
1476
|
+
if (!wanted.has(path))
|
|
1477
|
+
steps.push(
|
|
1478
|
+
isGone(path, item, seen, opened) ? gone(item) : { kind: "unchanged", id: item.id }
|
|
1479
|
+
);
|
|
1480
|
+
return [...steps, ...surplus];
|
|
1481
|
+
}
|
|
1482
|
+
function stillOpened(opened, have, seen, closed, created) {
|
|
1483
|
+
const items = /* @__PURE__ */ new Map();
|
|
1484
|
+
for (const item of have)
|
|
1485
|
+
if (item.issue !== null) items.set(item.issue.number, item.id);
|
|
1486
|
+
const next = /* @__PURE__ */ new Map();
|
|
1487
|
+
for (const [number, path] of opened) {
|
|
1488
|
+
const id = items.get(number);
|
|
1489
|
+
if (id !== void 0 && !closed.has(id) && !seen.has(path))
|
|
1490
|
+
next.set(number, path);
|
|
1491
|
+
}
|
|
1492
|
+
for (const [path, placed] of created) next.set(placed.number, path);
|
|
1493
|
+
return next;
|
|
1494
|
+
}
|
|
1495
|
+
function issuedAfter(steps, have, placed) {
|
|
1496
|
+
const byId = new Map(have.map((i) => [i.id, i]));
|
|
1497
|
+
const issued = /* @__PURE__ */ new Map();
|
|
1498
|
+
for (const step2 of steps) {
|
|
1499
|
+
if (step2.kind === "create" || step2.kind === "convert") {
|
|
1500
|
+
const p = placed.get(step2.want.path);
|
|
1501
|
+
if (p !== void 0) issued.set(step2.want.path, { ...p, body: null });
|
|
1502
|
+
} else if (step2.kind === "update" || step2.kind === "unchanged") {
|
|
1503
|
+
const item = byId.get(step2.id);
|
|
1504
|
+
const path = step2.kind === "update" ? step2.want.path : item?.path;
|
|
1505
|
+
if (item === void 0 || path == null || item.issue === null) continue;
|
|
1506
|
+
issued.set(path, {
|
|
1507
|
+
id: item.id,
|
|
1508
|
+
number: item.issue.number,
|
|
1509
|
+
body: item.issue.body
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
return issued;
|
|
1514
|
+
}
|
|
1515
|
+
function planBodies(bodies, issued) {
|
|
1516
|
+
const steps = [];
|
|
1517
|
+
for (const [path, body] of bodies) {
|
|
1518
|
+
const i = issued.get(path);
|
|
1519
|
+
if (i === void 0) continue;
|
|
1520
|
+
if (i.body === null || digestOf(i.body) !== digestOf(body))
|
|
1521
|
+
steps.push({ kind: "body", id: i.id, body });
|
|
1522
|
+
}
|
|
1523
|
+
return steps;
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1407
1526
|
// src/core/github.ts
|
|
1408
1527
|
import { setTimeout as delay } from "timers/promises";
|
|
1409
1528
|
var DEFAULT_GITHUB_API = "https://api.github.com";
|
|
@@ -2226,6 +2345,45 @@ async function repository(owner, name, label, o) {
|
|
|
2226
2345
|
const r = d?.repository ?? null;
|
|
2227
2346
|
return r === null ? null : { id: r.id, issues: r.hasIssuesEnabled, labelId: r.label?.id ?? null };
|
|
2228
2347
|
}
|
|
2348
|
+
async function openIssues(owner, name, label, o) {
|
|
2349
|
+
const found = [];
|
|
2350
|
+
let after = null;
|
|
2351
|
+
for (; ; ) {
|
|
2352
|
+
const d = await graphql(
|
|
2353
|
+
`
|
|
2354
|
+
query (
|
|
2355
|
+
$owner: String!
|
|
2356
|
+
$name: String!
|
|
2357
|
+
$label: String!
|
|
2358
|
+
$after: String
|
|
2359
|
+
) {
|
|
2360
|
+
repository(owner: $owner, name: $name) {
|
|
2361
|
+
issues(first: 100, after: $after, states: OPEN, labels: [$label]) {
|
|
2362
|
+
nodes {
|
|
2363
|
+
id
|
|
2364
|
+
number
|
|
2365
|
+
title
|
|
2366
|
+
body
|
|
2367
|
+
}
|
|
2368
|
+
pageInfo {
|
|
2369
|
+
hasNextPage
|
|
2370
|
+
endCursor
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
`,
|
|
2376
|
+
{ owner, name, label, after },
|
|
2377
|
+
o
|
|
2378
|
+
);
|
|
2379
|
+
const page = d.repository?.issues;
|
|
2380
|
+
if (page === void 0) return found;
|
|
2381
|
+
found.push(...page.nodes);
|
|
2382
|
+
if (!page.pageInfo.hasNextPage || page.pageInfo.endCursor === null)
|
|
2383
|
+
return found;
|
|
2384
|
+
after = page.pageInfo.endCursor;
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2229
2387
|
async function createLabel(owner, name, label, o) {
|
|
2230
2388
|
const body = await postJson(
|
|
2231
2389
|
`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/labels`,
|
|
@@ -2488,6 +2646,7 @@ var GitHubBoards = class {
|
|
|
2488
2646
|
const agent = await single("Agent", "Agent", [WORKING]);
|
|
2489
2647
|
const session = await text("Session");
|
|
2490
2648
|
const path = await text("Path");
|
|
2649
|
+
const sessions = await text("Sessions");
|
|
2491
2650
|
const current = await views(cache.projectId, this.#o);
|
|
2492
2651
|
const first = current[0];
|
|
2493
2652
|
if (first !== void 0 && first.name === DEFAULT_VIEW && !current.some((v) => v.name === ALL_VIEW)) {
|
|
@@ -2556,7 +2715,15 @@ var GitHubBoards = class {
|
|
|
2556
2715
|
await linkRepository(cache.projectId, memory.id, this.#o);
|
|
2557
2716
|
added.push(`link ${repository2}`);
|
|
2558
2717
|
}
|
|
2559
|
-
cache.fields = [
|
|
2718
|
+
cache.fields = [
|
|
2719
|
+
status2,
|
|
2720
|
+
collection,
|
|
2721
|
+
...own.values(),
|
|
2722
|
+
agent,
|
|
2723
|
+
session,
|
|
2724
|
+
path,
|
|
2725
|
+
sessions
|
|
2726
|
+
];
|
|
2560
2727
|
return added;
|
|
2561
2728
|
}
|
|
2562
2729
|
async items(board, options = {}) {
|
|
@@ -2581,7 +2748,8 @@ var GitHubBoards = class {
|
|
|
2581
2748
|
collectionStatus: r.values[statusFieldName(r.values[COLLECTION_FIELD] ?? "")] ?? null,
|
|
2582
2749
|
type: r.values[COLLECTION_FIELD] ?? null,
|
|
2583
2750
|
agent: r.values["Agent"] ?? null,
|
|
2584
|
-
session: r.values["Session"] ?? null
|
|
2751
|
+
session: r.values["Session"] ?? null,
|
|
2752
|
+
sessions: r.values["Sessions"] ?? null
|
|
2585
2753
|
};
|
|
2586
2754
|
});
|
|
2587
2755
|
}
|
|
@@ -2649,10 +2817,49 @@ var GitHubBoards = class {
|
|
|
2649
2817
|
await this.#values(board, step2.id, step2.want);
|
|
2650
2818
|
return null;
|
|
2651
2819
|
}
|
|
2652
|
-
/**
|
|
2820
|
+
/**
|
|
2821
|
+
* An open issue of `.rness`, labelled `rness`, whose body starts with the
|
|
2822
|
+
* document's first line — made by an earlier sync whose item the board's
|
|
2823
|
+
* listing did not show yet, 18 s later (spec 0020 §7) — or null. Read once
|
|
2824
|
+
* per process, at the first create; an issue taken is taken off the list.
|
|
2825
|
+
*/
|
|
2826
|
+
async #adoptable(board, cache, want) {
|
|
2827
|
+
cache.open ??= await openIssues(board.org, MEMORY, LABEL, this.#o);
|
|
2828
|
+
const at = cache.open.findIndex((i) => firstLine3(i.body) === want.body);
|
|
2829
|
+
if (at === -1) return null;
|
|
2830
|
+
return cache.open.splice(at, 1)[0] ?? null;
|
|
2831
|
+
}
|
|
2832
|
+
/**
|
|
2833
|
+
* A new document's issue: labelled, the first line as body, added to the
|
|
2834
|
+
* board, Path first. One already made for it is added instead: GitHub adds
|
|
2835
|
+
* an issue already on the board as the item it is, so no second one.
|
|
2836
|
+
*/
|
|
2653
2837
|
async #create(board, cache, want) {
|
|
2654
2838
|
const memory = await this.#memory(board.org);
|
|
2655
2839
|
const labelId = await this.#labelId(board);
|
|
2840
|
+
const found = await this.#adoptable(board, cache, want);
|
|
2841
|
+
if (found !== null) {
|
|
2842
|
+
const id2 = await addItem(cache.projectId, found.id, this.#o);
|
|
2843
|
+
const known = cache.known.get(id2) ?? {
|
|
2844
|
+
id: id2,
|
|
2845
|
+
draftId: null,
|
|
2846
|
+
issue: {
|
|
2847
|
+
id: found.id,
|
|
2848
|
+
number: found.number,
|
|
2849
|
+
open: true,
|
|
2850
|
+
repository: `${board.org}/${MEMORY}`,
|
|
2851
|
+
body: found.body,
|
|
2852
|
+
labels: [LABEL]
|
|
2853
|
+
},
|
|
2854
|
+
title: found.title,
|
|
2855
|
+
archived: false,
|
|
2856
|
+
values: {}
|
|
2857
|
+
};
|
|
2858
|
+
cache.known.set(id2, known);
|
|
2859
|
+
await this.#issue(known, want, labelId);
|
|
2860
|
+
await this.#values(board, id2, want);
|
|
2861
|
+
return { id: id2, number: found.number, adopted: true };
|
|
2862
|
+
}
|
|
2656
2863
|
const made = await createIssue(
|
|
2657
2864
|
memory.id,
|
|
2658
2865
|
{ title: want.title, body: want.body, labelIds: [labelId] },
|
|
@@ -2695,7 +2902,8 @@ var GitHubBoards = class {
|
|
|
2695
2902
|
["Path", want.path],
|
|
2696
2903
|
[COLLECTION_FIELD, want.type],
|
|
2697
2904
|
[STATUS_FIELD, want.status],
|
|
2698
|
-
...want.statusField === null ? [] : [[want.statusField, want.status]]
|
|
2905
|
+
...want.statusField === null ? [] : [[want.statusField, want.status]],
|
|
2906
|
+
["Sessions", want.sessions]
|
|
2699
2907
|
];
|
|
2700
2908
|
for (const [name, value] of wanted)
|
|
2701
2909
|
if ((values2[name] ?? null) !== value)
|
|
@@ -3063,7 +3271,7 @@ var GREETING = /^Hi ([^!\s]+)! You've successfully authenticated/m;
|
|
|
3063
3271
|
function parseSshGreeting(stderr) {
|
|
3064
3272
|
return GREETING.exec(stderr)?.[1] ?? null;
|
|
3065
3273
|
}
|
|
3066
|
-
function
|
|
3274
|
+
function firstLine4(text) {
|
|
3067
3275
|
return text.split("\n").find((l) => l.trim() !== "")?.trim() ?? null;
|
|
3068
3276
|
}
|
|
3069
3277
|
var STDERR_FLUSH_MS2 = 200;
|
|
@@ -3103,7 +3311,7 @@ async function detectGithubSsh(opts) {
|
|
|
3103
3311
|
settle(
|
|
3104
3312
|
login !== null ? { ok: true, login } : {
|
|
3105
3313
|
ok: false,
|
|
3106
|
-
reason:
|
|
3314
|
+
reason: firstLine4(stderr2) ?? `ssh exited with code ${code ?? "?"}`
|
|
3107
3315
|
}
|
|
3108
3316
|
);
|
|
3109
3317
|
};
|
|
@@ -3473,6 +3681,8 @@ Writing:
|
|
|
3473
3681
|
\`org/\` it affects.
|
|
3474
3682
|
- An ADR it replaces is named in Context. That one becomes \`Superseded\`,
|
|
3475
3683
|
with \`superseded_by:\`, only once the new ADR is \`Accepted\`.
|
|
3684
|
+
- Add \`\${CLAUDE_SESSION_ID}\` at the end of \`sessions:\` in the front matter,
|
|
3685
|
+
unless it is already there.
|
|
3476
3686
|
- The rness hook checks every edit under \`${rness}/\`: fix what it reports.
|
|
3477
3687
|
|
|
3478
3688
|
After writing: give the path and the Decision section, and say the ADR
|
|
@@ -3510,6 +3720,8 @@ Writing:
|
|
|
3510
3720
|
- What was checked in this session (a document read, a command run) is
|
|
3511
3721
|
written as verified, with the date; everything else as a proposal or an
|
|
3512
3722
|
open question.
|
|
3723
|
+
- Add \`\${CLAUDE_SESSION_ID}\` at the end of \`sessions:\` in the front matter,
|
|
3724
|
+
unless it is already there.
|
|
3513
3725
|
- The rness hook checks every edit under \`${rness}/\`: fix what it reports.
|
|
3514
3726
|
|
|
3515
3727
|
After writing: give the path and the summary. It stays \`Draft\` until the
|
|
@@ -3550,6 +3762,8 @@ Writing:
|
|
|
3550
3762
|
repository has one.
|
|
3551
3763
|
- Where the plan decides something the specification leaves open, a
|
|
3552
3764
|
section says so.
|
|
3765
|
+
- Add \`\${CLAUDE_SESSION_ID}\` at the end of \`sessions:\` in the front matter,
|
|
3766
|
+
unless it is already there.
|
|
3553
3767
|
- The rness hook checks every edit under \`${rness}/\`: fix what it reports.
|
|
3554
3768
|
|
|
3555
3769
|
After writing: give the path and the list of tasks. It becomes \`Ready\` when
|
|
@@ -3579,6 +3793,8 @@ Arguments: \`$ARGUMENTS\`.
|
|
|
3579
3793
|
ran, what it showed, what could not run and why;
|
|
3580
3794
|
- the specification: \`Implemented\` once every plan of it is
|
|
3581
3795
|
\`Completed\`; \`updated\` today;
|
|
3796
|
+
- the plan and the specification: add \`\${CLAUDE_SESSION_ID}\` at the end
|
|
3797
|
+
of \`sessions:\` in their front matter, unless it is already there;
|
|
3582
3798
|
- the smallest set of documents the work makes inaccurate: \`${rness}/docs/\`,
|
|
3583
3799
|
the READMEs of the repositories it changed.
|
|
3584
3800
|
6. A task not proven: the plan stays \`In progress\` \u2014 or \`Blocked\`, the
|
|
@@ -5660,7 +5876,7 @@ async function createBlank(input) {
|
|
|
5660
5876
|
}
|
|
5661
5877
|
|
|
5662
5878
|
// src/commands/create.ts
|
|
5663
|
-
function
|
|
5879
|
+
function firstLine5(text) {
|
|
5664
5880
|
return text.split("\n").find((l) => l.trim() !== "")?.trim() ?? "unknown error";
|
|
5665
5881
|
}
|
|
5666
5882
|
function splitSpecs(list2) {
|
|
@@ -5719,7 +5935,7 @@ async function pickRepositories(input) {
|
|
|
5719
5935
|
ui.hint(`listed the first ${MAX_PAGES * PER_PAGE} repositories of ${org}`);
|
|
5720
5936
|
} catch (e) {
|
|
5721
5937
|
failed = true;
|
|
5722
|
-
ui.warn(
|
|
5938
|
+
ui.warn(firstLine5(e instanceof Error ? e.message : String(e)));
|
|
5723
5939
|
}
|
|
5724
5940
|
const inCatalogue = (name) => Object.hasOwn(input.catalogue, name);
|
|
5725
5941
|
const byLabel = (a, b) => a.label.localeCompare(b.label, "en", { sensitivity: "base" });
|
|
@@ -5813,7 +6029,7 @@ async function cloneSelection(input) {
|
|
|
5813
6029
|
manifest = result.manifest;
|
|
5814
6030
|
ui.line("declared", `scope ${result.name} (org/${result.name})`);
|
|
5815
6031
|
} catch (e) {
|
|
5816
|
-
const message2 =
|
|
6032
|
+
const message2 = firstLine5(e instanceof Error ? e.message : String(e));
|
|
5817
6033
|
ui.error(`${spec}: ${message2}`);
|
|
5818
6034
|
failures.push({ spec, message: message2 });
|
|
5819
6035
|
}
|
|
@@ -5908,7 +6124,7 @@ async function publishContext(input) {
|
|
|
5908
6124
|
);
|
|
5909
6125
|
return true;
|
|
5910
6126
|
} catch (e) {
|
|
5911
|
-
ui.warn(
|
|
6127
|
+
ui.warn(firstLine5(e instanceof Error ? e.message : String(e)));
|
|
5912
6128
|
return false;
|
|
5913
6129
|
}
|
|
5914
6130
|
}
|
|
@@ -6509,8 +6725,7 @@ async function declaredManager(rnessDir, pm) {
|
|
|
6509
6725
|
}
|
|
6510
6726
|
return `${pm}@${await packageManagerVersion(pm)}`;
|
|
6511
6727
|
}
|
|
6512
|
-
async function clonesToCommit(root, cwd, manifest) {
|
|
6513
|
-
const files = writtenFiles(manifest);
|
|
6728
|
+
async function clonesToCommit(root, cwd, manifest, files) {
|
|
6514
6729
|
const clones = [];
|
|
6515
6730
|
for (const repo of Object.keys(manifest.repos)) {
|
|
6516
6731
|
const dir = join23(root, "org", repo);
|
|
@@ -6524,6 +6739,27 @@ async function clonesToCommit(root, cwd, manifest) {
|
|
|
6524
6739
|
}
|
|
6525
6740
|
return clones;
|
|
6526
6741
|
}
|
|
6742
|
+
async function filesTheSyncWrites(root, rnessDir, manifest) {
|
|
6743
|
+
const own = writtenFiles(manifest);
|
|
6744
|
+
const pinned = await readPinnedCli(rnessDir);
|
|
6745
|
+
if (pinned === null) return own;
|
|
6746
|
+
try {
|
|
6747
|
+
const { stdout } = await execFileP6(
|
|
6748
|
+
process.execPath,
|
|
6749
|
+
[join23(pinned.dir, pinned.bin), "written-files", "--cwd", root],
|
|
6750
|
+
{
|
|
6751
|
+
cwd: root,
|
|
6752
|
+
env: { ...process.env, NO_COLOR: "1", RNESS_NO_INSTALL: "1" },
|
|
6753
|
+
timeout: 1e4
|
|
6754
|
+
}
|
|
6755
|
+
);
|
|
6756
|
+
const theirs = JSON.parse(stdout);
|
|
6757
|
+
if (Array.isArray(theirs) && theirs.every((f) => typeof f === "string"))
|
|
6758
|
+
return [.../* @__PURE__ */ new Set([...own, ...theirs])];
|
|
6759
|
+
} catch {
|
|
6760
|
+
}
|
|
6761
|
+
return own;
|
|
6762
|
+
}
|
|
6527
6763
|
function finish(ui, cwd, rnessDir, label, target2, ending) {
|
|
6528
6764
|
const rel = relative5(cwd, rnessDir) || ".";
|
|
6529
6765
|
const message2 = `chore: rness ${target2}`;
|
|
@@ -6772,11 +7008,15 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal, deps =
|
|
|
6772
7008
|
}
|
|
6773
7009
|
return finish(ui, cwd, ws.rnessDir, label, target2, {
|
|
6774
7010
|
commit: committed.kind,
|
|
6775
|
-
clones: await
|
|
6776
|
-
ws.
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
7011
|
+
clones: await (async () => {
|
|
7012
|
+
const manifest = await loadManifest(ws.rnessDir);
|
|
7013
|
+
return clonesToCommit(
|
|
7014
|
+
ws.root,
|
|
7015
|
+
cwd,
|
|
7016
|
+
manifest,
|
|
7017
|
+
await filesTheSyncWrites(ws.root, ws.rnessDir, manifest)
|
|
7018
|
+
);
|
|
7019
|
+
})()
|
|
6780
7020
|
});
|
|
6781
7021
|
} catch (e) {
|
|
6782
7022
|
return reportError(e);
|
|
@@ -7642,114 +7882,6 @@ async function writeOpened(file, opened) {
|
|
|
7642
7882
|
}
|
|
7643
7883
|
}
|
|
7644
7884
|
|
|
7645
|
-
// src/pulse/plan.ts
|
|
7646
|
-
var differs = (item, w) => item.title !== w.title || item.status !== w.status || w.statusField !== null && item.collectionStatus !== w.status || item.type !== w.type;
|
|
7647
|
-
var rank = (i) => i.issue === null ? 2 : i.issue.open ? 0 : 1;
|
|
7648
|
-
var keptFirst = (a, b) => rank(a) - rank(b) || (a.issue?.number ?? 0) - (b.issue?.number ?? 0);
|
|
7649
|
-
var gone = (item) => item.issue === null ? { kind: "archive", id: item.id } : { kind: "close", id: item.id };
|
|
7650
|
-
var firstLine5 = (body) => body.split(/\r\n?|\n/, 1)[0] ?? "";
|
|
7651
|
-
function strays(have) {
|
|
7652
|
-
const byLine = /* @__PURE__ */ new Map();
|
|
7653
|
-
for (const item of have) {
|
|
7654
|
-
if (item.path !== null || item.issue === null || item.issue.body === null || !item.issue.labelled)
|
|
7655
|
-
continue;
|
|
7656
|
-
const line3 = firstLine5(item.issue.body);
|
|
7657
|
-
byLine.set(line3, [...byLine.get(line3) ?? [], item]);
|
|
7658
|
-
}
|
|
7659
|
-
for (const items of byLine.values()) items.sort(keptFirst);
|
|
7660
|
-
return byLine;
|
|
7661
|
-
}
|
|
7662
|
-
function unwantedPaths(want, have) {
|
|
7663
|
-
const wanted = new Set(want.map((w) => w.path));
|
|
7664
|
-
const paths = /* @__PURE__ */ new Set();
|
|
7665
|
-
for (const item of have)
|
|
7666
|
-
if (item.path !== null && !wanted.has(item.path)) paths.add(item.path);
|
|
7667
|
-
return [...paths];
|
|
7668
|
-
}
|
|
7669
|
-
function isGone(path, item, seen, opened) {
|
|
7670
|
-
return seen.has(path) || item.issue !== null && opened.get(item.issue.number) === path;
|
|
7671
|
-
}
|
|
7672
|
-
function planSync(want, have, seen = /* @__PURE__ */ new Set(), opened = /* @__PURE__ */ new Map()) {
|
|
7673
|
-
const byPath = /* @__PURE__ */ new Map();
|
|
7674
|
-
for (const item of have)
|
|
7675
|
-
if (item.path !== null)
|
|
7676
|
-
byPath.set(item.path, [...byPath.get(item.path) ?? [], item]);
|
|
7677
|
-
const kept = /* @__PURE__ */ new Map();
|
|
7678
|
-
const surplus = [];
|
|
7679
|
-
for (const [path, items] of byPath) {
|
|
7680
|
-
const [keep, ...rest] = [...items].sort(keptFirst);
|
|
7681
|
-
if (keep !== void 0) kept.set(path, keep);
|
|
7682
|
-
surplus.push(...rest.map(gone));
|
|
7683
|
-
}
|
|
7684
|
-
const left = strays(have);
|
|
7685
|
-
const steps = [];
|
|
7686
|
-
const wanted = /* @__PURE__ */ new Set();
|
|
7687
|
-
for (const w of want) {
|
|
7688
|
-
wanted.add(w.path);
|
|
7689
|
-
const item = kept.get(w.path) ?? left.get(w.body)?.[0];
|
|
7690
|
-
if (item === void 0) steps.push({ kind: "create", want: w });
|
|
7691
|
-
else if (item.issue === null)
|
|
7692
|
-
steps.push({ kind: "convert", id: item.id, want: w });
|
|
7693
|
-
else if (item.path === null || !item.issue.open || !item.issue.labelled || differs(item, w))
|
|
7694
|
-
steps.push({
|
|
7695
|
-
kind: "update",
|
|
7696
|
-
id: item.id,
|
|
7697
|
-
want: w,
|
|
7698
|
-
reopen: !item.issue.open
|
|
7699
|
-
});
|
|
7700
|
-
else steps.push({ kind: "unchanged", id: item.id });
|
|
7701
|
-
}
|
|
7702
|
-
for (const [path, item] of kept)
|
|
7703
|
-
if (!wanted.has(path))
|
|
7704
|
-
steps.push(
|
|
7705
|
-
isGone(path, item, seen, opened) ? gone(item) : { kind: "unchanged", id: item.id }
|
|
7706
|
-
);
|
|
7707
|
-
return [...steps, ...surplus];
|
|
7708
|
-
}
|
|
7709
|
-
function stillOpened(opened, have, seen, closed, created) {
|
|
7710
|
-
const items = /* @__PURE__ */ new Map();
|
|
7711
|
-
for (const item of have)
|
|
7712
|
-
if (item.issue !== null) items.set(item.issue.number, item.id);
|
|
7713
|
-
const next = /* @__PURE__ */ new Map();
|
|
7714
|
-
for (const [number, path] of opened) {
|
|
7715
|
-
const id = items.get(number);
|
|
7716
|
-
if (id !== void 0 && !closed.has(id) && !seen.has(path))
|
|
7717
|
-
next.set(number, path);
|
|
7718
|
-
}
|
|
7719
|
-
for (const [path, placed] of created) next.set(placed.number, path);
|
|
7720
|
-
return next;
|
|
7721
|
-
}
|
|
7722
|
-
function issuedAfter(steps, have, placed) {
|
|
7723
|
-
const byId = new Map(have.map((i) => [i.id, i]));
|
|
7724
|
-
const issued = /* @__PURE__ */ new Map();
|
|
7725
|
-
for (const step2 of steps) {
|
|
7726
|
-
if (step2.kind === "create" || step2.kind === "convert") {
|
|
7727
|
-
const p = placed.get(step2.want.path);
|
|
7728
|
-
if (p !== void 0) issued.set(step2.want.path, { ...p, body: null });
|
|
7729
|
-
} else if (step2.kind === "update" || step2.kind === "unchanged") {
|
|
7730
|
-
const item = byId.get(step2.id);
|
|
7731
|
-
const path = step2.kind === "update" ? step2.want.path : item?.path;
|
|
7732
|
-
if (item === void 0 || path == null || item.issue === null) continue;
|
|
7733
|
-
issued.set(path, {
|
|
7734
|
-
id: item.id,
|
|
7735
|
-
number: item.issue.number,
|
|
7736
|
-
body: item.issue.body
|
|
7737
|
-
});
|
|
7738
|
-
}
|
|
7739
|
-
}
|
|
7740
|
-
return issued;
|
|
7741
|
-
}
|
|
7742
|
-
function planBodies(bodies, issued) {
|
|
7743
|
-
const steps = [];
|
|
7744
|
-
for (const [path, body] of bodies) {
|
|
7745
|
-
const i = issued.get(path);
|
|
7746
|
-
if (i === void 0) continue;
|
|
7747
|
-
if (i.body === null || digestOf(i.body) !== digestOf(body))
|
|
7748
|
-
steps.push({ kind: "body", id: i.id, body });
|
|
7749
|
-
}
|
|
7750
|
-
return steps;
|
|
7751
|
-
}
|
|
7752
|
-
|
|
7753
7885
|
// src/commands/pulse.ts
|
|
7754
7886
|
var PROJECT_SCOPE = "project";
|
|
7755
7887
|
var NEEDS_LOGIN = "the pulse needs a GitHub login: run rness login";
|
|
@@ -7827,10 +7959,15 @@ async function filesOf2(rnessDir) {
|
|
|
7827
7959
|
return files;
|
|
7828
7960
|
}
|
|
7829
7961
|
var count2 = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
7830
|
-
function sayDone(ui, org, documents2, steps, writes) {
|
|
7831
|
-
const n = (kind) => steps.filter((s) => s.kind === kind).length;
|
|
7962
|
+
function sayDone(ui, org, documents2, steps, writes, adopted) {
|
|
7963
|
+
const n = (kind) => steps.filter((s) => s.kind === kind).length - (kind === "create" ? adopted : 0);
|
|
7832
7964
|
const reopened = steps.filter((s) => s.kind === "update" && s.reopen).length;
|
|
7833
7965
|
if (n("create") > 0) ui.line("created", count2(n("create"), "issue"));
|
|
7966
|
+
if (adopted > 0)
|
|
7967
|
+
ui.line(
|
|
7968
|
+
"adopted",
|
|
7969
|
+
`${count2(adopted, "issue")} already made for its document`
|
|
7970
|
+
);
|
|
7834
7971
|
if (n("convert") > 0)
|
|
7835
7972
|
ui.line(
|
|
7836
7973
|
"converted",
|
|
@@ -7843,11 +7980,12 @@ function sayDone(ui, org, documents2, steps, writes) {
|
|
|
7843
7980
|
).length;
|
|
7844
7981
|
const parts = [
|
|
7845
7982
|
["created", n("create")],
|
|
7983
|
+
["adopted", adopted],
|
|
7846
7984
|
["converted", n("convert")],
|
|
7847
7985
|
["updated", n("update") + bodyOnly],
|
|
7848
7986
|
[
|
|
7849
7987
|
"unchanged",
|
|
7850
|
-
documents2 - n("create") - n("convert") - n("update") - bodyOnly
|
|
7988
|
+
documents2 - n("create") - adopted - n("convert") - n("update") - bodyOnly
|
|
7851
7989
|
],
|
|
7852
7990
|
["archived", n("close") + n("archive")]
|
|
7853
7991
|
].filter(([, k]) => k > 0).map(([word, k]) => `${k} ${word}`);
|
|
@@ -7875,6 +8013,7 @@ async function syncBoard(c, board, ui, sayLayout) {
|
|
|
7875
8013
|
const changes = steps.filter((s) => s.kind !== "unchanged").length;
|
|
7876
8014
|
let writes = [];
|
|
7877
8015
|
let made = 0;
|
|
8016
|
+
let adopted = 0;
|
|
7878
8017
|
try {
|
|
7879
8018
|
const placed = /* @__PURE__ */ new Map();
|
|
7880
8019
|
const created = /* @__PURE__ */ new Map();
|
|
@@ -7884,7 +8023,9 @@ async function syncBoard(c, board, ui, sayLayout) {
|
|
|
7884
8023
|
const p = await fromGithub(c.provider.apply(board, step2));
|
|
7885
8024
|
if (p !== null && (step2.kind === "create" || step2.kind === "convert"))
|
|
7886
8025
|
placed.set(step2.want.path, p);
|
|
7887
|
-
if (p
|
|
8026
|
+
if (p?.adopted === true) adopted++;
|
|
8027
|
+
else if (p !== null && step2.kind === "create")
|
|
8028
|
+
created.set(step2.want.path, p);
|
|
7888
8029
|
if (step2.kind === "close" || step2.kind === "archive")
|
|
7889
8030
|
closed.add(step2.id);
|
|
7890
8031
|
if (step2.kind !== "unchanged") made++;
|
|
@@ -7923,7 +8064,7 @@ async function syncBoard(c, board, ui, sayLayout) {
|
|
|
7923
8064
|
{ cause: e }
|
|
7924
8065
|
);
|
|
7925
8066
|
}
|
|
7926
|
-
sayDone(ui, c.org, want.length, steps, writes);
|
|
8067
|
+
sayDone(ui, c.org, want.length, steps, writes, adopted);
|
|
7927
8068
|
}
|
|
7928
8069
|
async function pulseCreateCommand(opts, deps = {}) {
|
|
7929
8070
|
try {
|
|
@@ -8029,13 +8170,16 @@ async function mark(opts) {
|
|
|
8029
8170
|
return 0;
|
|
8030
8171
|
}
|
|
8031
8172
|
const wanted = new Set(opts.paths);
|
|
8032
|
-
const documents2 = new
|
|
8033
|
-
(await statusTabs(c.rnessDir)).flatMap(
|
|
8173
|
+
const documents2 = new Map(
|
|
8174
|
+
(await statusTabs(c.rnessDir)).flatMap(
|
|
8175
|
+
(t) => t.rows.map((r) => [r.path, r.status])
|
|
8176
|
+
)
|
|
8034
8177
|
);
|
|
8035
|
-
const onBoard = new
|
|
8036
|
-
items.flatMap((i) => i.path === null ? [] : [i.path])
|
|
8178
|
+
const onBoard = new Map(
|
|
8179
|
+
items.flatMap((i) => i.path === null ? [] : [[i.path, i.status]])
|
|
8037
8180
|
);
|
|
8038
|
-
|
|
8181
|
+
const stale = (path) => documents2.has(path) && (!onBoard.has(path) || onBoard.get(path) !== documents2.get(path));
|
|
8182
|
+
if ([...wanted].some(stale)) {
|
|
8039
8183
|
const synced = await oneSyncAtATime(
|
|
8040
8184
|
key,
|
|
8041
8185
|
() => syncBoard(c, board, plainUi, eachAdded),
|
|
@@ -8281,6 +8425,21 @@ async function statusCommand(tab, opts, terminal = { input: process.stdin, outpu
|
|
|
8281
8425
|
}
|
|
8282
8426
|
}
|
|
8283
8427
|
|
|
8428
|
+
// src/commands/written-files.ts
|
|
8429
|
+
async function writtenFilesCommand(opts) {
|
|
8430
|
+
try {
|
|
8431
|
+
const ws = await findWorkspace(opts.cwd ?? process.cwd());
|
|
8432
|
+
const manifest = await loadManifest(ws.rnessDir);
|
|
8433
|
+
process.stdout.write(`${JSON.stringify(writtenFiles(manifest))}
|
|
8434
|
+
`);
|
|
8435
|
+
return 0;
|
|
8436
|
+
} catch (e) {
|
|
8437
|
+
process.stderr.write(`${e instanceof Error ? e.message : String(e)}
|
|
8438
|
+
`);
|
|
8439
|
+
return 1;
|
|
8440
|
+
}
|
|
8441
|
+
}
|
|
8442
|
+
|
|
8284
8443
|
// src/cli.ts
|
|
8285
8444
|
function buildProgram(state) {
|
|
8286
8445
|
const program = new Command().name("rness").description("Configuration-plane CLI for rness workspaces").version(VERSION, "-v, --version", "print the version").exitOverride().showHelpAfterError().configureOutput({
|
|
@@ -8372,6 +8531,9 @@ function buildProgram(state) {
|
|
|
8372
8531
|
program.command("git-credential", { hidden: true }).argument("<operation>").action(async (operation) => {
|
|
8373
8532
|
state.code = await gitCredentialCommand(operation);
|
|
8374
8533
|
});
|
|
8534
|
+
program.command("written-files", { hidden: true }).addOption(new Option("--cwd <dir>").hideHelp()).action(async (opts) => {
|
|
8535
|
+
state.code = await writtenFilesCommand(opts);
|
|
8536
|
+
});
|
|
8375
8537
|
program.command("hook", { hidden: true }).argument("<event>", "session-start, post-tool-use or session-end").action(async (event) => {
|
|
8376
8538
|
state.code = await hookCommand(event);
|
|
8377
8539
|
});
|
|
@@ -8561,4 +8723,4 @@ export {
|
|
|
8561
8723
|
OWN_COMMANDS,
|
|
8562
8724
|
catchUp
|
|
8563
8725
|
};
|
|
8564
|
-
//# sourceMappingURL=chunk-
|
|
8726
|
+
//# sourceMappingURL=chunk-7IVHL744.js.map
|