@davesheffer/hunch 0.17.0 → 0.17.1
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/dist/cli/index.js
CHANGED
|
@@ -64,6 +64,7 @@ program
|
|
|
64
64
|
.option("--no-providers", "skip scaffolding non-Claude assistant configs (Cursor / VS Code / Codex / AGENTS.md)")
|
|
65
65
|
.option("--no-agent-hooks", "skip installing the Claude Code agent hooks (.claude/settings.json)")
|
|
66
66
|
.option("--firmness <level>", "agent-hook firmness: off | advisory | firm | strict")
|
|
67
|
+
.option("--private-sync", "post-commit synthesis writes captured decisions into the private overlay (HUNCH_PRIVATE_DIR), never the public repo")
|
|
67
68
|
.action((opts) => {
|
|
68
69
|
// Validate --firmness up front, before any side effects (indexing, git hooks,
|
|
69
70
|
// .mcp.json) or opening the store — a bad value must not leave a half-init.
|
|
@@ -92,8 +93,8 @@ program
|
|
|
92
93
|
console.log(` ⚠ ${res.skipped} file(s) could not be parsed (skipped)`);
|
|
93
94
|
}
|
|
94
95
|
if (isGitRepo(root)) {
|
|
95
|
-
const h = installPostCommitHook(root, inv.shell);
|
|
96
|
-
console.log(` ✓ post-commit hook ${h.action} (learning loop)`);
|
|
96
|
+
const h = installPostCommitHook(root, inv.shell, { private: opts.privateSync });
|
|
97
|
+
console.log(` ✓ post-commit hook ${h.action} (learning loop)${opts.privateSync ? " — syncs to the private overlay" : ""}`);
|
|
97
98
|
const m = installMergeDriver(root, inv.shell);
|
|
98
99
|
console.log(` ✓ team merge driver ${m.action}`);
|
|
99
100
|
// Auto-install the pre-commit guard by default (advisory: flags invariants
|
|
@@ -223,12 +224,17 @@ program
|
|
|
223
224
|
.option("--from-hook", "invoked by the git hook")
|
|
224
225
|
.option("--quiet", "minimal output")
|
|
225
226
|
.option("--force", "re-synthesize even if a decision already exists for the commit")
|
|
227
|
+
.option("--private", "write the synthesized decision into the private overlay (HUNCH_PRIVATE_DIR), not the public repo — for a repo whose memory is kept private")
|
|
226
228
|
.action(async (sha, opts) => {
|
|
227
229
|
const { store, root } = storeFor();
|
|
228
230
|
if (!isGitRepo(root))
|
|
229
231
|
return opts.quiet ? undefined : fail("sync needs a git repo");
|
|
232
|
+
if (opts.private && !store.hasPrivate) {
|
|
233
|
+
store.close();
|
|
234
|
+
return opts.quiet ? undefined : fail("--private needs HUNCH_PRIVATE_DIR set to a private store");
|
|
235
|
+
}
|
|
230
236
|
store.json.ensureDirs();
|
|
231
|
-
const r = await syncCommit(store, root, sha ?? headSha(root), { force: opts.force });
|
|
237
|
+
const r = await syncCommit(store, root, sha ?? headSha(root), { force: opts.force, private: opts.private });
|
|
232
238
|
if (r.status === "written") {
|
|
233
239
|
store.reindex();
|
|
234
240
|
// Don't rewrite CLAUDE.md from the hook — it would dirty the working tree
|
|
@@ -9,17 +9,21 @@ import { join, isAbsolute } from "node:path";
|
|
|
9
9
|
import { hooksDir } from "../extractors/git.js";
|
|
10
10
|
const MARK = "# >>> hunch post-commit >>>";
|
|
11
11
|
const ENDMARK = "# <<< hunch post-commit <<<";
|
|
12
|
-
function block(invocation) {
|
|
12
|
+
function block(invocation, opts = {}) {
|
|
13
|
+
// --private routes the auto-synthesized decision into the HUNCH_PRIVATE_DIR overlay
|
|
14
|
+
// instead of the public repo. The hook script is local (.git/hooks/), never committed,
|
|
15
|
+
// so a repo whose memory is kept private leaves no trace of this in the public tree.
|
|
16
|
+
const priv = opts.private ? " --private" : "";
|
|
13
17
|
return [
|
|
14
18
|
MARK,
|
|
15
19
|
'if [ -z "$HUNCH_SYNC" ]; then',
|
|
16
20
|
" export HUNCH_SYNC=1",
|
|
17
|
-
` ( ${invocation} sync --from-hook --quiet >/dev/null 2>&1 || true ) &`,
|
|
21
|
+
` ( ${invocation} sync --from-hook --quiet${priv} >/dev/null 2>&1 || true ) &`,
|
|
18
22
|
"fi",
|
|
19
23
|
ENDMARK,
|
|
20
24
|
].join("\n");
|
|
21
25
|
}
|
|
22
|
-
export function installPostCommitHook(root, invocation) {
|
|
26
|
+
export function installPostCommitHook(root, invocation, opts = {}) {
|
|
23
27
|
const dir = hooksDir(root);
|
|
24
28
|
// `git rev-parse --git-path hooks` returns a path relative to the repo in a
|
|
25
29
|
// normal checkout, but an ABSOLUTE one inside a linked worktree (the shared
|
|
@@ -28,7 +32,7 @@ export function installPostCommitHook(root, invocation) {
|
|
|
28
32
|
const abs = isAbsolute(dir) ? dir : join(root, dir);
|
|
29
33
|
mkdirSync(abs, { recursive: true });
|
|
30
34
|
const hookPath = join(abs, "post-commit");
|
|
31
|
-
const blk = block(invocation);
|
|
35
|
+
const blk = block(invocation, opts);
|
|
32
36
|
if (!existsSync(hookPath)) {
|
|
33
37
|
writeFileSync(hookPath, `#!/bin/sh\n${blk}\n`);
|
|
34
38
|
chmodSync(hookPath, 0o755);
|
|
@@ -119,7 +119,12 @@ export async function syncCommit(store, root, sha, opts = {}) {
|
|
|
119
119
|
},
|
|
120
120
|
date: meta.date, // the commit date
|
|
121
121
|
};
|
|
122
|
-
|
|
122
|
+
// Route to the PRIVATE overlay when asked (post-commit sync in a repo whose memory
|
|
123
|
+
// is kept private) — keeps auto-captured decisions out of the public repo entirely.
|
|
124
|
+
if (opts.private)
|
|
125
|
+
store.putPrivate("decisions", decision);
|
|
126
|
+
else
|
|
127
|
+
store.json.put("decisions", decision);
|
|
123
128
|
return { status: "written", decision, provider: provider.name };
|
|
124
129
|
}
|
|
125
130
|
/** Capture a Bug from a test failure. Suspects are ranked churn×recency×fan-in. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@davesheffer/hunch",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.1",
|
|
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.",
|