@davesheffer/hunch 1.47.1 → 1.48.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/LICENSE +105 -201
- package/NOTICE +10 -3
- package/README.md +8 -6
- package/dist/cli/index.js +31 -14
- package/dist/core/correction.js +4 -3
- package/dist/core/format.d.ts +3 -1
- package/dist/core/format.js +14 -2
- package/dist/core/reviewMemory.d.ts +1 -1
- package/dist/core/subagentrole.d.ts +6 -0
- package/dist/core/subagentrole.js +32 -0
- package/dist/extractors/parse.js +20 -30
- package/dist/integrations/hooks.js +10 -8
- package/dist/store/hunchStore.d.ts +10 -6
- package/dist/store/hunchStore.js +96 -27
- package/dist/synthesis/prContext.d.ts +75 -0
- package/dist/synthesis/prContext.js +265 -0
- package/dist/synthesis/provider.d.ts +38 -0
- package/dist/synthesis/provider.js +110 -13
- package/dist/synthesis/synthesize.d.ts +14 -0
- package/dist/synthesis/synthesize.js +46 -6
- package/package.json +2 -2
- package/server.json +2 -2
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { commitMeta, commitDiff, headSha, currentBranch } from "../extractors/git.js";
|
|
2
2
|
import { analyzeDiff } from "../extractors/diff.js";
|
|
3
|
-
import { selectProvider, selectEnsemble, selectVerifier, verifyDecisionSafe, DeterministicProvider } from "./provider.js";
|
|
3
|
+
import { selectProvider, selectEnsemble, selectVerifier, verifyDecisionSafe, DeterministicProvider, UnusableOutputError } from "./provider.js";
|
|
4
4
|
import { decisionId, bugId, constraintId } from "../core/ids.js";
|
|
5
5
|
import { commitCoveredBy } from "../core/dupdetect.js";
|
|
6
6
|
import { pathMatchesGlob } from "../core/glob.js";
|
|
7
7
|
import { draftTripwires, knownRepoDeps } from "./tripwires.js";
|
|
8
|
+
import { prContextFor } from "./prContext.js";
|
|
8
9
|
import { isSubstantive } from "../extractors/languages.js";
|
|
9
10
|
// Subjects that signal mechanical churn. `chore(deps):` is matched as a literal
|
|
10
11
|
// prefix on its own: a word-boundary check after the closing parenthesis would
|
|
@@ -124,6 +125,15 @@ export async function syncCommit(store, root, sha, opts = {}) {
|
|
|
124
125
|
? await selectProvider({ root })
|
|
125
126
|
: new DeterministicProvider();
|
|
126
127
|
const input = { subject: meta.subject, body: meta.body, files: substantiveFiles, diff, analysis };
|
|
128
|
+
// The merged PR's description often holds the why a squash commit drops (#562). Fetch
|
|
129
|
+
// it only when a model will read it: never for a local-only capture (no PR text goes
|
|
130
|
+
// to any provider) and not for the free deterministic draft.
|
|
131
|
+
// The review thread feeds only the Critic-verified path (gated by a noise audit).
|
|
132
|
+
if (!localOnly && provider.name !== "deterministic") {
|
|
133
|
+
const pr = await (opts.prContext ?? prContextFor)(root, { sha: meta.sha, subject: meta.subject }, { thread: wantVerify });
|
|
134
|
+
if (pr)
|
|
135
|
+
input.pr = pr;
|
|
136
|
+
}
|
|
127
137
|
let draft = await draftDecisionSafe(provider, input);
|
|
128
138
|
// The Critic pass: audit the draft against the commit, PRUNE unsupported alternatives
|
|
129
139
|
// (BEFORE they scaffold tripwires below) and consequences, and lower confidence on weak
|
|
@@ -137,6 +147,10 @@ export async function syncCommit(store, root, sha, opts = {}) {
|
|
|
137
147
|
// were reconciled, their agreement, and the verifier's grounding. Rides in `evidence`
|
|
138
148
|
// (no schema change → respects forward-migration invariant con_947c578b2c).
|
|
139
149
|
const synthBits = [`provider=${actualProvider}`];
|
|
150
|
+
if (input.pr)
|
|
151
|
+
synthBits.push(`pr=#${input.pr.number}${input.pr.thread ? "+thread" : ""}`);
|
|
152
|
+
if (draft.fallbackKind)
|
|
153
|
+
synthBits.push(`fallback=${draft.fallbackKind}`);
|
|
140
154
|
if (draft.samples)
|
|
141
155
|
synthBits.push(`samples=${draft.samples}`);
|
|
142
156
|
if (draft.agreement != null)
|
|
@@ -227,7 +241,7 @@ export async function syncCommit(store, root, sha, opts = {}) {
|
|
|
227
241
|
store.putPrivate("decisions", decision);
|
|
228
242
|
else
|
|
229
243
|
store.json.put("decisions", decision);
|
|
230
|
-
return { status: "written", decision, provider: actualProvider };
|
|
244
|
+
return { status: "written", decision, provider: actualProvider, ...(draft.fallbackReason ? { fallbackReason: draft.fallbackReason } : {}) };
|
|
231
245
|
}
|
|
232
246
|
function putBugInHome(store, bug, home) {
|
|
233
247
|
return home === "private" ? store.putPrivate("bugs", bug) : store.json.put("bugs", bug);
|
|
@@ -516,9 +530,35 @@ function recentDiffFor(root) {
|
|
|
516
530
|
const head = headSha(root);
|
|
517
531
|
return head ? commitDiff(head, root, 12_000) : "";
|
|
518
532
|
}
|
|
533
|
+
/** Extra samples when a provider answered but its output held no usable record
|
|
534
|
+
* (issue #561): a model that echoed the schema usually answers properly on the
|
|
535
|
+
* next sample. Transport failures (timeout, crash, auth) are not retried, since a
|
|
536
|
+
* second hang would only double the wait before the same fallback. */
|
|
537
|
+
export const UNUSABLE_OUTPUT_RETRIES = 1;
|
|
538
|
+
async function sampleUntilUsable(draft) {
|
|
539
|
+
for (let attempt = 0;; attempt++) {
|
|
540
|
+
try {
|
|
541
|
+
return await draft();
|
|
542
|
+
}
|
|
543
|
+
catch (err) {
|
|
544
|
+
if (!(err instanceof UnusableOutputError) || attempt >= UNUSABLE_OUTPUT_RETRIES)
|
|
545
|
+
throw err;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
/** Short, print-safe label for the `synth:` evidence line, so a fallback from the
|
|
550
|
+
* quiet post-commit hook still leaves a trace `hunch review` can show. */
|
|
551
|
+
function fallbackKindOf(err) {
|
|
552
|
+
return err instanceof UnusableOutputError ? err.kind : "provider-error";
|
|
553
|
+
}
|
|
554
|
+
function fallbackReasonOf(err) {
|
|
555
|
+
if (err instanceof UnusableOutputError)
|
|
556
|
+
return `${err.message}, ${UNUSABLE_OUTPUT_RETRIES + 1} attempts`;
|
|
557
|
+
return err instanceof Error ? err.message : String(err);
|
|
558
|
+
}
|
|
519
559
|
export async function draftDecisionSafe(provider, input) {
|
|
520
560
|
try {
|
|
521
|
-
return await provider.draftDecision(input);
|
|
561
|
+
return await sampleUntilUsable(() => provider.draftDecision(input));
|
|
522
562
|
}
|
|
523
563
|
catch (err) {
|
|
524
564
|
// A provider failure (network, bad creds, CLI crash, unparseable output) must
|
|
@@ -527,17 +567,17 @@ export async function draftDecisionSafe(provider, input) {
|
|
|
527
567
|
// Tell the caller a fallback happened (and why) so it reports the provider that
|
|
528
568
|
// actually drafted the record rather than the one that was selected.
|
|
529
569
|
const fallback = await new DeterministicProvider().draftDecision(input);
|
|
530
|
-
return { ...fallback, fellBackTo: "deterministic", fallbackReason: err
|
|
570
|
+
return { ...fallback, fellBackTo: "deterministic", fallbackReason: fallbackReasonOf(err), fallbackKind: fallbackKindOf(err) };
|
|
531
571
|
}
|
|
532
572
|
}
|
|
533
573
|
export async function draftBugSafe(provider, input) {
|
|
534
574
|
try {
|
|
535
|
-
return await provider.draftBug(input);
|
|
575
|
+
return await sampleUntilUsable(() => provider.draftBug(input));
|
|
536
576
|
}
|
|
537
577
|
catch (err) {
|
|
538
578
|
// Same contract as draftDecisionSafe: surface the fallback and its cause.
|
|
539
579
|
const fallback = await new DeterministicProvider().draftBug(input);
|
|
540
|
-
return { ...fallback, fellBackTo: "deterministic", fallbackReason:
|
|
580
|
+
return { ...fallback, fellBackTo: "deterministic", fallbackReason: fallbackReasonOf(err) };
|
|
541
581
|
}
|
|
542
582
|
}
|
|
543
583
|
//# sourceMappingURL=synthesize.js.map
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@davesheffer/hunch",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.48.0",
|
|
4
4
|
"mcpName": "io.github.davesheffer/hunch",
|
|
5
|
-
"license": "
|
|
5
|
+
"license": "FSL-1.1-ALv2",
|
|
6
6
|
"author": "Dave Sheffer <dave.sheffer1@gmail.com>",
|
|
7
7
|
"description": "A shared record for AI agents: decisions, completed work, and commitments, with sources. Git-native engineering memory and a self-hosted state server.",
|
|
8
8
|
"homepage": "https://www.hunchmemory.com",
|
package/server.json
CHANGED
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
9
|
"websiteUrl": "https://www.hunchmemory.com",
|
|
10
|
-
"version": "1.
|
|
10
|
+
"version": "1.48.0",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
15
15
|
"identifier": "@davesheffer/hunch",
|
|
16
|
-
"version": "1.
|
|
16
|
+
"version": "1.48.0",
|
|
17
17
|
"runtimeHint": "npx",
|
|
18
18
|
"packageArguments": [
|
|
19
19
|
{
|