@rness/cli 0.15.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 +24 -1
- package/dist/bin/rness.js +1 -1
- package/dist/{chunk-HGT7BIWK.js → chunk-7IVHL744.js} +258 -129
- package/dist/chunk-7IVHL744.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-HGT7BIWK.js.map +0 -1
package/README.md
CHANGED
|
@@ -310,6 +310,13 @@ added to project`) may change a field of rness's items; the next sync
|
|
|
310
310
|
`the pulse needs the project scope: run rness login` or
|
|
311
311
|
`cannot reach GitHub: …`. Two sessions marking one plan both write; the
|
|
312
312
|
last wins.
|
|
313
|
+
- **One issue per document**: before making an issue, `pulse sync` reads
|
|
314
|
+
the open issues of `.rness` labelled `rness` (one request per 100, and
|
|
315
|
+
only when it has one to make). One whose body starts with the document's
|
|
316
|
+
first line was made by an earlier sync, whose item the board's listing
|
|
317
|
+
did not show yet. It is added to the board instead of made again, and
|
|
318
|
+
the output says `adopted 1 issue already made for its document`. Seen on
|
|
319
|
+
2026-09-30: two syncs 18 s apart made two issues for one document.
|
|
313
320
|
- **Rate**: rness sends one request at a time. A new document costs an
|
|
314
321
|
issue, its addition to the board, up to five fields, then its body. An
|
|
315
322
|
unchanged document costs nothing but its share of the listing, which
|
|
@@ -345,7 +352,7 @@ repository, the board).
|
|
|
345
352
|
`contract`, `provider`, `org`, `agents`, `pulse`, `repos`, `scopes`.
|
|
346
353
|
- A provider _written_ in `rness.json` that this version cannot talk to
|
|
347
354
|
(`gitlab`) is refused by `validate`, `create`, `login` and `pulse`:
|
|
348
|
-
`provider "gitlab" is not supported by @rness/cli 0.15.
|
|
355
|
+
`provider "gitlab" is not supported by @rness/cli 0.15.1 (supported:
|
|
349
356
|
github)`. `add`, `sync` and the local commands never refuse. `null` is not a
|
|
350
357
|
value: an absent key means none.
|
|
351
358
|
|
|
@@ -522,6 +529,22 @@ per repository, the files to commit there.
|
|
|
522
529
|
Exit codes: 0 success, 1 failure, 2 usage — or a refusal without a TTY.
|
|
523
530
|
`RNESS_DEBUG=1` adds stack traces; `RNESS_NO_DELEGATE=1` skips the delegation.
|
|
524
531
|
|
|
532
|
+
## 0.15.1 — upgrade names every file to commit
|
|
533
|
+
|
|
534
|
+
- `rness upgrade`'s next steps name every file the new version's sync
|
|
535
|
+
wrote in a repository. They used to be listed from the running copy,
|
|
536
|
+
which does not know the files a newer release adds: 0.13.0 named two of
|
|
537
|
+
the plugin's six files after syncing with 0.14.0. The running copy now
|
|
538
|
+
asks the copy it installed. This applies to upgrades run by 0.15.1 or
|
|
539
|
+
later; from an older copy, commit `.claude/skills/rness/` whole, as the
|
|
540
|
+
changelog of each release says.
|
|
541
|
+
- Agent Pulse no longer gives a document a second issue when two syncs
|
|
542
|
+
follow each other within seconds. The second one's listing of the board
|
|
543
|
+
may not show the item the first one added yet. Before making an issue,
|
|
544
|
+
`pulse sync` now looks for an open issue of `.rness` already made for the
|
|
545
|
+
document, and adds that one (`adopted 1 issue`). See "Pulse".
|
|
546
|
+
- Blocks are unchanged.
|
|
547
|
+
|
|
525
548
|
## 0.15.0 — Agent Pulse follows a status change; the sessions are kept
|
|
526
549
|
|
|
527
550
|
- An edit that changes a document's status syncs Agent Pulse at once: its
|
package/dist/bin/rness.js
CHANGED
|
@@ -486,7 +486,7 @@ function parseRepoSpec(spec, org, host) {
|
|
|
486
486
|
}
|
|
487
487
|
|
|
488
488
|
// src/version.ts
|
|
489
|
-
var VERSION = "0.15.
|
|
489
|
+
var VERSION = "0.15.1";
|
|
490
490
|
|
|
491
491
|
// src/core/pm.ts
|
|
492
492
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -1415,6 +1415,114 @@ function desiredOf(tabs, org) {
|
|
|
1415
1415
|
);
|
|
1416
1416
|
}
|
|
1417
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
|
+
|
|
1418
1526
|
// src/core/github.ts
|
|
1419
1527
|
import { setTimeout as delay } from "timers/promises";
|
|
1420
1528
|
var DEFAULT_GITHUB_API = "https://api.github.com";
|
|
@@ -2237,6 +2345,45 @@ async function repository(owner, name, label, o) {
|
|
|
2237
2345
|
const r = d?.repository ?? null;
|
|
2238
2346
|
return r === null ? null : { id: r.id, issues: r.hasIssuesEnabled, labelId: r.label?.id ?? null };
|
|
2239
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
|
+
}
|
|
2240
2387
|
async function createLabel(owner, name, label, o) {
|
|
2241
2388
|
const body = await postJson(
|
|
2242
2389
|
`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/labels`,
|
|
@@ -2670,10 +2817,49 @@ var GitHubBoards = class {
|
|
|
2670
2817
|
await this.#values(board, step2.id, step2.want);
|
|
2671
2818
|
return null;
|
|
2672
2819
|
}
|
|
2673
|
-
/**
|
|
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
|
+
*/
|
|
2674
2837
|
async #create(board, cache, want) {
|
|
2675
2838
|
const memory = await this.#memory(board.org);
|
|
2676
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
|
+
}
|
|
2677
2863
|
const made = await createIssue(
|
|
2678
2864
|
memory.id,
|
|
2679
2865
|
{ title: want.title, body: want.body, labelIds: [labelId] },
|
|
@@ -3085,7 +3271,7 @@ var GREETING = /^Hi ([^!\s]+)! You've successfully authenticated/m;
|
|
|
3085
3271
|
function parseSshGreeting(stderr) {
|
|
3086
3272
|
return GREETING.exec(stderr)?.[1] ?? null;
|
|
3087
3273
|
}
|
|
3088
|
-
function
|
|
3274
|
+
function firstLine4(text) {
|
|
3089
3275
|
return text.split("\n").find((l) => l.trim() !== "")?.trim() ?? null;
|
|
3090
3276
|
}
|
|
3091
3277
|
var STDERR_FLUSH_MS2 = 200;
|
|
@@ -3125,7 +3311,7 @@ async function detectGithubSsh(opts) {
|
|
|
3125
3311
|
settle(
|
|
3126
3312
|
login !== null ? { ok: true, login } : {
|
|
3127
3313
|
ok: false,
|
|
3128
|
-
reason:
|
|
3314
|
+
reason: firstLine4(stderr2) ?? `ssh exited with code ${code ?? "?"}`
|
|
3129
3315
|
}
|
|
3130
3316
|
);
|
|
3131
3317
|
};
|
|
@@ -5690,7 +5876,7 @@ async function createBlank(input) {
|
|
|
5690
5876
|
}
|
|
5691
5877
|
|
|
5692
5878
|
// src/commands/create.ts
|
|
5693
|
-
function
|
|
5879
|
+
function firstLine5(text) {
|
|
5694
5880
|
return text.split("\n").find((l) => l.trim() !== "")?.trim() ?? "unknown error";
|
|
5695
5881
|
}
|
|
5696
5882
|
function splitSpecs(list2) {
|
|
@@ -5749,7 +5935,7 @@ async function pickRepositories(input) {
|
|
|
5749
5935
|
ui.hint(`listed the first ${MAX_PAGES * PER_PAGE} repositories of ${org}`);
|
|
5750
5936
|
} catch (e) {
|
|
5751
5937
|
failed = true;
|
|
5752
|
-
ui.warn(
|
|
5938
|
+
ui.warn(firstLine5(e instanceof Error ? e.message : String(e)));
|
|
5753
5939
|
}
|
|
5754
5940
|
const inCatalogue = (name) => Object.hasOwn(input.catalogue, name);
|
|
5755
5941
|
const byLabel = (a, b) => a.label.localeCompare(b.label, "en", { sensitivity: "base" });
|
|
@@ -5843,7 +6029,7 @@ async function cloneSelection(input) {
|
|
|
5843
6029
|
manifest = result.manifest;
|
|
5844
6030
|
ui.line("declared", `scope ${result.name} (org/${result.name})`);
|
|
5845
6031
|
} catch (e) {
|
|
5846
|
-
const message2 =
|
|
6032
|
+
const message2 = firstLine5(e instanceof Error ? e.message : String(e));
|
|
5847
6033
|
ui.error(`${spec}: ${message2}`);
|
|
5848
6034
|
failures.push({ spec, message: message2 });
|
|
5849
6035
|
}
|
|
@@ -5938,7 +6124,7 @@ async function publishContext(input) {
|
|
|
5938
6124
|
);
|
|
5939
6125
|
return true;
|
|
5940
6126
|
} catch (e) {
|
|
5941
|
-
ui.warn(
|
|
6127
|
+
ui.warn(firstLine5(e instanceof Error ? e.message : String(e)));
|
|
5942
6128
|
return false;
|
|
5943
6129
|
}
|
|
5944
6130
|
}
|
|
@@ -6539,8 +6725,7 @@ async function declaredManager(rnessDir, pm) {
|
|
|
6539
6725
|
}
|
|
6540
6726
|
return `${pm}@${await packageManagerVersion(pm)}`;
|
|
6541
6727
|
}
|
|
6542
|
-
async function clonesToCommit(root, cwd, manifest) {
|
|
6543
|
-
const files = writtenFiles(manifest);
|
|
6728
|
+
async function clonesToCommit(root, cwd, manifest, files) {
|
|
6544
6729
|
const clones = [];
|
|
6545
6730
|
for (const repo of Object.keys(manifest.repos)) {
|
|
6546
6731
|
const dir = join23(root, "org", repo);
|
|
@@ -6554,6 +6739,27 @@ async function clonesToCommit(root, cwd, manifest) {
|
|
|
6554
6739
|
}
|
|
6555
6740
|
return clones;
|
|
6556
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
|
+
}
|
|
6557
6763
|
function finish(ui, cwd, rnessDir, label, target2, ending) {
|
|
6558
6764
|
const rel = relative5(cwd, rnessDir) || ".";
|
|
6559
6765
|
const message2 = `chore: rness ${target2}`;
|
|
@@ -6802,11 +7008,15 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal, deps =
|
|
|
6802
7008
|
}
|
|
6803
7009
|
return finish(ui, cwd, ws.rnessDir, label, target2, {
|
|
6804
7010
|
commit: committed.kind,
|
|
6805
|
-
clones: await
|
|
6806
|
-
ws.
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
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
|
+
})()
|
|
6810
7020
|
});
|
|
6811
7021
|
} catch (e) {
|
|
6812
7022
|
return reportError(e);
|
|
@@ -7672,114 +7882,6 @@ async function writeOpened(file, opened) {
|
|
|
7672
7882
|
}
|
|
7673
7883
|
}
|
|
7674
7884
|
|
|
7675
|
-
// src/pulse/plan.ts
|
|
7676
|
-
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;
|
|
7677
|
-
var rank = (i) => i.issue === null ? 2 : i.issue.open ? 0 : 1;
|
|
7678
|
-
var keptFirst = (a, b) => rank(a) - rank(b) || (a.issue?.number ?? 0) - (b.issue?.number ?? 0);
|
|
7679
|
-
var gone = (item) => item.issue === null ? { kind: "archive", id: item.id } : { kind: "close", id: item.id };
|
|
7680
|
-
var firstLine5 = (body) => body.split(/\r\n?|\n/, 1)[0] ?? "";
|
|
7681
|
-
function strays(have) {
|
|
7682
|
-
const byLine = /* @__PURE__ */ new Map();
|
|
7683
|
-
for (const item of have) {
|
|
7684
|
-
if (item.path !== null || item.issue === null || item.issue.body === null || !item.issue.labelled)
|
|
7685
|
-
continue;
|
|
7686
|
-
const line3 = firstLine5(item.issue.body);
|
|
7687
|
-
byLine.set(line3, [...byLine.get(line3) ?? [], item]);
|
|
7688
|
-
}
|
|
7689
|
-
for (const items of byLine.values()) items.sort(keptFirst);
|
|
7690
|
-
return byLine;
|
|
7691
|
-
}
|
|
7692
|
-
function unwantedPaths(want, have) {
|
|
7693
|
-
const wanted = new Set(want.map((w) => w.path));
|
|
7694
|
-
const paths = /* @__PURE__ */ new Set();
|
|
7695
|
-
for (const item of have)
|
|
7696
|
-
if (item.path !== null && !wanted.has(item.path)) paths.add(item.path);
|
|
7697
|
-
return [...paths];
|
|
7698
|
-
}
|
|
7699
|
-
function isGone(path, item, seen, opened) {
|
|
7700
|
-
return seen.has(path) || item.issue !== null && opened.get(item.issue.number) === path;
|
|
7701
|
-
}
|
|
7702
|
-
function planSync(want, have, seen = /* @__PURE__ */ new Set(), opened = /* @__PURE__ */ new Map()) {
|
|
7703
|
-
const byPath = /* @__PURE__ */ new Map();
|
|
7704
|
-
for (const item of have)
|
|
7705
|
-
if (item.path !== null)
|
|
7706
|
-
byPath.set(item.path, [...byPath.get(item.path) ?? [], item]);
|
|
7707
|
-
const kept = /* @__PURE__ */ new Map();
|
|
7708
|
-
const surplus = [];
|
|
7709
|
-
for (const [path, items] of byPath) {
|
|
7710
|
-
const [keep, ...rest] = [...items].sort(keptFirst);
|
|
7711
|
-
if (keep !== void 0) kept.set(path, keep);
|
|
7712
|
-
surplus.push(...rest.map(gone));
|
|
7713
|
-
}
|
|
7714
|
-
const left = strays(have);
|
|
7715
|
-
const steps = [];
|
|
7716
|
-
const wanted = /* @__PURE__ */ new Set();
|
|
7717
|
-
for (const w of want) {
|
|
7718
|
-
wanted.add(w.path);
|
|
7719
|
-
const item = kept.get(w.path) ?? left.get(w.body)?.[0];
|
|
7720
|
-
if (item === void 0) steps.push({ kind: "create", want: w });
|
|
7721
|
-
else if (item.issue === null)
|
|
7722
|
-
steps.push({ kind: "convert", id: item.id, want: w });
|
|
7723
|
-
else if (item.path === null || !item.issue.open || !item.issue.labelled || differs(item, w))
|
|
7724
|
-
steps.push({
|
|
7725
|
-
kind: "update",
|
|
7726
|
-
id: item.id,
|
|
7727
|
-
want: w,
|
|
7728
|
-
reopen: !item.issue.open
|
|
7729
|
-
});
|
|
7730
|
-
else steps.push({ kind: "unchanged", id: item.id });
|
|
7731
|
-
}
|
|
7732
|
-
for (const [path, item] of kept)
|
|
7733
|
-
if (!wanted.has(path))
|
|
7734
|
-
steps.push(
|
|
7735
|
-
isGone(path, item, seen, opened) ? gone(item) : { kind: "unchanged", id: item.id }
|
|
7736
|
-
);
|
|
7737
|
-
return [...steps, ...surplus];
|
|
7738
|
-
}
|
|
7739
|
-
function stillOpened(opened, have, seen, closed, created) {
|
|
7740
|
-
const items = /* @__PURE__ */ new Map();
|
|
7741
|
-
for (const item of have)
|
|
7742
|
-
if (item.issue !== null) items.set(item.issue.number, item.id);
|
|
7743
|
-
const next = /* @__PURE__ */ new Map();
|
|
7744
|
-
for (const [number, path] of opened) {
|
|
7745
|
-
const id = items.get(number);
|
|
7746
|
-
if (id !== void 0 && !closed.has(id) && !seen.has(path))
|
|
7747
|
-
next.set(number, path);
|
|
7748
|
-
}
|
|
7749
|
-
for (const [path, placed] of created) next.set(placed.number, path);
|
|
7750
|
-
return next;
|
|
7751
|
-
}
|
|
7752
|
-
function issuedAfter(steps, have, placed) {
|
|
7753
|
-
const byId = new Map(have.map((i) => [i.id, i]));
|
|
7754
|
-
const issued = /* @__PURE__ */ new Map();
|
|
7755
|
-
for (const step2 of steps) {
|
|
7756
|
-
if (step2.kind === "create" || step2.kind === "convert") {
|
|
7757
|
-
const p = placed.get(step2.want.path);
|
|
7758
|
-
if (p !== void 0) issued.set(step2.want.path, { ...p, body: null });
|
|
7759
|
-
} else if (step2.kind === "update" || step2.kind === "unchanged") {
|
|
7760
|
-
const item = byId.get(step2.id);
|
|
7761
|
-
const path = step2.kind === "update" ? step2.want.path : item?.path;
|
|
7762
|
-
if (item === void 0 || path == null || item.issue === null) continue;
|
|
7763
|
-
issued.set(path, {
|
|
7764
|
-
id: item.id,
|
|
7765
|
-
number: item.issue.number,
|
|
7766
|
-
body: item.issue.body
|
|
7767
|
-
});
|
|
7768
|
-
}
|
|
7769
|
-
}
|
|
7770
|
-
return issued;
|
|
7771
|
-
}
|
|
7772
|
-
function planBodies(bodies, issued) {
|
|
7773
|
-
const steps = [];
|
|
7774
|
-
for (const [path, body] of bodies) {
|
|
7775
|
-
const i = issued.get(path);
|
|
7776
|
-
if (i === void 0) continue;
|
|
7777
|
-
if (i.body === null || digestOf(i.body) !== digestOf(body))
|
|
7778
|
-
steps.push({ kind: "body", id: i.id, body });
|
|
7779
|
-
}
|
|
7780
|
-
return steps;
|
|
7781
|
-
}
|
|
7782
|
-
|
|
7783
7885
|
// src/commands/pulse.ts
|
|
7784
7886
|
var PROJECT_SCOPE = "project";
|
|
7785
7887
|
var NEEDS_LOGIN = "the pulse needs a GitHub login: run rness login";
|
|
@@ -7857,10 +7959,15 @@ async function filesOf2(rnessDir) {
|
|
|
7857
7959
|
return files;
|
|
7858
7960
|
}
|
|
7859
7961
|
var count2 = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
7860
|
-
function sayDone(ui, org, documents2, steps, writes) {
|
|
7861
|
-
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);
|
|
7862
7964
|
const reopened = steps.filter((s) => s.kind === "update" && s.reopen).length;
|
|
7863
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
|
+
);
|
|
7864
7971
|
if (n("convert") > 0)
|
|
7865
7972
|
ui.line(
|
|
7866
7973
|
"converted",
|
|
@@ -7873,11 +7980,12 @@ function sayDone(ui, org, documents2, steps, writes) {
|
|
|
7873
7980
|
).length;
|
|
7874
7981
|
const parts = [
|
|
7875
7982
|
["created", n("create")],
|
|
7983
|
+
["adopted", adopted],
|
|
7876
7984
|
["converted", n("convert")],
|
|
7877
7985
|
["updated", n("update") + bodyOnly],
|
|
7878
7986
|
[
|
|
7879
7987
|
"unchanged",
|
|
7880
|
-
documents2 - n("create") - n("convert") - n("update") - bodyOnly
|
|
7988
|
+
documents2 - n("create") - adopted - n("convert") - n("update") - bodyOnly
|
|
7881
7989
|
],
|
|
7882
7990
|
["archived", n("close") + n("archive")]
|
|
7883
7991
|
].filter(([, k]) => k > 0).map(([word, k]) => `${k} ${word}`);
|
|
@@ -7905,6 +8013,7 @@ async function syncBoard(c, board, ui, sayLayout) {
|
|
|
7905
8013
|
const changes = steps.filter((s) => s.kind !== "unchanged").length;
|
|
7906
8014
|
let writes = [];
|
|
7907
8015
|
let made = 0;
|
|
8016
|
+
let adopted = 0;
|
|
7908
8017
|
try {
|
|
7909
8018
|
const placed = /* @__PURE__ */ new Map();
|
|
7910
8019
|
const created = /* @__PURE__ */ new Map();
|
|
@@ -7914,7 +8023,9 @@ async function syncBoard(c, board, ui, sayLayout) {
|
|
|
7914
8023
|
const p = await fromGithub(c.provider.apply(board, step2));
|
|
7915
8024
|
if (p !== null && (step2.kind === "create" || step2.kind === "convert"))
|
|
7916
8025
|
placed.set(step2.want.path, p);
|
|
7917
|
-
if (p
|
|
8026
|
+
if (p?.adopted === true) adopted++;
|
|
8027
|
+
else if (p !== null && step2.kind === "create")
|
|
8028
|
+
created.set(step2.want.path, p);
|
|
7918
8029
|
if (step2.kind === "close" || step2.kind === "archive")
|
|
7919
8030
|
closed.add(step2.id);
|
|
7920
8031
|
if (step2.kind !== "unchanged") made++;
|
|
@@ -7953,7 +8064,7 @@ async function syncBoard(c, board, ui, sayLayout) {
|
|
|
7953
8064
|
{ cause: e }
|
|
7954
8065
|
);
|
|
7955
8066
|
}
|
|
7956
|
-
sayDone(ui, c.org, want.length, steps, writes);
|
|
8067
|
+
sayDone(ui, c.org, want.length, steps, writes, adopted);
|
|
7957
8068
|
}
|
|
7958
8069
|
async function pulseCreateCommand(opts, deps = {}) {
|
|
7959
8070
|
try {
|
|
@@ -8314,6 +8425,21 @@ async function statusCommand(tab, opts, terminal = { input: process.stdin, outpu
|
|
|
8314
8425
|
}
|
|
8315
8426
|
}
|
|
8316
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
|
+
|
|
8317
8443
|
// src/cli.ts
|
|
8318
8444
|
function buildProgram(state) {
|
|
8319
8445
|
const program = new Command().name("rness").description("Configuration-plane CLI for rness workspaces").version(VERSION, "-v, --version", "print the version").exitOverride().showHelpAfterError().configureOutput({
|
|
@@ -8405,6 +8531,9 @@ function buildProgram(state) {
|
|
|
8405
8531
|
program.command("git-credential", { hidden: true }).argument("<operation>").action(async (operation) => {
|
|
8406
8532
|
state.code = await gitCredentialCommand(operation);
|
|
8407
8533
|
});
|
|
8534
|
+
program.command("written-files", { hidden: true }).addOption(new Option("--cwd <dir>").hideHelp()).action(async (opts) => {
|
|
8535
|
+
state.code = await writtenFilesCommand(opts);
|
|
8536
|
+
});
|
|
8408
8537
|
program.command("hook", { hidden: true }).argument("<event>", "session-start, post-tool-use or session-end").action(async (event) => {
|
|
8409
8538
|
state.code = await hookCommand(event);
|
|
8410
8539
|
});
|
|
@@ -8594,4 +8723,4 @@ export {
|
|
|
8594
8723
|
OWN_COMMANDS,
|
|
8595
8724
|
catchUp
|
|
8596
8725
|
};
|
|
8597
|
-
//# sourceMappingURL=chunk-
|
|
8726
|
+
//# sourceMappingURL=chunk-7IVHL744.js.map
|