@coderook/cli 0.5.0 → 0.6.0

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.
Files changed (2) hide show
  1. package/dist/cli/src/cli.js +70 -1
  2. package/package.json +43 -42
@@ -270,9 +270,36 @@ async function commandStatus(parsed) {
270
270
  async function commandSubmit(parsed) {
271
271
  const folder = folderFor(parsed);
272
272
  const message = flagText(parsed, "m", "message") ?? "";
273
- const { link, baseline } = await reconcile(folder);
273
+ const { link, baseline, behind } = await reconcile(folder);
274
274
  const rules = await (0, worktree_js_1.readRules)(folder);
275
275
  const files = await (0, worktree_js_1.changedFiles)(folder, rules, baseline);
276
+ /*
277
+ An upgraded folder with no materialisation record and something that
278
+ differs from its recorded version is ambiguous in the one way that
279
+ matters: the difference is either work to send, or a copy left behind by
280
+ somebody's merge. Sending the second reverts their change.
281
+
282
+ While the folder is level with the project the question does not arise —
283
+ nothing can have merged underneath it — so only a folder that is behind
284
+ is stopped, and only until somebody says which it is.
285
+ */
286
+ if (link && !link.local && files.length && behind) {
287
+ if (await establishMaterialisation(folder, link)) {
288
+ link.local = { ...link.manifest };
289
+ await (0, config_js_1.writeLink)(folder, link);
290
+ }
291
+ else if (!hasFlag(parsed, "f", "force")) {
292
+ console.error(red("This folder was connected by an older version of CodeRook,"));
293
+ console.error("which did not record what it had received — and somebody");
294
+ console.error(`has saved since (the project is on v${behind.sequence}).\n`);
295
+ console.error(`${files.length} file${files.length === 1 ? " differs" : "s differ"} here:`);
296
+ for (const file of files.slice(0, 20))
297
+ console.error(` ${file.path}`);
298
+ console.error(`\nIf that is your work, send it with ${accent("coderook submit --force")}.` +
299
+ `\nIf it is an old copy, take theirs with ${accent("coderook get --replace")}.`);
300
+ return 1;
301
+ }
302
+ }
276
303
  if (!files.length) {
277
304
  // Having nothing to send is not the same as holding the whole version:
278
305
  // a merge can leave this folder with an older copy of somebody else's
@@ -415,6 +442,20 @@ The connection failed: ${text}`));
415
442
  ` · version holds ${bytes(result.sourceBytes)}`);
416
443
  return 0;
417
444
  }
445
+ /**
446
+ * Work out what an upgraded folder actually holds, or admit that it cannot.
447
+ *
448
+ * Returns the materialisation when the folder matches its recorded version
449
+ * exactly — which proves the manifest describes what is here — and null when
450
+ * anything differs, because a difference is either somebody's unsaved edit or
451
+ * a copy their merge left stale, and nothing on disk says which.
452
+ */
453
+ async function establishMaterialisation(folder, link) {
454
+ const rules = await (0, worktree_js_1.readRules)(folder);
455
+ const against = new Map(Object.entries(link.manifest));
456
+ const differing = await (0, worktree_js_1.changedFiles)(folder, rules, against);
457
+ return differing.length ? null : { ...link.manifest };
458
+ }
418
459
  async function commandGet(parsed) {
419
460
  const folder = folderFor(parsed);
420
461
  const { link } = await reconcile(folder);
@@ -434,6 +475,34 @@ async function commandGet(parsed) {
434
475
  version would actually change those files.
435
476
  */
436
477
  const replacing = hasFlag(parsed, "replace", "f", "force");
478
+ /*
479
+ A folder connected by a client older than the materialisation record has
480
+ only the Version manifest, which says what the project held — not what
481
+ was placed here. The two are the same only until somebody's merge makes
482
+ them differ, so assuming it would be the very guess that lost work in the
483
+ first place.
484
+
485
+ It can be established rather than assumed: if the folder matches its own
486
+ recorded version exactly, then it demonstrably holds that version and the
487
+ manifest is the materialisation. If it does not match, an edit cannot be
488
+ told from a stale copy, and fetching is refused until somebody says which
489
+ it is.
490
+ */
491
+ if (!link.local) {
492
+ const settled = await establishMaterialisation(folder, link);
493
+ if (settled) {
494
+ link.local = settled;
495
+ await (0, config_js_1.writeLink)(folder, link);
496
+ }
497
+ else if (!replacing) {
498
+ console.error(red("This folder was connected by an older version of CodeRook,"));
499
+ console.error("which did not record what it had received, so changed files here");
500
+ console.error("cannot be told apart from copies left behind by a merge.\n");
501
+ console.error(`Save them with ${accent("coderook submit")} if they are your work, or ` +
502
+ `take the\nsaved version exactly with ${accent("coderook get --replace")}.`);
503
+ return 1;
504
+ }
505
+ }
437
506
  if (link.local && !replacing) {
438
507
  const rules = await (0, worktree_js_1.readRules)(folder);
439
508
  const edited = await (0, worktree_js_1.changedFiles)(folder, rules, new Map(Object.entries(link.local)));
package/package.json CHANGED
@@ -1,42 +1,43 @@
1
- {
2
- "name": "@coderook/cli",
3
- "version": "0.5.0",
4
- "description": "CodeRook from the command line, on any operating system",
5
- "license": "SEE LICENSE IN LICENSE.txt",
6
- "homepage": "https://coderook.com",
7
- "bugs": {
8
- "url": "https://coderook.com/contact"
9
- },
10
- "keywords": [
11
- "coderook",
12
- "versioning",
13
- "backup",
14
- "cbx"
15
- ],
16
- "engines": {
17
- "node": ">=20.11.0"
18
- },
19
- "bin": {
20
- "coderook": "dist/cli/src/cli.js"
21
- },
22
- "files": [
23
- "dist"
24
- ],
25
- "scripts": {
26
- "build": "tsc -p tsconfig.json",
27
- "check": "tsc -p tsconfig.json --noEmit",
28
- "test": "tsc -p tsconfig.json && node --test --experimental-strip-types test/*.test.ts",
29
- "start": "node dist/cli/src/cli.js",
30
- "prepublishOnly": "npm run build",
31
- "test:e2e": "node test/e2e.mjs",
32
- "test:matrix": "node test/state-matrix.mjs",
33
- "test:attempt": "node test/attempt-identity.mjs",
34
- "test:get": "node test/get-safety.mjs",
35
- "test:live": "node test/e2e.mjs --allow-production && node test/state-matrix.mjs --allow-production && node test/get-safety.mjs --allow-production && node test/get-protects-edits.mjs --allow-production && node test/attempt-identity.mjs --allow-production",
36
- "test:getedits": "node test/get-protects-edits.mjs"
37
- },
38
- "devDependencies": {
39
- "@types/node": "24.10.1",
40
- "typescript": "5.9.3"
41
- }
42
- }
1
+ {
2
+ "name": "@coderook/cli",
3
+ "version": "0.6.0",
4
+ "description": "CodeRook from the command line, on any operating system",
5
+ "license": "SEE LICENSE IN LICENSE.txt",
6
+ "homepage": "https://coderook.com",
7
+ "bugs": {
8
+ "url": "https://coderook.com/contact"
9
+ },
10
+ "keywords": [
11
+ "coderook",
12
+ "versioning",
13
+ "backup",
14
+ "cbx"
15
+ ],
16
+ "engines": {
17
+ "node": ">=20.11.0"
18
+ },
19
+ "bin": {
20
+ "coderook": "dist/cli/src/cli.js"
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsc -p tsconfig.json",
27
+ "check": "tsc -p tsconfig.json --noEmit",
28
+ "test": "tsc -p tsconfig.json && node --test --experimental-strip-types test/*.test.ts",
29
+ "start": "node dist/cli/src/cli.js",
30
+ "prepublishOnly": "npm run build",
31
+ "test:e2e": "node test/e2e.mjs",
32
+ "test:matrix": "node test/state-matrix.mjs",
33
+ "test:attempt": "node test/attempt-identity.mjs",
34
+ "test:get": "node test/get-safety.mjs",
35
+ "test:live": "node test/e2e.mjs --allow-production && node test/state-matrix.mjs --allow-production && node test/get-safety.mjs --allow-production && node test/get-protects-edits.mjs --allow-production && node test/upgrade-migration.mjs --allow-production && node test/attempt-identity.mjs --allow-production",
36
+ "test:getedits": "node test/get-protects-edits.mjs",
37
+ "test:upgrade": "node test/upgrade-migration.mjs"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "24.10.1",
41
+ "typescript": "5.9.3"
42
+ }
43
+ }