@davesheffer/hunch 1.11.0 → 1.12.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/dist/cli/index.js +47 -1
- package/dist/core/agenthook.js +4 -0
- package/dist/core/hookcache.js +16 -0
- package/dist/integrations/scaffold.js +12 -0
- package/package.json +1 -1
- package/server.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -57,7 +57,7 @@ import { blockingInScope, vetoInScope, proposedEditLines } from "../core/hookpol
|
|
|
57
57
|
import { isHumanConfirmed } from "../core/strictgate.js";
|
|
58
58
|
import { appendEvent, readEvents } from "../core/events.js";
|
|
59
59
|
import { computeStats, formatStats } from "../core/stats.js";
|
|
60
|
-
import { injectionMode } from "../core/hookcache.js";
|
|
60
|
+
import { injectionMode, resetSessionInjections } from "../core/hookcache.js";
|
|
61
61
|
import { contextHookOutput, denyHookOutput, hookProvider, normalizeHookEvent, stopHookOutput } from "../core/agenthook.js";
|
|
62
62
|
import { PIPELINE_LOOP, UNVERIFIED_NAG, loadPipelineState, onCommand, onEdit, onPrompt, onSkill, pipelineEnabled, savePipelineState, stopVerdict, } from "../core/pipeline.js";
|
|
63
63
|
import { draftDuplicateOf, isAcceptedDuplicateAnchor } from "../core/dupdetect.js";
|
|
@@ -3797,7 +3797,53 @@ program
|
|
|
3797
3797
|
emitContext(provider, "UserPromptSubmit", text);
|
|
3798
3798
|
return;
|
|
3799
3799
|
}
|
|
3800
|
+
if (evt.hook_event_name === "PreCompact") {
|
|
3801
|
+
// Compaction is about to summarize injected grounding out of the agent's
|
|
3802
|
+
// context while the dedup map still says "delivered". Reset it so every
|
|
3803
|
+
// post-compact injection is full again. Emit nothing — this event has no
|
|
3804
|
+
// context channel worth spending.
|
|
3805
|
+
resetSessionInjections(evt.session_id);
|
|
3806
|
+
return;
|
|
3807
|
+
}
|
|
3808
|
+
if (evt.hook_event_name === "SubagentStart") {
|
|
3809
|
+
// A delegated agent starts with NONE of the parent session's grounding:
|
|
3810
|
+
// session orientation never fired inside it and only per-edit PreToolUse
|
|
3811
|
+
// follows it in — so read-only agents (Explore/Plan) could work fully
|
|
3812
|
+
// blind. Give it the invariants that must survive delegation. Public
|
|
3813
|
+
// store only; once per agent type per session.
|
|
3814
|
+
const s = new HunchStore(paths);
|
|
3815
|
+
try {
|
|
3816
|
+
const sevRank = { blocking: 0, warning: 1, advisory: 2 };
|
|
3817
|
+
const constraints = s.advisoryRecs("constraints")
|
|
3818
|
+
.filter((c) => c.status === "active")
|
|
3819
|
+
.sort((a, b) => sevRank[a.severity] - sevRank[b.severity]);
|
|
3820
|
+
if (!constraints.length)
|
|
3821
|
+
return;
|
|
3822
|
+
const L = [`🧠 Hunch — delegated agent grounding: ${constraints.length} invariant(s) in force in this repo.`];
|
|
3823
|
+
for (const c of constraints.slice(0, 8)) {
|
|
3824
|
+
const flat = c.statement.replace(/\s+/g, " ").trim();
|
|
3825
|
+
const claim = flat.length > 140 ? `${flat.slice(0, 139).trimEnd()}…` : flat;
|
|
3826
|
+
L.push(`- [${c.severity}] ${claim}${c.scope.length ? ` (scope: ${c.scope.slice(0, 3).join(", ")})` : ""}`);
|
|
3827
|
+
}
|
|
3828
|
+
if (constraints.length > 8)
|
|
3829
|
+
L.push(`…and ${constraints.length - 8} more — hunch_check_constraints(scope) for your files.`);
|
|
3830
|
+
L.push("Before editing: hunch_check_constraints(scope) · hunch_why(target). Orient: hunch_context(task).");
|
|
3831
|
+
// No dedup here: the hook event carries the PARENT session id, but each
|
|
3832
|
+
// spawned agent is a fresh empty context — deduping would ground the
|
|
3833
|
+
// first Explore and silently starve every later one.
|
|
3834
|
+
emitContext(provider, "SubagentStart", L.join("\n"));
|
|
3835
|
+
}
|
|
3836
|
+
finally {
|
|
3837
|
+
s.close();
|
|
3838
|
+
}
|
|
3839
|
+
return;
|
|
3840
|
+
}
|
|
3800
3841
|
if (evt.hook_event_name === "SessionStart") {
|
|
3842
|
+
// A compact-resume means everything injected so far was just summarized
|
|
3843
|
+
// away — the dedup map must forget it delivered anything, or the rest of
|
|
3844
|
+
// the session gets delta one-liners against grounding that is gone.
|
|
3845
|
+
if (evt.source === "compact")
|
|
3846
|
+
resetSessionInjections(evt.session_id);
|
|
3801
3847
|
// Orientation at the moment it matters: what just happened + what's next,
|
|
3802
3848
|
// straight from the graph — the agent sits down already knowing where it
|
|
3803
3849
|
// is instead of pulling (or worse, grepping) for it. Cheap reads only
|
package/dist/core/agenthook.js
CHANGED
|
@@ -77,6 +77,8 @@ function eventName(value, provider) {
|
|
|
77
77
|
posttooluse: "PostToolUse",
|
|
78
78
|
userpromptsubmit: "UserPromptSubmit",
|
|
79
79
|
sessionstart: "SessionStart",
|
|
80
|
+
subagentstart: "SubagentStart",
|
|
81
|
+
precompact: "PreCompact",
|
|
80
82
|
stop: "Stop",
|
|
81
83
|
};
|
|
82
84
|
if (map[name])
|
|
@@ -155,6 +157,8 @@ export function normalizeHookEvent(raw, provider) {
|
|
|
155
157
|
tool_name: hunchToolName(stringAt(input, "tool_name", "toolName"), toolInput ?? {}),
|
|
156
158
|
tool_input: toolInput,
|
|
157
159
|
prompt: stringAt(input, "prompt", "user_prompt", "userPrompt"),
|
|
160
|
+
source: stringAt(input, "source"),
|
|
161
|
+
agent_type: stringAt(input, "agent_type", "agentType", "subagent_type", "subagentType"),
|
|
158
162
|
};
|
|
159
163
|
}
|
|
160
164
|
/** Provider-aware hook output. Context output is intentionally omitted for
|
package/dist/core/hookcache.js
CHANGED
|
@@ -55,6 +55,22 @@ export function injectionMode(sessionId, key, content) {
|
|
|
55
55
|
return "full"; // grounded beats deduped, always
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
+
/** Forget everything injected into a session. Compaction summarizes injected
|
|
59
|
+
* grounding out of the agent's context while the dedup map still says
|
|
60
|
+
* "delivered" — so on PreCompact / SessionStart[source=compact] the map must
|
|
61
|
+
* reset, or post-compact edits get delta one-liners against grounding the
|
|
62
|
+
* agent no longer has. Never throws (same posture as injectionMode). */
|
|
63
|
+
export function resetSessionInjections(sessionId) {
|
|
64
|
+
try {
|
|
65
|
+
if (!sessionId)
|
|
66
|
+
return;
|
|
67
|
+
const file = join(tmpdir(), "hunch-hookcache", `${sessionId.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 80)}.json`);
|
|
68
|
+
rmSync(file, { force: true });
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
/* unwritable tmpdir — next injectionMode call falls back to "full" anyway */
|
|
72
|
+
}
|
|
73
|
+
}
|
|
58
74
|
/** Drop session caches from long-gone sessions (best effort, bounded dir). */
|
|
59
75
|
function sweep(dir) {
|
|
60
76
|
try {
|
|
@@ -156,6 +156,18 @@ export function installClaudeHooks(root, hookCmd) {
|
|
|
156
156
|
...keep(json.hooks.SessionStart),
|
|
157
157
|
{ hooks: [{ type: "command", command: hookCmd }] },
|
|
158
158
|
];
|
|
159
|
+
// Delegated agents start with no session grounding (orientation never fired
|
|
160
|
+
// inside them); compaction summarizes injected grounding away while the dedup
|
|
161
|
+
// map still says "delivered". These two events keep delivery alive across the
|
|
162
|
+
// whole session lifecycle, not just its first context window.
|
|
163
|
+
json.hooks.SubagentStart = [
|
|
164
|
+
...keep(json.hooks.SubagentStart),
|
|
165
|
+
{ hooks: [{ type: "command", command: hookCmd }] },
|
|
166
|
+
];
|
|
167
|
+
json.hooks.PreCompact = [
|
|
168
|
+
...keep(json.hooks.PreCompact),
|
|
169
|
+
{ hooks: [{ type: "command", command: hookCmd }] },
|
|
170
|
+
];
|
|
159
171
|
// Verification pipeline (core/pipeline.ts): PostToolUse records observable
|
|
160
172
|
// facts (edits, verify commands); Stop refuses to end a turn with unverified
|
|
161
173
|
// product edits at firm/strict firmness. Delivery is enforced, not hoped for.
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
9
|
"websiteUrl": "https://hunch-pi.vercel.app",
|
|
10
|
-
"version": "1.
|
|
10
|
+
"version": "1.12.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.12.0",
|
|
17
17
|
"runtimeHint": "npx",
|
|
18
18
|
"packageArguments": [
|
|
19
19
|
{
|