@davesheffer/hunch 0.11.0 → 0.11.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.
Files changed (2) hide show
  1. package/dist/cli/index.js +24 -5
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -55,7 +55,7 @@ program
55
55
  .description("Scaffold .hunch/, index the repo, install the git hook, and wire up Claude Code.")
56
56
  .option("--no-index", "skip the initial repo index")
57
57
  .option("--no-enforce", "do not install the advisory pre-commit constraint guard")
58
- .option("--enforce-strict", "make the pre-commit guard FAIL the commit on a blocking invariant (direct or near)")
58
+ .option("--enforce-strict", "make the pre-commit guard FAIL the commit on a direct, high-confidence, non-stale blocking invariant")
59
59
  .option("--no-providers", "skip scaffolding non-Claude assistant configs (Cursor / VS Code / Codex / AGENTS.md)")
60
60
  .option("--no-agent-hooks", "skip installing the Claude Code agent hooks (.claude/settings.json)")
61
61
  .option("--firmness <level>", "agent-hook firmness: off | advisory | firm | strict")
@@ -91,7 +91,7 @@ program
91
91
  if (opts.enforce !== false || opts.enforceStrict) {
92
92
  const strict = !!opts.enforceStrict;
93
93
  const p = installPreCommitHook(root, inv.shell, strict);
94
- console.log(` ✓ pre-commit constraint guard ${p.action} (${strict ? "strict — blocks on blocking invariants, direct or near" : "advisory — flags invariants in scope or blast radius"})`);
94
+ console.log(` ✓ pre-commit constraint guard ${p.action} (${strict ? "strict — fails only on direct, high-confidence, non-stale blocking invariants" : "advisory — flags invariants in scope or blast radius"})`);
95
95
  }
96
96
  }
97
97
  else {
@@ -144,20 +144,39 @@ program
144
144
  store.close();
145
145
  });
146
146
  // ---- backfill -------------------------------------------------------------
147
+ /** Run an async fn over items with at most `limit` in flight. A fixed pool of
148
+ * workers pulls from a shared cursor — no per-batch barrier, so a slow item
149
+ * never stalls the others. Used by backfill to overlap per-commit LLM spawns. */
150
+ async function mapPool(items, limit, fn) {
151
+ let next = 0;
152
+ const worker = async () => {
153
+ while (next < items.length) {
154
+ const i = next++;
155
+ await fn(items[i], i);
156
+ }
157
+ };
158
+ await Promise.all(Array.from({ length: Math.min(limit, items.length) }, () => worker()));
159
+ }
147
160
  program
148
161
  .command("backfill")
149
162
  .description("Replay git history to seed decisions (cold-start fix).")
150
163
  .option("--since <spec>", "how far back, e.g. 90d", "90d")
151
164
  .option("--max <n>", "max commits to process", "40")
165
+ .option("--concurrency <n>", "commits to synthesize in parallel (the LLM call is the bottleneck)", "4")
152
166
  .action(async (opts) => {
153
167
  const { store, root } = storeFor();
154
168
  if (!isGitRepo(root))
155
169
  return fail("backfill needs a git repo");
156
170
  store.json.ensureDirs();
157
171
  const commits = logSince(opts.since, root, Number(opts.max));
158
- console.log(`Backfilling from ${commits.length} commit(s) since ${opts.since}…`);
172
+ const conc = Math.max(1, Math.min(16, Number(opts.concurrency) || 4));
173
+ console.log(`Backfilling from ${commits.length} commit(s) since ${opts.since} (concurrency ${conc})…`);
159
174
  let written = 0, skipped = 0, llm = 0, heuristic = 0;
160
- for (const sha of commits) {
175
+ // The per-commit cost is the Claude synthesis spawn; run several at once. Safe:
176
+ // each commit drafts independently and writes its OWN decision file atomically,
177
+ // and the store's JS-side reads/writes run synchronously between awaits (single
178
+ // thread) — only the LLM spawns overlap. reindex() runs once, after the pool.
179
+ await mapPool(commits, conc, async (sha) => {
161
180
  const r = await syncCommit(store, root, sha);
162
181
  if (r.status === "written") {
163
182
  written++;
@@ -169,7 +188,7 @@ program
169
188
  }
170
189
  else
171
190
  skipped++;
172
- }
191
+ });
173
192
  store.reindex();
174
193
  updateClaudeMd(root, store);
175
194
  // Honest tally of where the tokens went: trivial commits are seeded by the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@davesheffer/hunch",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "license": "MIT",
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.",