@davesheffer/hunch 1.20.1 → 1.20.2

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
@@ -171,7 +171,7 @@ repository, separate from the code repository. Hunch does not host it. Create a
171
171
  that every teammate can access, install Hunch on team machines and CI, then have one maintainer run:
172
172
 
173
173
  ```bash
174
- npm i -g @davesheffer/hunch@1.20.1
174
+ npm i -g @davesheffer/hunch@1.20.2
175
175
  hunch shared --repo git@github.com:acme/project-hunch-memory.git
176
176
  git add .gitignore .hunch/team.json
177
177
  git commit -m "chore: connect shared Hunch memory"
@@ -186,7 +186,7 @@ printed by Hunch. Omit `--migrate` for a new setup.
186
186
  After the pointer commit lands, teammates need Hunch installed and Git access to the memory repo:
187
187
 
188
188
  ```bash
189
- npm i -g @davesheffer/hunch@1.20.1
189
+ npm i -g @davesheffer/hunch@1.20.2
190
190
  git pull
191
191
  hunch init
192
192
  hunch doctor
@@ -592,12 +592,27 @@ export function commitAndPushHunch(hunchDir, message, opts) {
592
592
  else {
593
593
  run(["add", "--", "."]);
594
594
  }
595
- // SAFETY BACKSTOP (critical bug_overlay_clobber): a memory sync is PURELY ADDITIVE small
596
- // JSON. If the staged set contains a DELETION, rename, or any non-.json file, hunchDir is NOT
597
- // a clean overlay store most dangerously, the overlay was never its own git repo so `git -C`
598
- // walked UP to the PROJECT repo. Committing/pushing there would overwrite/delete the user's
599
- // code (we shipped exactly this). Refuse hard: unstage and bail without committing or pushing.
600
- const staged = stagedMemoryPaths(hunchDir, env);
595
+ // Snapshot replacement can remove stale per-record JSON. Only a push-capable
596
+ // private/shared store may stage those deletions: the publication boundary
597
+ // above has already proved that it is a standalone repository distinct from
598
+ // the protected code repository. `-u` is still scoped to this exact Hunch
599
+ // subtree, and the staged-set guard below admits only contained JSON deletes.
600
+ // Public stores retain the older no-deletion rule because they live inside
601
+ // the user's code repository.
602
+ if (opts.push !== false && !run([
603
+ "-c", `core.attributesFile=${gitNullDevice()}`,
604
+ "-c", "core.autocrlf=false",
605
+ "add", "-u", "--", ".",
606
+ ])) {
607
+ run(["reset", "-q", "--", "."]);
608
+ return null;
609
+ }
610
+ // SAFETY BACKSTOP (critical — bug_overlay_clobber): only contained JSON
611
+ // memory bytes may be committed. Renames, copies, type changes, local.json,
612
+ // derived artifacts and every path outside this exact Hunch subtree remain
613
+ // fail-closed. A deletion is admitted only for the already-proven standalone
614
+ // private/shared repository above; it can never delete protected source.
615
+ const staged = stagedMemoryPaths(hunchDir, env, opts.push !== false);
601
616
  if (staged === null) {
602
617
  try {
603
618
  execFileSync("git", ["-C", hunchDir, "reset", "-q", "--", "."], { stdio: "ignore", env });
@@ -608,7 +623,7 @@ export function commitAndPushHunch(hunchDir, message, opts) {
608
623
  // stays on disk and the next flush's `git add .` sweeps it up. The overlay path
609
624
  // stays loud: there it signals the escaped-to-project-repo misconfiguration.
610
625
  if (opts.push !== false) {
611
- console.error(`hunch: refusing to auto-commit memory at "${hunchDir}" — the staged change includes deletions or non-memory files, so this is not a clean overlay repo. Nothing was committed or pushed. (Use \`hunch shared --repo <url>\` so the overlay is its OWN git repo.)`);
626
+ console.error(`hunch: refusing to auto-commit memory at "${hunchDir}" — the staged change includes an unsafe deletion or non-memory file, so this is not a clean overlay repo. Nothing was committed or pushed. (Use \`hunch shared --repo <url>\` so the overlay is its OWN git repo.)`);
612
627
  }
613
628
  return null;
614
629
  }
@@ -744,7 +759,7 @@ export function headFileContent(root, rel) {
744
759
  return null;
745
760
  }
746
761
  }
747
- function stagedMemoryPaths(hunchDir, env) {
762
+ function stagedMemoryPaths(hunchDir, env, allowMemoryDeletions = false) {
748
763
  let out = "";
749
764
  let prefix = "";
750
765
  try {
@@ -755,8 +770,11 @@ function stagedMemoryPaths(hunchDir, env) {
755
770
  }
756
771
  if (!prefix)
757
772
  return null; // a Hunch layout is a scoped subdirectory, never the whole repository
773
+ // Snapshot ID churn is semantically one delete plus one add. Disable Git's
774
+ // heuristic rename presentation so the exact paths remain independently
775
+ // auditable against the contained-memory rules below.
758
776
  try {
759
- out = execFileSync("git", ["-C", hunchDir, "diff", "--cached", "--no-ext-diff", "--no-textconv", "--name-status"], { encoding: "utf8", env });
777
+ out = execFileSync("git", ["-C", hunchDir, "diff", "--cached", "--no-ext-diff", "--no-textconv", "--no-renames", "--name-status"], { encoding: "utf8", env });
760
778
  }
761
779
  catch {
762
780
  return null;
@@ -772,8 +790,8 @@ function stagedMemoryPaths(hunchDir, env) {
772
790
  const path = (parts[parts.length - 1] ?? "").trim();
773
791
  if (path.includes(".hunch-commit.lock"))
774
792
  continue; // transient lock dir, never a record
775
- if (!/^[AM]$/.test(status))
776
- return null; // only Add / Modify — any D/R/C/T → not a memory sync
793
+ if (!/^[AMD]$/.test(status) || (status === "D" && !allowMemoryDeletions))
794
+ return null;
777
795
  const normalizedPath = path.replace(/\\/g, "/");
778
796
  if (!normalizedPath.startsWith(prefix))
779
797
  return null; // never bless another staged JSON file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@davesheffer/hunch",
3
- "version": "1.20.1",
3
+ "version": "1.20.2",
4
4
  "mcpName": "io.github.davesheffer/hunch",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Dave Sheffer <dave.sheffer1@gmail.com>",
package/server.json CHANGED
@@ -7,13 +7,13 @@
7
7
  "source": "github"
8
8
  },
9
9
  "websiteUrl": "https://hunch-pi.vercel.app",
10
- "version": "1.20.1",
10
+ "version": "1.20.2",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "registryBaseUrl": "https://registry.npmjs.org",
15
15
  "identifier": "@davesheffer/hunch",
16
- "version": "1.20.1",
16
+ "version": "1.20.2",
17
17
  "runtimeHint": "npx",
18
18
  "packageArguments": [
19
19
  {