@davesheffer/hunch 0.32.0 → 0.33.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.
- package/README.md +10 -0
- package/dist/cli/index.js +52 -5
- package/dist/integrations/worktree.js +33 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -185,6 +185,16 @@ is **OS-agnostic**: paths are stored in POSIX form and an installed Hunch regist
|
|
|
185
185
|
server by package name, so Windows / macOS / Linux teammates share one memory without
|
|
186
186
|
per-machine fixups. → [docs](https://hunch-pi.vercel.app/docs#team)
|
|
187
187
|
|
|
188
|
+
### Branches & worktrees
|
|
189
|
+
|
|
190
|
+
Memory follows you across every branch and **git worktree**, with no per-worktree setup. The
|
|
191
|
+
private overlay is registered once at the repo's **git common dir** (shared by all worktrees), so
|
|
192
|
+
a fresh `git worktree add` on any branch sees the same decisions, bugs, and invariants. Create one
|
|
193
|
+
already wired in with **`hunch worktree <path> [-b <branch>]`**, or just run `hunch init` / `hunch
|
|
194
|
+
private` once and every worktree picks it up. Auto-captured decisions are tagged with their branch,
|
|
195
|
+
and concurrent overlay writes are serialized — so parallel worktrees never corrupt or lose memory.
|
|
196
|
+
`hunch doctor` confirms a worktree is sharing.
|
|
197
|
+
|
|
188
198
|
## Private memory (public repo, private context)
|
|
189
199
|
|
|
190
200
|
Open-source your code without open-sourcing your *reasoning*. **`hunch private`** sets up a
|
package/dist/cli/index.js
CHANGED
|
@@ -34,6 +34,7 @@ import { extractInlineIntent } from "../extractors/comments.js";
|
|
|
34
34
|
import { renderText, renderMarkdown, reportFailsStrict } from "../core/checkreport.js";
|
|
35
35
|
import { partitionReview, READY_MIN_GROUNDED } from "../core/reviewqueue.js";
|
|
36
36
|
import { installPostCommitHook, installPreCommitHook } from "../integrations/hooks.js";
|
|
37
|
+
import { ensureSharedOverlayPointer } from "../integrations/worktree.js";
|
|
37
38
|
import { installMergeDriver } from "../integrations/mergeDriver.js";
|
|
38
39
|
import { ensureGitignore, ignoreHunchMemory, HUNCH_MEMORY_DIRS } from "../integrations/gitignore.js";
|
|
39
40
|
import { writeCiWorkflow } from "../integrations/ciAction.js";
|
|
@@ -154,6 +155,15 @@ program
|
|
|
154
155
|
// case-split in ~/.claude.json, merge it so hunch resolves under either casing.
|
|
155
156
|
// No-op (silent) off Windows.
|
|
156
157
|
reportClaudeConfigHeal();
|
|
158
|
+
// Worktree-seamless: register any configured overlay at the git common dir so EVERY
|
|
159
|
+
// worktree of this repo auto-discovers it (also backfills pre-0.32 single-worktree setups),
|
|
160
|
+
// and note when we're initializing inside a linked worktree (memory is shared, not separate).
|
|
161
|
+
if (ensureSharedOverlayPointer(root, store.privateDir, store.privateAutoCommit)) {
|
|
162
|
+
console.log(` ✓ private overlay registered at the git common dir — shared by every worktree of this repo`);
|
|
163
|
+
}
|
|
164
|
+
if (isLinkedWorktree(root)) {
|
|
165
|
+
console.log(` ✓ linked worktree — sharing the repo's hooks + memory (no separate setup needed)`);
|
|
166
|
+
}
|
|
157
167
|
store.close();
|
|
158
168
|
console.log("\nNext: make a commit (the hook captures a decision), then ask your coding assistant \"why is X built this way?\"");
|
|
159
169
|
console.log("Cold start? Seed from history: hunch backfill --since 90d");
|
|
@@ -348,12 +358,8 @@ program
|
|
|
348
358
|
// (current + future, any branch) auto-discovers the same memory with zero per-worktree
|
|
349
359
|
// setup. Stored ABSOLUTE — a linked worktree resolves relative paths from its OWN root, so
|
|
350
360
|
// only an absolute path survives the move. Lives under .git/ (never tracked; nothing to ignore).
|
|
351
|
-
const commonDir = gitCommonDir(root);
|
|
352
361
|
let worktreeNote = "";
|
|
353
|
-
if (
|
|
354
|
-
const sharedDir = join(commonDir, "hunch");
|
|
355
|
-
mkdirSync(sharedDir, { recursive: true });
|
|
356
|
-
writeFileAtomic(join(sharedDir, "local.json"), JSON.stringify({ privateDir: hunchDir, autoCommit: !!opts.autoCommit }, null, 2) + "\n");
|
|
362
|
+
if (ensureSharedOverlayPointer(root, hunchDir, !!opts.autoCommit)) {
|
|
357
363
|
worktreeNote = ` ✓ registered in the git common dir — shared by every worktree of this repo, on any branch\n`;
|
|
358
364
|
}
|
|
359
365
|
// 4) route post-commit synthesis to the overlay (local hook, never committed)
|
|
@@ -397,6 +403,47 @@ program
|
|
|
397
403
|
` record sensitive items with private:true (hunch_record_decision / hunch_record_correction)\n` +
|
|
398
404
|
` override per-shell with HUNCH_PRIVATE_DIR; CI / public PR comments stay public-only.`);
|
|
399
405
|
});
|
|
406
|
+
// ---- worktree (one-command worktree wired into Hunch) ----------------------
|
|
407
|
+
program
|
|
408
|
+
.command("worktree <path>")
|
|
409
|
+
.description("Create a git worktree already wired into Hunch — it shares this repo's memory (the private overlay), with zero per-worktree setup.")
|
|
410
|
+
.option("-b, --branch <name>", "create the worktree on a NEW branch")
|
|
411
|
+
.option("--no-share", "don't register the overlay at the git common dir (the worktree won't see private memory)")
|
|
412
|
+
.action((path, opts) => {
|
|
413
|
+
const root = findRoot();
|
|
414
|
+
if (!isGitRepo(root))
|
|
415
|
+
return fail("`hunch worktree` needs a git repo");
|
|
416
|
+
const dest = resolve(root, path);
|
|
417
|
+
if (existsSync(dest))
|
|
418
|
+
return fail(`path already exists: ${dest}`);
|
|
419
|
+
// 1) create the worktree (on a new branch if asked, else a checkout of HEAD)
|
|
420
|
+
const r = spawnSync("git", ["-C", root, "worktree", "add", ...(opts.branch ? ["-b", opts.branch] : []), dest], { stdio: "inherit" });
|
|
421
|
+
if (r.status !== 0)
|
|
422
|
+
return fail("git worktree add failed");
|
|
423
|
+
// 2) register the overlay at the SHARED git common dir so the new worktree (and every
|
|
424
|
+
// other) auto-discovers the same memory — also backfills pre-0.32 single-worktree setups.
|
|
425
|
+
const store = new HunchStore(hunchPaths(root));
|
|
426
|
+
const overlay = store.privateDir;
|
|
427
|
+
const autoCommit = store.privateAutoCommit;
|
|
428
|
+
store.close();
|
|
429
|
+
let shareNote;
|
|
430
|
+
if (!opts.share) {
|
|
431
|
+
shareNote = ` · --no-share — the worktree will NOT see private memory`;
|
|
432
|
+
}
|
|
433
|
+
else if (overlay && ensureSharedOverlayPointer(root, overlay, autoCommit)) {
|
|
434
|
+
shareNote = ` ✓ memory shared via the git common dir — this worktree sees the same decisions / bugs / constraints`;
|
|
435
|
+
}
|
|
436
|
+
else if (overlay) {
|
|
437
|
+
shareNote = ` · could not register the shared overlay pointer (no git common dir?)`;
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
shareNote = ` · no private overlay configured — run \`hunch private\` to share memory across worktrees`;
|
|
441
|
+
}
|
|
442
|
+
console.log(`✓ worktree created → ${dest}${opts.branch ? ` (new branch ${opts.branch})` : ""}\n` +
|
|
443
|
+
`${shareNote}\n` +
|
|
444
|
+
` hooks + MCP server are shared (worktree-aware) — open your assistant in the new worktree to start.\n` +
|
|
445
|
+
` (needs \`hunch\` installed globally; a worktree has no node_modules of its own)`);
|
|
446
|
+
});
|
|
400
447
|
// ---- query ----------------------------------------------------------------
|
|
401
448
|
program
|
|
402
449
|
.command("query")
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worktree wiring — make a repo's private-overlay memory seamless across every git
|
|
3
|
+
* worktree (v0.32+). A worktree's gitignored `.hunch/local.json` pointer doesn't exist
|
|
4
|
+
* in a fresh checkout, so we register the overlay at the SHARED git common dir
|
|
5
|
+
* (`git rev-parse --git-common-dir`), which every linked worktree resolves identically.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync, mkdirSync } from "node:fs";
|
|
8
|
+
import { join, resolve } from "node:path";
|
|
9
|
+
import { gitCommonDir } from "../extractors/git.js";
|
|
10
|
+
import { writeFileAtomic } from "../core/io.js";
|
|
11
|
+
/** Register the resolved private overlay at the shared git common dir, so every worktree
|
|
12
|
+
* of this repo auto-discovers the same memory. Idempotent (writes only when missing or
|
|
13
|
+
* changed). Stored ABSOLUTE — a worktree resolves relative paths from its OWN root.
|
|
14
|
+
* Returns true once the shared pointer is in place (memory is worktree-shared), false when
|
|
15
|
+
* there's no overlay configured or no git common dir. Reused by `init`/`worktree`/`private`. */
|
|
16
|
+
export function ensureSharedOverlayPointer(root, overlayDir, autoCommit) {
|
|
17
|
+
const common = overlayDir ? gitCommonDir(root) : "";
|
|
18
|
+
if (!common || !overlayDir)
|
|
19
|
+
return false;
|
|
20
|
+
const file = join(common, "hunch", "local.json");
|
|
21
|
+
const want = JSON.stringify({ privateDir: resolve(overlayDir), autoCommit }, null, 2) + "\n";
|
|
22
|
+
try {
|
|
23
|
+
if (!(existsSync(file) && readFileSync(file, "utf8") === want)) {
|
|
24
|
+
mkdirSync(join(common, "hunch"), { recursive: true });
|
|
25
|
+
writeFileAtomic(file, want);
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=worktree.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@davesheffer/hunch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"author": "Dave Sheffer <dave.sheffer1@gmail.com>",
|
|
6
6
|
"description": "Hunch — an Engineering Memory OS: a persistent, git-native reasoning graph over a codebase, exposed to Claude Code via MCP.",
|