@davesheffer/hunch 0.38.1 โ 0.38.3
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 +5 -0
- package/dist/cli/index.js +59 -33
- package/dist/extractors/git.js +53 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# ๐ง Hunch โ Architectural Conformance for AI code
|
|
2
2
|
|
|
3
|
+
[](https://github.com/davesheffer/hunch)
|
|
3
4
|
[](https://www.npmjs.com/package/@davesheffer/hunch)
|
|
4
5
|
[](https://www.npmjs.com/package/@davesheffer/hunch)
|
|
5
6
|
[](LICENSE)
|
|
@@ -27,6 +28,10 @@ hunch conform --strict # โ
/โ deterministic gate โ wire into CI; runs o
|
|
|
27
28
|
> dbQuery โ VIOLATED ยท why: the Mar-2025 N+1 meltdown ยท prevents recurrence of bug_0317."* See
|
|
28
29
|
> [`demo/architectural-conformance.sh`](demo/architectural-conformance.sh).
|
|
29
30
|
|
|
31
|
+
**It works both ways โ prevent *and* catch โ and you need both:**
|
|
32
|
+
- **Prevent** โ in a reproducible benchmark ([`bench/`](bench/architectural-conformance.md): n=90, Haiku/Sonnet/Opus, 3 invariant classes), the recorded invariant in context cut architectural violations **58% โ 16%** overall (Sonnet **67% โ 0%**). But prevention is *necessary, not sufficient*: **even Opus ignored a layering rule 60% of the time when told.** Each violation passes a linter clean.
|
|
33
|
+
- **Catch** โ which is exactly why the deterministic gate exists. `hunch check --strict` (the pre-commit hook + the [`hunch ci`](https://hunch-pi.vercel.app/docs#ci) PR gate) **blocks** what the model ignores โ with the receipt, **no model in the gate**. Injection helps; the gate is the guarantee.
|
|
34
|
+
|
|
30
35
|
<sub>Works with **Claude Code, Cursor, Copilot, Windsurf & Google Antigravity** from one shared, git-native graph.</sub>
|
|
31
36
|
|
|
32
37
|
### ๐ **[Read the full documentation โ hunch-pi.vercel.app/docs](https://hunch-pi.vercel.app/docs)**
|
package/dist/cli/index.js
CHANGED
|
@@ -79,7 +79,8 @@ program
|
|
|
79
79
|
.option("--no-providers", "skip scaffolding non-Claude assistant configs (Cursor / VS Code / Codex / AGENTS.md)")
|
|
80
80
|
.option("--no-agent-hooks", "skip installing the Claude Code agent hooks (.claude/settings.json)")
|
|
81
81
|
.option("--firmness <level>", "agent-hook firmness: off | advisory | firm | strict")
|
|
82
|
-
.option("--private-sync", "post-commit synthesis writes captured decisions into the
|
|
82
|
+
.option("--private-sync", "post-commit synthesis writes captured decisions into the overlay repo (HUNCH_PRIVATE_DIR), never the public store")
|
|
83
|
+
.option("--shared-sync", "alias of --private-sync (for teams using one shared overlay repo for any code repo)")
|
|
83
84
|
.option("--auto-commit", "opt-in: the post-commit hook also git add+commit+pushes the captured decision (the repo it landed in)")
|
|
84
85
|
.action((opts) => {
|
|
85
86
|
// Validate --firmness up front, before any side effects (indexing, git hooks,
|
|
@@ -109,8 +110,9 @@ program
|
|
|
109
110
|
console.log(` โ ${res.skipped} file(s) could not be parsed (skipped)`);
|
|
110
111
|
}
|
|
111
112
|
if (isGitRepo(root)) {
|
|
112
|
-
const
|
|
113
|
-
|
|
113
|
+
const syncToOverlay = !!(opts.privateSync || opts.sharedSync);
|
|
114
|
+
const h = installPostCommitHook(root, inv.shell, { private: syncToOverlay, commit: opts.autoCommit });
|
|
115
|
+
console.log(` โ post-commit hook ${h.action} (learning loop)${syncToOverlay ? " โ syncs to the shared overlay" : ""}${opts.autoCommit ? " โ auto-commit+push on" : ""}`);
|
|
114
116
|
const m = installMergeDriver(root, inv.shell);
|
|
115
117
|
console.log(` โ team merge driver ${m.action}`);
|
|
116
118
|
// Auto-install the pre-commit guard by default (advisory: flags invariants
|
|
@@ -170,6 +172,7 @@ program
|
|
|
170
172
|
store.close();
|
|
171
173
|
console.log("\nNext: make a commit (the hook captures a decision), then ask your coding assistant \"why is X built this way?\"");
|
|
172
174
|
console.log("Cold start? Seed from history: hunch backfill --since 90d");
|
|
175
|
+
console.log("\nโญ If Hunch earns its keep, a star helps others find it โ https://github.com/davesheffer/hunch");
|
|
173
176
|
});
|
|
174
177
|
// ---- index ----------------------------------------------------------------
|
|
175
178
|
program
|
|
@@ -265,7 +268,8 @@ program
|
|
|
265
268
|
.option("--from-hook", "invoked by the git hook")
|
|
266
269
|
.option("--quiet", "minimal output")
|
|
267
270
|
.option("--force", "re-synthesize even if a decision already exists for the commit")
|
|
268
|
-
.option("--private", "write the synthesized decision into the
|
|
271
|
+
.option("--private", "write the synthesized decision into the configured overlay (HUNCH_PRIVATE_DIR), not the public store")
|
|
272
|
+
.option("--overlay", "alias of --private")
|
|
269
273
|
.option("--commit", "after a capture, also git add+commit+push the repo the decision landed in (opt-in; best-effort) โ the private store under --private, else this repo")
|
|
270
274
|
.option("--deep", "Deep Synthesis: ensemble every available subscription CLI and reconcile their drafts (agreement-weighted, advisory). Slower; subscription-only")
|
|
271
275
|
.option("--verify", "Critic pass: audit the draft against its commit, prune unsupported alternatives/consequences, down-weight weak grounding (extra subscription call; advisory)")
|
|
@@ -274,12 +278,13 @@ program
|
|
|
274
278
|
const { store, root } = storeFor();
|
|
275
279
|
if (!isGitRepo(root))
|
|
276
280
|
return opts.quiet ? undefined : fail("sync needs a git repo");
|
|
277
|
-
|
|
281
|
+
const toOverlay = !!(opts.private || opts.overlay);
|
|
282
|
+
if (toOverlay && !store.hasPrivate) {
|
|
278
283
|
store.close();
|
|
279
|
-
return opts.quiet ? undefined : fail("--private needs HUNCH_PRIVATE_DIR set to
|
|
284
|
+
return opts.quiet ? undefined : fail("--private/--overlay needs HUNCH_PRIVATE_DIR set to an overlay store");
|
|
280
285
|
}
|
|
281
286
|
store.json.ensureDirs();
|
|
282
|
-
const r = await syncCommit(store, root, sha ?? headSha(root), { force: opts.force, private:
|
|
287
|
+
const r = await syncCommit(store, root, sha ?? headSha(root), { force: opts.force, private: toOverlay, deep: opts.deep, verify: opts.verify, samples: parseSamples(opts.samples) });
|
|
283
288
|
if (r.status === "written") {
|
|
284
289
|
store.reindex();
|
|
285
290
|
// Don't rewrite grounding from the hook โ it would dirty the working tree on
|
|
@@ -295,7 +300,7 @@ program
|
|
|
295
300
|
// just no-ops. Stage ONLY the hunch dir (never sweep unrelated working-tree
|
|
296
301
|
// changes), and set HUNCH_SYNC=1 so the commit we create can't re-trigger this
|
|
297
302
|
// hook (no recursion, including on a manual `hunch sync --commit`).
|
|
298
|
-
const commitTarget = opts.commit ? (
|
|
303
|
+
const commitTarget = opts.commit ? (toOverlay ? store.privateDir : hunchPaths(root).hunch) : undefined;
|
|
299
304
|
if (commitTarget) {
|
|
300
305
|
commitAndPushHunch(commitTarget, `hunch: capture ${r.decision?.id ?? "decision"}`);
|
|
301
306
|
if (!opts.quiet)
|
|
@@ -309,29 +314,21 @@ program
|
|
|
309
314
|
}
|
|
310
315
|
store.close();
|
|
311
316
|
});
|
|
312
|
-
|
|
313
|
-
program
|
|
314
|
-
.command("private [dir]")
|
|
315
|
-
.description("Enable a PRIVATE memory overlay โ sensitive decisions/bugs/constraints kept in a separate location, unioned into local queries, never committed here. Writes a gitignored .hunch/local.json so it's auto-detected (no env var needed).")
|
|
316
|
-
.option("--repo <url>", "clone a private git repo to use as the store (into ./.hunch-private)")
|
|
317
|
-
.option("--no-hook", "don't switch the post-commit hook to private sync")
|
|
318
|
-
.option("--no-auto-commit", "DON'T auto commit+push the overlay after each capture (default: ON โ fully automated two-way sync, never push by hand)")
|
|
319
|
-
.option("--sync", "flush the configured private store now (git add+commit+push) โ catches records made via MCP between commits")
|
|
320
|
-
.option("--migrate", "ONE-TIME: move this repo's EXISTING public .hunch memory into the overlay, then make the public repo code-only โ untrack + gitignore the memory tree and regenerate grounding so no memory is published here")
|
|
321
|
-
.action((dir, opts) => {
|
|
317
|
+
function configureOverlay(dir, opts, mode) {
|
|
322
318
|
const root = findRoot();
|
|
319
|
+
const paths = hunchPaths(root);
|
|
320
|
+
const commandName = mode === "private" ? "private" : "shared";
|
|
323
321
|
if (opts.sync) {
|
|
324
322
|
const s = new HunchStore(hunchPaths(root));
|
|
325
323
|
const target = s.privateDir;
|
|
326
324
|
s.close();
|
|
327
325
|
if (!target)
|
|
328
|
-
return fail(
|
|
329
|
-
commitAndPushHunch(target, "hunch: sync
|
|
330
|
-
console.log(`โ flushed
|
|
326
|
+
return fail(`no overlay configured โ run \`hunch ${commandName}\` first`);
|
|
327
|
+
commitAndPushHunch(target, "hunch: sync overlay memory");
|
|
328
|
+
console.log(`โ flushed overlay store โ ${target}`);
|
|
331
329
|
return;
|
|
332
330
|
}
|
|
333
|
-
|
|
334
|
-
// 1) resolve the private store's hunch dir (holds decisions/, bugs/, โฆ)
|
|
331
|
+
// 1) resolve the overlay store's hunch dir (holds decisions/, bugs/, โฆ)
|
|
335
332
|
let hunchDir;
|
|
336
333
|
if (opts.repo) {
|
|
337
334
|
const dest = join(root, ".hunch-private");
|
|
@@ -352,6 +349,13 @@ program
|
|
|
352
349
|
// multiple machines/worktrees merge by RECORD ID (no manual conflict resolution) when the
|
|
353
350
|
// two-way auto-sync pulls before pushing. The overlay repo root is the parent of its .hunch.
|
|
354
351
|
const overlayRoot = hunchPathsForDir(hunchDir).root;
|
|
352
|
+
// CRITICAL (bug_overlay_clobber): with --auto-commit, the overlay MUST be its own git repo.
|
|
353
|
+
// Otherwise the post-commit auto-commit (commitAndPushHunch) runs `git -C overlayDir โฆ` which
|
|
354
|
+
// walks UP to the PROJECT repo and can commit memory over your code. Initialize a standalone
|
|
355
|
+
// repo when one isn't there (a local repo with no remote just accumulates commits โ safe).
|
|
356
|
+
if (opts.autoCommit && !isGitRepo(overlayRoot)) {
|
|
357
|
+
spawnSync("git", ["init", "-q", overlayRoot], { stdio: "ignore" });
|
|
358
|
+
}
|
|
355
359
|
if (isGitRepo(overlayRoot))
|
|
356
360
|
installMergeDriver(overlayRoot, inv.shell);
|
|
357
361
|
// 3) record the path in a GITIGNORED local config โ auto-detected, no env var, and
|
|
@@ -370,7 +374,7 @@ program
|
|
|
370
374
|
// only an absolute path survives the move. Lives under .git/ (never tracked; nothing to ignore).
|
|
371
375
|
let worktreeNote = "";
|
|
372
376
|
if (ensureSharedOverlayPointer(root, hunchDir, !!opts.autoCommit)) {
|
|
373
|
-
worktreeNote =
|
|
377
|
+
worktreeNote = " โ registered in the git common dir โ shared by every worktree of this repo, on any branch\n";
|
|
374
378
|
}
|
|
375
379
|
// 4) route post-commit synthesis to the overlay (local hook, never committed)
|
|
376
380
|
let hookNote = "";
|
|
@@ -404,18 +408,40 @@ program
|
|
|
404
408
|
` next: review, then commit the PUBLIC repo:\n` +
|
|
405
409
|
` git add -A && git commit -m "chore: move engineering memory to a private overlay" && git push\n`;
|
|
406
410
|
}
|
|
407
|
-
|
|
408
|
-
|
|
411
|
+
const lead = mode === "private"
|
|
412
|
+
? `โ private overlay enabled โ ${hunchDir}\n`
|
|
413
|
+
: `โ shared overlay enabled โ ${hunchDir}\n`;
|
|
414
|
+
const tail = mode === "private"
|
|
415
|
+
? " record sensitive items with private:true (hunch_record_decision / hunch_record_correction)\n override per-shell with HUNCH_PRIVATE_DIR; CI / public PR comments stay public-only."
|
|
416
|
+
: " this works for any repo (public or private): one shared memory source across teammates, branches, and worktrees.\n override per-shell with HUNCH_PRIVATE_DIR if needed.";
|
|
417
|
+
console.log(lead +
|
|
418
|
+
" โ recorded in .hunch/local.json (gitignored) โ auto-detected, no env var or shell-profile edit\n" +
|
|
409
419
|
worktreeNote +
|
|
410
420
|
hookNote +
|
|
411
421
|
migrateNote +
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
422
|
+
tail);
|
|
423
|
+
}
|
|
424
|
+
program
|
|
425
|
+
.command("private [dir]")
|
|
426
|
+
.description("Enable a PRIVATE memory overlay โ sensitive decisions/bugs/constraints kept in a separate location, unioned into local queries, never committed here. Writes a gitignored .hunch/local.json so it's auto-detected (no env var needed).")
|
|
427
|
+
.option("--repo <url>", "clone a private git repo to use as the store (into ./.hunch-private)")
|
|
428
|
+
.option("--no-hook", "don't switch the post-commit hook to private sync")
|
|
429
|
+
.option("--no-auto-commit", "DON'T auto commit+push the overlay after each capture (default: ON โ fully automated two-way sync, never push by hand)")
|
|
430
|
+
.option("--sync", "flush the configured private store now (git add+commit+push) โ catches records made via MCP between commits")
|
|
431
|
+
.option("--migrate", "ONE-TIME: move this repo's EXISTING public .hunch memory into the overlay, then make the public repo code-only โ untrack + gitignore the memory tree and regenerate grounding so no memory is published here")
|
|
432
|
+
.action((dir, opts) => configureOverlay(dir, opts, "private"));
|
|
433
|
+
program
|
|
434
|
+
.command("shared [dir]")
|
|
435
|
+
.description("Enable a SHARED memory overlay repo for this project (works for any repo: private or public). Memory stays in one location, shared across teammates, branches, and worktrees.")
|
|
436
|
+
.option("--repo <url>", "clone a git repo to use as the shared memory store (into ./.hunch-private)")
|
|
437
|
+
.option("--no-hook", "don't switch the post-commit hook to overlay sync")
|
|
438
|
+
.option("--no-auto-commit", "DON'T auto commit+push the overlay after each capture (default: ON โ fully automated two-way sync)")
|
|
439
|
+
.option("--sync", "flush the configured overlay store now (git add+commit+push)")
|
|
440
|
+
.action((dir, opts) => configureOverlay(dir, opts, "shared"));
|
|
415
441
|
// ---- worktree (one-command worktree wired into Hunch) ----------------------
|
|
416
442
|
program
|
|
417
443
|
.command("worktree <path>")
|
|
418
|
-
.description("Create a git worktree already wired into Hunch โ it shares this repo's memory
|
|
444
|
+
.description("Create a git worktree already wired into Hunch โ it shares this repo's memory overlay, with zero per-worktree setup.")
|
|
419
445
|
.option("-b, --branch <name>", "create the worktree on a NEW branch")
|
|
420
446
|
.option("--no-share", "don't register the overlay at the git common dir (the worktree won't see private memory)")
|
|
421
447
|
.option("--no-index", "don't build the new worktree's code graph (skip if you'll index later)")
|
|
@@ -447,7 +473,7 @@ program
|
|
|
447
473
|
shareNote = ` ยท could not register the shared overlay pointer (no git common dir?)`;
|
|
448
474
|
}
|
|
449
475
|
else {
|
|
450
|
-
shareNote = ` ยท no
|
|
476
|
+
shareNote = ` ยท no overlay configured โ run \`hunch shared\` (or \`hunch private\`) to share memory across worktrees`;
|
|
451
477
|
}
|
|
452
478
|
// 3) build the new worktree's CODE GRAPH (symbols/edges โ blast-radius / dependents).
|
|
453
479
|
// Indexed IN-PROCESS (uses THIS install's tree-sitter, so the worktree needs no
|
|
@@ -1752,7 +1778,7 @@ program
|
|
|
1752
1778
|
console.log(`hunch: ${c.symbols} symbols, ${c.edges} edges, ${c.components} components, ${c.decisions} decisions, ${c.bugs} bugs, ${c.constraints} constraints`);
|
|
1753
1779
|
console.log(store.privateDir
|
|
1754
1780
|
? `private: on โ ${store.privateDir} (local overlay โ unioned into queries; never committed or posted publicly)`
|
|
1755
|
-
: dim(`private: off โ run \`hunch private\` to
|
|
1781
|
+
: dim(`private: off โ run \`hunch shared\` (or \`hunch private\`) to use one overlay repo across teammates/worktrees (or set HUNCH_PRIVATE_DIR)`));
|
|
1756
1782
|
// Worktree posture: linked worktrees share ONE memory via the git common dir. Only
|
|
1757
1783
|
// surfaced in a linked worktree (no noise in a normal single checkout), so a
|
|
1758
1784
|
// "memory missing here" symptom has an obvious cause + fix.
|
|
@@ -1761,7 +1787,7 @@ program
|
|
|
1761
1787
|
const sharedPtr = !!common && existsSync(join(common, "hunch", "local.json"));
|
|
1762
1788
|
console.log(store.privateDir
|
|
1763
1789
|
? `worktree: linked โ sharing the repo's memory${sharedPtr ? " via the git common dir" : ""}`
|
|
1764
|
-
: dim(`worktree: linked, but no overlay resolved here โ run \`hunch private\` once (any worktree) so all worktrees share it`));
|
|
1790
|
+
: dim(`worktree: linked, but no overlay resolved here โ run \`hunch shared\` (or \`hunch private\`) once (any worktree) so all worktrees share it`));
|
|
1765
1791
|
}
|
|
1766
1792
|
// Semantic search is opt-in and local. Report availability + coverage without
|
|
1767
1793
|
// loading the model (selectEmbedder only probes; embeddingStats just counts rows).
|
package/dist/extractors/git.js
CHANGED
|
@@ -43,13 +43,30 @@ export function commitAndPushHunch(hunchDir, message) {
|
|
|
43
43
|
catch { /* best-effort: nothing staged / not a repo / offline */ }
|
|
44
44
|
};
|
|
45
45
|
run(["add", "--", "."]);
|
|
46
|
-
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
// SAFETY BACKSTOP (critical โ bug_overlay_clobber): a memory sync is PURELY ADDITIVE small
|
|
47
|
+
// JSON. If the staged set contains a DELETION, rename, or any non-.json file, hunchDir is NOT
|
|
48
|
+
// a clean overlay store โ most dangerously, the overlay was never its own git repo so `git -C`
|
|
49
|
+
// walked UP to the PROJECT repo. Committing/pushing there would overwrite/delete the user's
|
|
50
|
+
// code (we shipped exactly this). Refuse hard: unstage and bail without committing or pushing.
|
|
51
|
+
if (!stagedIsMemoryOnly(hunchDir, env)) {
|
|
52
|
+
try {
|
|
53
|
+
execFileSync("git", ["-C", hunchDir, "reset", "-q", "--", "."], { stdio: "ignore", env });
|
|
54
|
+
}
|
|
55
|
+
catch { /* best-effort unstage */ }
|
|
56
|
+
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.)`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// Only sync+push when a memory commit was actually created โ never run pull/push against the
|
|
60
|
+
// enclosing repo on an empty stage. Two-way sync: MERGE the remote BEFORE pushing so a push
|
|
61
|
+
// can't be rejected non-fast-forward; the .hunch merge driver resolves same-record conflicts
|
|
62
|
+
// by id. On conflict/offline, mergeRemote aborts to a clean tree and we skip the push.
|
|
63
|
+
let committed = false;
|
|
64
|
+
try {
|
|
65
|
+
execFileSync("git", ["-C", hunchDir, "commit", "-m", message], { stdio: "ignore", env });
|
|
66
|
+
committed = true;
|
|
67
|
+
}
|
|
68
|
+
catch { /* nothing staged / not a repo */ }
|
|
69
|
+
if (committed && mergeRemote(hunchDir, env))
|
|
53
70
|
run(["push"]);
|
|
54
71
|
}
|
|
55
72
|
finally {
|
|
@@ -59,6 +76,35 @@ export function commitAndPushHunch(hunchDir, message) {
|
|
|
59
76
|
catch { /* released best-effort */ }
|
|
60
77
|
}
|
|
61
78
|
}
|
|
79
|
+
/** Is the staged set a clean, MEMORY-ONLY change โ only JSON record adds/updates, nothing else?
|
|
80
|
+
* The overlay store is entirely JSON (decisions/, bugs/, โฆ, manifest.json). A real memory sync
|
|
81
|
+
* is purely additive; a DELETION, rename, or any non-.json staged path means hunchDir is NOT a
|
|
82
|
+
* clean overlay repo (e.g. it resolved to the project repo), so committing there would clobber
|
|
83
|
+
* code. Empty stage โ false (nothing to commit). The transient mkdir lock is ignored. */
|
|
84
|
+
function stagedIsMemoryOnly(hunchDir, env) {
|
|
85
|
+
let out = "";
|
|
86
|
+
try {
|
|
87
|
+
out = execFileSync("git", ["-C", hunchDir, "diff", "--cached", "--name-status"], { encoding: "utf8", env });
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
const lines = out.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
93
|
+
if (!lines.length)
|
|
94
|
+
return false;
|
|
95
|
+
for (const line of lines) {
|
|
96
|
+
const parts = line.split("\t");
|
|
97
|
+
const status = (parts[0] ?? "").trim();
|
|
98
|
+
const path = (parts[parts.length - 1] ?? "").trim();
|
|
99
|
+
if (path.includes(".hunch-commit.lock"))
|
|
100
|
+
continue; // transient lock dir, never a record
|
|
101
|
+
if (!/^[AM]$/.test(status))
|
|
102
|
+
return false; // only Add / Modify โ any D/R/C/T โ not a memory sync
|
|
103
|
+
if (!path.endsWith(".json"))
|
|
104
|
+
return false; // the store is entirely JSON records
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
62
108
|
/** Merge the overlay's remote into the local branch (pull, no rebase), leaving a CLEAN tree
|
|
63
109
|
* whether it succeeds or not. Returns true when the branch is safe to push (merged, or there's
|
|
64
110
|
* no upstream to merge), false when a conflict was aborted (caller skips the push and retries
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@davesheffer/hunch",
|
|
3
|
-
"version": "0.38.
|
|
3
|
+
"version": "0.38.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"author": "Dave Sheffer <dave.sheffer1@gmail.com>",
|
|
6
6
|
"description": "Architectural Conformance for AI-generated code: a git-native graph that deterministically blocks AI changes which break your architecture โ the semantic invariants (layering, must-reach, dependency direction) pattern-SAST can't express โ grounded in the decisions and bugs behind each rule, across any MCP assistant (Claude Code, Cursor, Copilot, Windsurf, Codex).",
|