@hegel-dev/companion 1.0.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.
Files changed (64) hide show
  1. package/README.md +84 -0
  2. package/dist/analyzers/prompt-analyzer.d.ts +7 -0
  3. package/dist/analyzers/prompt-analyzer.d.ts.map +1 -0
  4. package/dist/analyzers/prompt-analyzer.js +224 -0
  5. package/dist/analyzers/prompt-analyzer.js.map +1 -0
  6. package/dist/analyzers/response-analyzer.d.ts +6 -0
  7. package/dist/analyzers/response-analyzer.d.ts.map +1 -0
  8. package/dist/analyzers/response-analyzer.js +218 -0
  9. package/dist/analyzers/response-analyzer.js.map +1 -0
  10. package/dist/analyzers/session-analyzer.d.ts +10 -0
  11. package/dist/analyzers/session-analyzer.d.ts.map +1 -0
  12. package/dist/analyzers/session-analyzer.js +194 -0
  13. package/dist/analyzers/session-analyzer.js.map +1 -0
  14. package/dist/config.d.ts +11 -0
  15. package/dist/config.d.ts.map +1 -0
  16. package/dist/config.js +27 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/debug-wrapper.d.ts +2 -0
  19. package/dist/debug-wrapper.d.ts.map +1 -0
  20. package/dist/debug-wrapper.js +55 -0
  21. package/dist/debug-wrapper.js.map +1 -0
  22. package/dist/dev-watch.d.ts +10 -0
  23. package/dist/dev-watch.d.ts.map +1 -0
  24. package/dist/dev-watch.js +55 -0
  25. package/dist/dev-watch.js.map +1 -0
  26. package/dist/format.d.ts +4 -0
  27. package/dist/format.d.ts.map +1 -0
  28. package/dist/format.js +38 -0
  29. package/dist/format.js.map +1 -0
  30. package/dist/hook.d.ts +8 -0
  31. package/dist/hook.d.ts.map +1 -0
  32. package/dist/hook.js +320 -0
  33. package/dist/hook.js.map +1 -0
  34. package/dist/hooks-generator.d.ts +45 -0
  35. package/dist/hooks-generator.d.ts.map +1 -0
  36. package/dist/hooks-generator.js +120 -0
  37. package/dist/hooks-generator.js.map +1 -0
  38. package/dist/mcp.d.ts +10 -0
  39. package/dist/mcp.d.ts.map +1 -0
  40. package/dist/mcp.js +173 -0
  41. package/dist/mcp.js.map +1 -0
  42. package/dist/prompts.d.ts +11 -0
  43. package/dist/prompts.d.ts.map +1 -0
  44. package/dist/prompts.js +85 -0
  45. package/dist/prompts.js.map +1 -0
  46. package/dist/setup.d.ts +28 -0
  47. package/dist/setup.d.ts.map +1 -0
  48. package/dist/setup.js +247 -0
  49. package/dist/setup.js.map +1 -0
  50. package/dist/state.d.ts +14 -0
  51. package/dist/state.d.ts.map +1 -0
  52. package/dist/state.js +77 -0
  53. package/dist/state.js.map +1 -0
  54. package/dist/transcript.d.ts +32 -0
  55. package/dist/transcript.d.ts.map +1 -0
  56. package/dist/transcript.js +156 -0
  57. package/dist/transcript.js.map +1 -0
  58. package/dist/types.d.ts +137 -0
  59. package/dist/types.d.ts.map +1 -0
  60. package/dist/types.js +3 -0
  61. package/dist/types.js.map +1 -0
  62. package/hegel-vscode/hegel-companion-1.0.0.vsix +0 -0
  63. package/hegel.config.schema.json +63 -0
  64. package/package.json +59 -0
