@coderook/cli 0.25.2 → 0.25.3

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.
@@ -2,7 +2,7 @@
2
2
  "name": "coderook",
3
3
  "displayName": "CodeRook",
4
4
  "description": "Save, browse and restore whole-snapshot versions of a project on CodeRook, from Claude Code.",
5
- "version": "0.25.2",
5
+ "version": "0.25.3",
6
6
  "author": {
7
7
  "name": "ACCA Gaming Productions",
8
8
  "url": "https://coderook.com"
package/README.md CHANGED
@@ -109,12 +109,15 @@ somebody looking for where they can save needs to see the one they cannot.
109
109
  ## Ignore rules
110
110
 
111
111
  ```
112
- cbx rules show the rules in force
113
- cbx rules --init write a starter .gitignore
114
- cbx rules --suggest what is here that probably should not be sent
115
- cbx rules --suggest --apply add the confident ones
112
+ cbx ignore show the rules in force
113
+ cbx ignore --init write a starter .gitignore
114
+ cbx ignore --suggest what is here that probably should not be sent
115
+ cbx ignore --suggest --apply add the confident ones
116
116
  ```
117
117
 
118
+ `cbx rules` is the same command under another name, so anything already
119
+ written against it keeps working.
120
+
118
121
  `--suggest` looks at what the folder would actually send and names the
119
122
  dependency directories, virtual environments and build output in it, with how
120
123
  much each is costing you. Lines marked `+` are safe to assume and are the ones
@@ -21,6 +21,7 @@ exports.versionsInOrder = versionsInOrder;
21
21
  exports.stamp = stamp;
22
22
  exports.importRef = importRef;
23
23
  exports.quotePath = quotePath;
24
+ exports.refPlacements = refPlacements;
24
25
  /**
25
26
  * Git's constant hash for the empty tree.
26
27
  *
@@ -223,3 +224,35 @@ function quotePath(filePath) {
223
224
  .replaceAll("\n", "\\n")
224
225
  .replaceAll("\r", "\\r")}"`;
225
226
  }
227
+ /**
228
+ * Where each ref git asked for has to be pointed, once the commits exist.
229
+ *
230
+ * Git holds the helper to the whole batch: it names the refs it wants, and
231
+ * if any one of them does not exist when the stream ends it aborts the fetch
232
+ * — `could not read ref refs/coderook/<name>` — and the clone fails with
233
+ * nothing to show for it.
234
+ *
235
+ * Emitting commits is not enough to guarantee that, because a commit is
236
+ * written once per *version* while refs are per *line*. Two lines can share
237
+ * one version — making a line from where another already is does exactly
238
+ * that — so a single commit is expected to satisfy two refs, and only the
239
+ * first is written. A line whose version arrived in an earlier fetch has no
240
+ * commit emitted for it at all, and lands in the same hole.
241
+ *
242
+ * So each ref is stated separately rather than inferred from the commits.
243
+ * A ref whose head has no mark is reported rather than guessed at: pointing
244
+ * it somewhere plausible would hand back a branch that is quietly not the
245
+ * one asked for.
246
+ */
247
+ function refPlacements(wanted, markOfVersion) {
248
+ const placed = [];
249
+ const unplaceable = [];
250
+ for (const [ref, head] of wanted) {
251
+ const mark = markOfVersion.get(head);
252
+ if (mark === undefined)
253
+ unplaceable.push(ref);
254
+ else
255
+ placed.push({ ref, mark });
256
+ }
257
+ return { placed, unplaceable };
258
+ }
@@ -529,9 +529,40 @@ async function doImport(refs, url) {
529
529
  let nextMark = 1;
530
530
  for (const mark of commitMark.values())
531
531
  nextMark = Math.max(nextMark, mark + 1);
532
+ /*
533
+ Point every ref git asked for at the commit its line's head became.
534
+
535
+ Which ref needs what is worked out in `refPlacements`; this only says it.
536
+ `reset` is idempotent, so naming a ref that a commit in this stream has
537
+ already set costs a line and changes nothing.
538
+ */
539
+ const settleRefs = () => {
540
+ const { placed, unplaceable } = (0, git_history_js_1.refPlacements)(wanted, commitMark);
541
+ for (const { ref, mark } of placed) {
542
+ send(`reset ${(0, git_history_js_1.importRef)(ref)}`);
543
+ send(`from :${mark}`);
544
+ }
545
+ for (const ref of unplaceable) {
546
+ say(` could not place ${ref}: no commit for its head version`);
547
+ }
548
+ };
532
549
  const fresh = order.filter((version) => !commitMark.has(version.id));
533
550
  if (!fresh.length) {
534
551
  say(`Already up to date with ${slug}.`);
552
+ /*
553
+ Still has to name the refs. "Nothing new to fetch" and "this ref does
554
+ not exist" are different answers, and a line added since the last fetch
555
+ is the first case while looking like the second.
556
+
557
+ The marks table is loaded first because the refs are placed by mark,
558
+ and without it those marks name nothing in this stream.
559
+ */
560
+ if (marks) {
561
+ send("feature done");
562
+ send(`feature import-marks-if-exists=${marks.file.replaceAll("\\", "/")}`);
563
+ send(`feature export-marks=${marks.file.replaceAll("\\", "/")}`);
564
+ settleRefs();
565
+ }
535
566
  send("done");
536
567
  return;
537
568
  }
@@ -612,6 +643,8 @@ async function doImport(refs, url) {
612
643
  say(` ${done}/${fresh.length} versions`);
613
644
  }
614
645
  }
646
+ /* Every ref git asked for, named outright now the commits exist. */
647
+ settleRefs();
615
648
  /*
616
649
  Releases come back as tags, because that is the same statement in the
617
650
  other vocabulary: a version somebody gave a name to.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coderook/cli",
3
- "version": "0.25.2",
3
+ "version": "0.25.3",
4
4
  "description": "CodeRook from the command line, on any operating system",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "homepage": "https://coderook.com",