f03421d19ef3
pin koh3 3.0.108 and prove a stolen repo's offer stops on a clash instead of choosing a side (v3.0.70)
- time
- 2026-09-28 05:20 UTC · 2 weeks ago
- machine
- Junes-MacBook-Pro.local
- agent
- claude-opus-5-5
- session
- fix a2 review findings
- parent
- bb2b6cc5f7e2
↓ kepr-f03421d1.tar.gzatlas at this save
files changed3 files
package.json+1 −1tests/koh-version.txt+1 −1tests/kohsteal.test.ts+22 −0package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "kepr",3- "version": "3.0.69",3+ "version": "3.0.70",44 "private": true,55 "type": "module",66 "scripts": {tests/kohsteal.test.ts+22 −0
@@ -237,6 +237,28 @@237237 expect((await koh3(repoDir, ownerHome, ["steal"])).code).toBe(0);238238 expect(await readFile(join(repoDir, "README.md"), "utf8")).toContain("The thief's edit");239239 240+ // The other clone still rides its source. When both sides changed the same file,241+ // offer without a terminal refuses as steal would, and never picks a side itself:242+ // the file is named, steal is where to choose, and the source stays.243+ const other = join(fresh, REPO);244+ await writeFile(join(repoDir, "README.md"), "# shipped\n\nThe owner's edit.\n");245+ expect((await koh3(repoDir, ownerHome, ["save", "owner edits the readme"])).code).toBe(0);246+ await writeFile(join(other, "README.md"), "# shipped\n\nThe other clone's edit.\n");247+ expect((await koh3(other, thiefHome, ["save", "other clone edits"])).code).toBe(0);248+ const clashed = await koh3(other, thiefHome, ["offer"]);249+ expect(clashed.code).toBe(1);250+ expect(clashed.err).toContain(251+ 'README.md changed on both machines — run "koh steal" to choose, then offer',252+ );253+ expect(await readFile(join(other, "README.md"), "utf8")).toContain("other clone's edit");254+ expect((await koh3(other, thiefHome, ["remote"])).out).toContain(`${host}/${REPO}`);255+ // Choosing there upgrades the clone, and says where the version it gave up lives.256+ const chosen = await koh3(other, thiefHome, ["steal", "--theirs"]);257+ expect(chosen.code, chosen.err + chosen.out).toBe(0);258+ expect(chosen.out + chosen.err).toContain("now syncs with your bucket");259+ expect(chosen.out + chosen.err).toContain("your README.md is in");260+ expect(await readFile(join(other, "README.md"), "utf8")).toContain("The owner's edit");261+240262 // A repo the public side never serves clones from the bucket once signed in.241263 const second = join(root, "thief-two");242264 await mkdir(second, { recursive: true });