package/dist/hook.js ADDED
@@ -0,0 +1,320 @@
1
+ import { stdin } from "node:process";
2
+ import { appendFile, mkdir, access } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import { loadConfig } from "./config.js";
6
+ import { loadState, saveState, addPrompt, addResponse, addFileEdit, addConcern, recordModel, } from "./state.js";
7
+ import { analyzePrompt, buildPromptRecord, } from "./analyzers/prompt-analyzer.js";
8
+ import { analyzeResponse, buildResponseRecord, } from "./analyzers/response-analyzer.js";
9
+ import { analyzeSession } from "./analyzers/session-analyzer.js";
10
+ import { loadTranscript } from "./transcript.js";
11
+ import { formatBlockMessage } from "./format.js";
12
+ import { writeHooksFile } from "./hooks-generator.js";
13
+ async function readStdin() {
14
+ const chunks = [];
15
+ for await (const chunk of stdin) {
16
+ chunks.push(chunk);
17
+ }
18
+ const raw = Buffer.concat(chunks).toString("utf-8");
19
+ // Cursor on Windows prepends a UTF-8 BOM (\uFEFF) to stdin — strip it
20
+ return raw.replace(/^\uFEFF/, "");
21
+ }
22
+ const LOG_DIR = ".hegel-state";
23
+ const LOG_FILE = `${LOG_DIR}/hegel.log`;
24
+ /**
25
+ * Detects if the hook is running inside the Hegel project itself.
26
+ * When true, bypass is automatic — you can't develop the guardian while it guards you.
27
+ */
28
+ async function isSelfProject(input) {
29
+ const roots = input.workspace_roots ?? [];
30
+ for (const root of roots) {
31
+ try {
32
+ await access(join(root, "hegel.config.json"));
33
+ await access(join(root, ".cursor-plugin", "plugin.json"));
34
+ return true;
35
+ }
36
+ catch {
37
+ // not the Hegel project
38
+ }
39
+ }
40
+ return false;
41
+ }
42
+ async function shouldBypass(input, config) {
43
+ if (config.observeOnly)
44
+ return true;
45
+ return isSelfProject(input);
46
+ }
47
+ async function log(level, event, message) {
48
+ try {
49
+ await mkdir(LOG_DIR, { recursive: true });
50
+ const ts = new Date().toISOString();
51
+ await appendFile(LOG_FILE, `[${ts}] [${level}] [${event}] ${message}\n`, "utf-8");
52
+ }
53
+ catch {
54
+ // logging should never break the hook
55
+ }
56
+ }
57
+ function shortConversationId(conversationId) {
58
+ return conversationId ? conversationId.slice(0, 8) : "unknown";
59
+ }
60
+ function summarizeText(text) {
61
+ return `len=${text.length} chars words=${text.split(/\s+/).filter(Boolean).length}`;
62
+ }
63
+ function writeOutput(obj) {
64
+ process.stdout.write(JSON.stringify(obj) + "\n");
65
+ }
66
+ /**
67
+ * Hot-reload: regenerate hooks.json if the config hash has changed.
68
+ * Cheap on no-op (hash compare only, no write). We run this from both
69
+ * `sessionStart` and `beforeSubmitPrompt` because Cursor only fires
70
+ * `sessionStart` on extension/hook-runtime init — opening a new chat
71
+ * inside the same IDE window does NOT re-trigger it — so relying on
72
+ * `sessionStart` alone meant UI config changes (model, strictness,
73
+ * observeOnly, …) silently failed to propagate until an IDE restart.
74
+ */
75
+ async function maybeRegenerateHooks(workspaceRoots, config, triggerEvent) {
76
+ for (const root of workspaceRoots ?? []) {
77
+ try {
78
+ const updated = await writeHooksFile(root, config);
79
+ if (updated) {
80
+ await log("info", `${triggerEvent}:hot-reload`, `Regenerated hooks.json for ${root} (config changed)`);
81
+ }
82
+ }
83
+ catch {
84
+ // best-effort; hooks.json update must never break the hook
85
+ }
86
+ }
87
+ }
88
+ async function handleBeforeSubmitPrompt(input, output) {
89
+ const config = await loadConfig(input.workspace_roots?.[0] || process.cwd());
90
+ await maybeRegenerateHooks(input.workspace_roots, config, "beforeSubmitPrompt");
91
+ const bypass = await shouldBypass(input, config);
92
+ const state = await loadState(input.conversation_id);
93
+ if (input.session_id)
94
+ state.sessionId = input.session_id;
95
+ if (input.composer_mode)
96
+ state.composerMode = input.composer_mode;
97
+ recordModel(state, input.model);
98
+ const promptText = input.prompt.trim();
99
+ if (input.composer_mode === "ask") {
100
+ await log("info", "beforeSubmitPrompt", `Skipping analysis in ask mode`);
101
+ const record = buildPromptRecord(promptText, []);
102
+ addPrompt(state, record);
103
+ await saveState(state);
104
+ output({ continue: true });
105
+ return;
106
+ }
107
+ // Escape hatch: if the user resubmits the same prompt that was just blocked,
108
+ // let it through — they've seen the warning and chose to proceed.
109
+ if (state.lastBlockedPrompt && state.lastBlockedPrompt === promptText) {
110
+ await log("info", "beforeSubmitPrompt", `Resubmit of blocked prompt — allowing through (${summarizeText(promptText)})`);
111
+ state.lastBlockedPrompt = undefined;
112
+ const record = buildPromptRecord(promptText, []);
113
+ addPrompt(state, record);
114
+ await saveState(state);
115
+ output({ continue: true });
116
+ return;
117
+ }
118
+ const transcript = await loadTranscript(input.transcript_path);
119
+ const { concerns, shouldBlock } = analyzePrompt(input.prompt, state, transcript);
120
+ await log("info", "beforeSubmitPrompt", `${summarizeText(promptText)} concerns=${concerns.length} block=${shouldBlock} bypass=${bypass} transcript=${transcript ? transcript.turns.length + " turns" : "unavailable"}`);
121
+ const record = buildPromptRecord(promptText, concerns);
122
+ addPrompt(state, record);
123
+ for (const c of concerns) {
124
+ c.sourceText = promptText.length > 200 ? promptText.slice(0, 200) + "..." : promptText;
125
+ c.sourceType = "prompt";
126
+ addConcern(state, c);
127
+ }
128
+ if (shouldBlock && !bypass) {
129
+ state.lastBlockedPrompt = promptText;
130
+ await saveState(state);
131
+ const msg = formatBlockMessage(concerns);
132
+ await log("warn", "beforeSubmitPrompt", `BLOCKED concerns=${concerns.length}`);
133
+ output({ continue: false, user_message: msg });
134
+ }
135
+ else {
136
+ if (shouldBlock && bypass) {
137
+ await log("info", "beforeSubmitPrompt", `BYPASS: would have blocked (${concerns.length} concerns)`);
138
+ }
139
+ state.lastBlockedPrompt = undefined;
140
+ await saveState(state);
141
+ output({ continue: true });
142
+ }
143
+ }
144
+ async function handleAfterAgentResponse(input, output) {
145
+ const state = await loadState(input.conversation_id);
146
+ if (input.session_id)
147
+ state.sessionId = input.session_id;
148
+ if (input.composer_mode)
149
+ state.composerMode = input.composer_mode;
150
+ recordModel(state, input.model);
151
+ if (input.composer_mode === "ask") {
152
+ await log("info", "afterAgentResponse", `Skipping analysis in ask mode`);
153
+ const record = buildResponseRecord(input.text, [], false);
154
+ addResponse(state, record);
155
+ await saveState(state);
156
+ output({});
157
+ return;
158
+ }
159
+ const transcript = await loadTranscript(input.transcript_path);
160
+ const { concerns } = analyzeResponse(input.text, state, transcript);
161
+ const lastPromptTs = state.prompts.at(-1)?.timestamp ?? 0;
162
+ const lastResponseTs = state.responses.at(-1)?.timestamp ?? 0;
163
+ const unprompted = state.prompts.length === 0 || lastResponseTs > lastPromptTs;
164
+ await log("info", "afterAgentResponse", `responseLen=${input.text.length} concerns=${concerns.length} unprompted=${unprompted}`);
165
+ const record = buildResponseRecord(input.text, concerns, unprompted);
166
+ addResponse(state, record);
167
+ if (unprompted)
168
+ state.turnCount++;
169
+ for (const c of concerns) {
170
+ c.sourceText = input.text.length > 200 ? input.text.slice(0, 200) + "..." : input.text;
171
+ c.sourceType = "response";
172
+ addConcern(state, c);
173
+ }
174
+ await saveState(state);
175
+ output({});
176
+ }
177
+ async function handleAfterFileEdit(input, output) {
178
+ const state = await loadState(input.conversation_id);
179
+ // Approximate change volume as lines removed + lines added.
180
+ // Without a line-level diff this overcounts unchanged lines in partial
181
+ // edits, but correlates better with real change size than max(old, new).
182
+ const totalLines = input.edits.reduce((sum, e) => {
183
+ const oldLines = (e.old_string.match(/\n/g) ?? []).length + 1;
184
+ const newLines = (e.new_string.match(/\n/g) ?? []).length + 1;
185
+ return sum + oldLines + newLines;
186
+ }, 0);
187
+ addFileEdit(state, {
188
+ timestamp: Date.now(),
189
+ filePath: input.file_path,
190
+ editCount: input.edits.length,
191
+ totalLinesChanged: totalLines,
192
+ });
193
+ await saveState(state);
194
+ output({});
195
+ }
196
+ async function handleStop(input, output) {
197
+ const state = await loadState(input.conversation_id);
198
+ await log("info", "stop", `status=${input.status} loop=${input.loop_count} turns=${state.turnCount}`);
199
+ // Skip session review for aborted turns (e.g. hook blocks, user cancel) and
200
+ // when nothing has changed since the last review (Cursor fires stop per turn).
201
+ const alreadyReviewed = state.lastReviewedAtTurn === state.turnCount;
202
+ if (input.status !== "aborted" && !alreadyReviewed) {
203
+ const transcript = await loadTranscript(input.transcript_path);
204
+ const { summary, concerns } = analyzeSession(state, transcript);
205
+ await log("info", "stop:review", summary.replace(/\n/g, " | "));
206
+ for (const c of concerns) {
207
+ c.sourceType = "session";
208
+ addConcern(state, c);
209
+ }
210
+ state.lastReviewedAtTurn = state.turnCount;
211
+ await saveState(state);
212
+ }
213
+ // Session review is intentionally NOT emitted as `followup_message`:
214
+ // Cursor treats stop-hook `followup_message` as a new agent turn, which
215
+ // (a) re-ingests Hegel's own review into the conversation transcript,
216
+ // (b) triggers a redundant assistant response, and
217
+ // (c) causes the prompt-analyzer to flag its own review as context-drift.
218
+ // The review is instead surfaced through the VS Code sidebar dashboard,
219
+ // the status bar, and the MCP `hegel-review` tool.
220
+ output({});
221
+ }
222
+ async function handlePreCompact(input, output) {
223
+ const config = await loadConfig(input.workspace_roots?.[0] || process.cwd());
224
+ const bypass = await shouldBypass(input, config);
225
+ const state = await loadState(input.conversation_id);
226
+ state.compactionCount++;
227
+ await saveState(state);
228
+ await log("info", "preCompact", `compaction #${state.compactionCount} — ${input.context_usage_percent}% used, compacting ${input.messages_to_compact} messages`);
229
+ if (bypass) {
230
+ output({});
231
+ return;
232
+ }
233
+ const pct = input.context_usage_percent;
234
+ const nth = state.compactionCount;
235
+ const msg = nth >= 3
236
+ ? `⚖️ Hegel: Context compacted ${nth} times (${pct}% used). Early context is severely degraded — strongly consider starting a fresh chat with a summary of key decisions.`
237
+ : pct >= 90
238
+ ? `⚖️ Hegel: Context window at ${pct}% — compacting ${input.messages_to_compact} messages. Important early context may be lost. Consider starting a fresh chat with a summary of key decisions.`
239
+ : `⚖️ Hegel: Context compaction triggered (${pct}% used). Continuing in the same session.`;
240
+ output({ user_message: msg });
241
+ }
242
+ async function handleSessionStart(input, output) {
243
+ const config = await loadConfig(input.workspace_roots?.[0] || process.cwd());
244
+ const bypass = await shouldBypass(input, config);
245
+ const mode = bypass ? "observe-only" : "active";
246
+ await log("info", "sessionStart", `Mode: ${mode} (observeOnly=${config.observeOnly}, selfProject=${await isSelfProject(input)})`);
247
+ // Hot-reload: regenerate hooks.json if config has changed since last setup.
248
+ // This path fires on extension/hook-runtime init; the same check also runs
249
+ // from `beforeSubmitPrompt` so per-chat UI changes propagate without an
250
+ // IDE restart.
251
+ await maybeRegenerateHooks(input.workspace_roots, config, "sessionStart");
252
+ output({
253
+ additional_context: `[Hegel dialectical companion is ${mode} for this session. It will monitor prompt quality, response patterns, and session health.]`,
254
+ });
255
+ }
256
+ // ── Main Dispatcher ──
257
+ export async function processHookInput(input, output = writeOutput) {
258
+ const event = input.hook_event_name;
259
+ await log("info", event ?? "unknown", `conversation=${shortConversationId(input.conversation_id)} model=${input.model}`);
260
+ // Guard against stale state: if startedAt is more than 4 hours old,
261
+ // treat this as a new session (covers missing sessionStart and ID reuse).
262
+ if (event !== "sessionStart") {
263
+ const state = await loadState(input.conversation_id);
264
+ const ageMs = Date.now() - state.startedAt;
265
+ if (ageMs > 4 * 60 * 60 * 1000) {
266
+ await log("info", "stale-state-reset", `State for ${shortConversationId(input.conversation_id)} was ${Math.round(ageMs / 60_000)} min old — resetting startedAt`);
267
+ state.startedAt = Date.now();
268
+ await saveState(state);
269
+ }
270
+ }
271
+ switch (event) {
272
+ case "beforeSubmitPrompt":
273
+ await handleBeforeSubmitPrompt(input, output);
274
+ break;
275
+ case "afterAgentResponse":
276
+ await handleAfterAgentResponse(input, output);
277
+ break;
278
+ case "afterFileEdit":
279
+ await handleAfterFileEdit(input, output);
280
+ break;
281
+ case "stop":
282
+ await handleStop(input, output);
283
+ break;
284
+ case "preCompact":
285
+ await handlePreCompact(input, output);
286
+ break;
287
+ case "sessionStart":
288
+ await handleSessionStart(input, output);
289
+ break;
290
+ default:
291
+ output({});
292
+ }
293
+ }
294
+ export async function processHookJson(raw, output = writeOutput) {
295
+ let input;
296
+ try {
297
+ input = JSON.parse(raw);
298
+ }
299
+ catch {
300
+ output({});
301
+ return;
302
+ }
303
+ await processHookInput(input, output);
304
+ }
305
+ export async function runHook(readInput = readStdin, output = writeOutput) {
306
+ const raw = await readInput();
307
+ await processHookJson(raw, output);
308
+ }
309
+ function isEntrypoint() {
310
+ return !process.env.VITEST &&
311
+ !!process.argv[1] &&
312
+ import.meta.url === pathToFileURL(process.argv[1]).href;
313
+ }
314
+ if (isEntrypoint()) {
315
+ runHook().catch(async (err) => {
316
+ await log("error", "main", `Unhandled: ${err instanceof Error ? err.message : String(err)}`);
317
+ writeOutput({});
318
+ });
319
+ }
320
+ //# sourceMappingURL=hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.js","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import type { HegelConfig } from "./config.js";
2
+ interface HookEntry {
3
+ command?: string;
4
+ type?: string;
5
+ prompt?: string;
6
+ model?: string;
7
+ timeout?: number;
8
+ loop_limit?: number;
9
+ }
10
+ interface HooksConfig {
11
+ version: number;
12
+ hooks: Record<string, HookEntry[]>;
13
+ _hegel?: {
14
+ configHash: string;
15
+ generatedAt: string;
16
+ };
17
+ }
18
+ /**
19
+ * Computes a hash of the config fields that affect hooks.json content.
20
+ * When this hash changes, hooks.json needs regeneration.
21
+ */
22
+ export declare function configHash(config: HegelConfig): string;
23
+ /**
24
+ * Reads the _hegel.configHash from an existing hooks.json.
25
+ * Returns null if the file doesn't exist or has no Hegel metadata.
26
+ */
27
+ export declare function readExistingHash(hooksFilePath: string): Promise<string | null>;
28
+ /**
29
+ * Generates hooks.json content for a target project.
30
+ * This is the shared logic used by both setup.ts (CLI) and
31
+ * the sessionStart hot-reload check.
32
+ */
33
+ export declare function generateHooksConfig(config: HegelConfig): HooksConfig;
34
+ /**
35
+ * Writes hooks.json to a target project directory.
36
+ * Returns true if the file was written, false if no update was needed.
37
+ */
38
+ /**
39
+ * Writes hooks.json to a target project directory.
40
+ * Returns true if the file was written, false if no update was needed.
41
+ * Pass force=true to always write (used by the setup CLI).
42
+ */
43
+ export declare function writeHooksFile(projectPath: string, config: HegelConfig, force?: boolean): Promise<boolean>;
44
+ export {};
45
+ //# sourceMappingURL=hooks-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-generator.d.ts","sourceRoot":"","sources":["../src/hooks-generator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C,UAAU,SAAS;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACnC,MAAM,CAAC,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAYtD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQpF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CA0DpE;AAED;;;GAGG;AACH;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,WAAW,EACnB,KAAK,UAAQ,GACZ,OAAO,CAAC,OAAO,CAAC,CAclB"}
@@ -0,0 +1,120 @@
1
+ import { readFile, writeFile, mkdir } from "node:fs/promises";
2
+ import { join, dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { createHash } from "node:crypto";
5
+ import { buildPromptAnalysisPrompt, buildResponseAnalysisPrompt } from "./prompts.js";
6
+ function hegelRoot() {
7
+ return resolve(join(dirname(fileURLToPath(import.meta.url)), ".."));
8
+ }
9
+ /**
10
+ * Computes a hash of the config fields that affect hooks.json content.
11
+ * When this hash changes, hooks.json needs regeneration.
12
+ */
13
+ export function configHash(config) {
14
+ const significant = {
15
+ enableLlmAnalysis: config.enableLlmAnalysis,
16
+ strictness: config.strictness,
17
+ observeOnly: config.observeOnly,
18
+ model: config.model,
19
+ timeoutSeconds: config.timeoutSeconds,
20
+ };
21
+ return createHash("sha256")
22
+ .update(JSON.stringify(significant))
23
+ .digest("hex")
24
+ .slice(0, 12);
25
+ }
26
+ /**
27
+ * Reads the _hegel.configHash from an existing hooks.json.
28
+ * Returns null if the file doesn't exist or has no Hegel metadata.
29
+ */
30
+ export async function readExistingHash(hooksFilePath) {
31
+ try {
32
+ const raw = await readFile(hooksFilePath, "utf-8");
33
+ const parsed = JSON.parse(raw);
34
+ return parsed._hegel?.configHash ?? null;
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ /**
41
+ * Generates hooks.json content for a target project.
42
+ * This is the shared logic used by both setup.ts (CLI) and
43
+ * the sessionStart hot-reload check.
44
+ */
45
+ export function generateHooksConfig(config) {
46
+ const root = hegelRoot();
47
+ const hookScript = join(root, "dist", "hook.js").replace(/\\/g, "/");
48
+ const hooks = {
49
+ version: 1,
50
+ hooks: {
51
+ sessionStart: [
52
+ { command: `node ${hookScript}` },
53
+ ],
54
+ beforeSubmitPrompt: [
55
+ { command: `node ${hookScript}`, timeout: 5 },
56
+ ],
57
+ afterAgentResponse: [
58
+ { command: `node ${hookScript}` },
59
+ ],
60
+ afterFileEdit: [
61
+ { command: `node ${hookScript}` },
62
+ ],
63
+ preCompact: [
64
+ { command: `node ${hookScript}` },
65
+ ],
66
+ stop: [
67
+ { command: `node ${hookScript}`, loop_limit: 1 },
68
+ ],
69
+ },
70
+ _hegel: {
71
+ configHash: configHash(config),
72
+ generatedAt: new Date().toISOString(),
73
+ },
74
+ };
75
+ if (config.enableLlmAnalysis) {
76
+ const promptAnalysis = buildPromptAnalysisPrompt(config.strictness, config.observeOnly);
77
+ const responseAnalysis = buildResponseAnalysisPrompt(config.strictness, config.observeOnly);
78
+ const promptHook = {
79
+ type: "prompt",
80
+ prompt: promptAnalysis,
81
+ timeout: config.timeoutSeconds,
82
+ };
83
+ const responseHook = {
84
+ type: "prompt",
85
+ prompt: responseAnalysis,
86
+ timeout: config.timeoutSeconds,
87
+ };
88
+ if (config.model !== "auto") {
89
+ promptHook.model = config.model;
90
+ responseHook.model = config.model;
91
+ }
92
+ hooks.hooks.beforeSubmitPrompt.push(promptHook);
93
+ hooks.hooks.afterAgentResponse.push(responseHook);
94
+ }
95
+ return hooks;
96
+ }
97
+ /**
98
+ * Writes hooks.json to a target project directory.
99
+ * Returns true if the file was written, false if no update was needed.
100
+ */
101
+ /**
102
+ * Writes hooks.json to a target project directory.
103
+ * Returns true if the file was written, false if no update was needed.
104
+ * Pass force=true to always write (used by the setup CLI).
105
+ */
106
+ export async function writeHooksFile(projectPath, config, force = false) {
107
+ const cursorDir = join(projectPath, ".cursor");
108
+ const hooksFile = join(cursorDir, "hooks.json");
109
+ if (!force) {
110
+ const existingHash = await readExistingHash(hooksFile);
111
+ const currentHash = configHash(config);
112
+ if (existingHash === currentHash)
113
+ return false;
114
+ }
115
+ const hooks = generateHooksConfig(config);
116
+ await mkdir(cursorDir, { recursive: true });
117
+ await writeFile(hooksFile, JSON.stringify(hooks, null, 2) + "\n", "utf-8");
118
+ return true;
119
+ }
120
+ //# sourceMappingURL=hooks-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-generator.js","sourceRoot":"","sources":["../src/hooks-generator.ts"],"names":[],"mappings":"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"}
package/dist/mcp.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import type { SessionState } from "./types.js";
3
+ export declare function resolveWorkspaceRoot(argv?: string[], cwd?: string): string;
4
+ export declare function stateDirForWorkspace(workspaceRoot: string): string;
5
+ export declare function getMostRecentSession(stateDir: string, now?: number): Promise<SessionState | null>;
6
+ export declare function buildStatusText(session: SessionState): string;
7
+ export declare function buildReviewText(session: SessionState): string;
8
+ export declare function createServer(stateDir: string): Server;
9
+ export declare function runMcpServer(stateDir?: string): Promise<void>;
10
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AASnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAQ/C,wBAAgB,oBAAoB,CAAC,IAAI,GAAE,MAAM,EAAiB,EAAE,GAAG,GAAE,MAAsB,GAAG,MAAM,CAgBvG;AAED,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAmB,GACvB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CA0B9B;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAwB7D;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CA6B7D;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAkErD;AAED,wBAAsB,YAAY,CAAC,QAAQ,GAAE,MAAqD,iBAIjG"}