@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 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.0 (supported:
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
@@ -6,7 +6,7 @@ import {
6
6
  findDelegate,
7
7
  reportError,
8
8
  run
9
- } from "../chunk-HGT7BIWK.js";
9
+ } from "../chunk-7IVHL744.js";
10
10
 
11
11
  // src/bin/rness.ts
12
12
  import { pathToFileURL } from "url";
@@ -486,7 +486,7 @@ function parseRepoSpec(spec, org, host) {
486
486
  }
487
487
 
488
488
  // src/version.ts
489
- var VERSION = "0.15.0";
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
- /** A new document's issue: labelled, the first line as body, added to the board, Path first. */
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 firstLine3(text) {
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: firstLine3(stderr2) ?? `ssh exited with code ${code ?? "?"}`
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 firstLine4(text) {
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(firstLine4(e instanceof Error ? e.message : String(e)));
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 = firstLine4(e instanceof Error ? e.message : String(e));
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(firstLine4(e instanceof Error ? e.message : String(e)));
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 clonesToCommit(
6806
- ws.root,
6807
- cwd,
6808
- await loadManifest(ws.rnessDir)
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 !== null && step2.kind === "create") created.set(step2.want.path, 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-HGT7BIWK.js.map
8726
+ //# sourceMappingURL=chunk-7IVHL744.js.map