@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.
- package/README.md +84 -0
- package/dist/analyzers/prompt-analyzer.d.ts +7 -0
- package/dist/analyzers/prompt-analyzer.d.ts.map +1 -0
- package/dist/analyzers/prompt-analyzer.js +224 -0
- package/dist/analyzers/prompt-analyzer.js.map +1 -0
- package/dist/analyzers/response-analyzer.d.ts +6 -0
- package/dist/analyzers/response-analyzer.d.ts.map +1 -0
- package/dist/analyzers/response-analyzer.js +218 -0
- package/dist/analyzers/response-analyzer.js.map +1 -0
- package/dist/analyzers/session-analyzer.d.ts +10 -0
- package/dist/analyzers/session-analyzer.d.ts.map +1 -0
- package/dist/analyzers/session-analyzer.js +194 -0
- package/dist/analyzers/session-analyzer.js.map +1 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +27 -0
- package/dist/config.js.map +1 -0
- package/dist/debug-wrapper.d.ts +2 -0
- package/dist/debug-wrapper.d.ts.map +1 -0
- package/dist/debug-wrapper.js +55 -0
- package/dist/debug-wrapper.js.map +1 -0
- package/dist/dev-watch.d.ts +10 -0
- package/dist/dev-watch.d.ts.map +1 -0
- package/dist/dev-watch.js +55 -0
- package/dist/dev-watch.js.map +1 -0
- package/dist/format.d.ts +4 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +38 -0
- package/dist/format.js.map +1 -0
- package/dist/hook.d.ts +8 -0
- package/dist/hook.d.ts.map +1 -0
- package/dist/hook.js +320 -0
- package/dist/hook.js.map +1 -0
- package/dist/hooks-generator.d.ts +45 -0
- package/dist/hooks-generator.d.ts.map +1 -0
- package/dist/hooks-generator.js +120 -0
- package/dist/hooks-generator.js.map +1 -0
- package/dist/mcp.d.ts +10 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +173 -0
- package/dist/mcp.js.map +1 -0
- package/dist/prompts.d.ts +11 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +85 -0
- package/dist/prompts.js.map +1 -0
- package/dist/setup.d.ts +28 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +247 -0
- package/dist/setup.js.map +1 -0
- package/dist/state.d.ts +14 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +77 -0
- package/dist/state.js.map +1 -0
- package/dist/transcript.d.ts +32 -0
- package/dist/transcript.d.ts.map +1 -0
- package/dist/transcript.js +156 -0
- package/dist/transcript.js.map +1 -0
- package/dist/types.d.ts +137 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/hegel-vscode/hegel-companion-1.0.0.vsix +0 -0
- package/hegel.config.schema.json +63 -0
- package/package.json +59 -0
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { readdir, stat, readFile } from "node:fs/promises";
|
|
5
|
+
import { join, isAbsolute } from "node:path";
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
7
|
+
import { sessionDurationMinutes, totalFilesEdited, totalLinesChanged } from "./state.js";
|
|
8
|
+
// Look for .hegel-state in the directory where the MCP server was launched
|
|
9
|
+
// Cursor launches MCP servers with the workspace root as the CWD.
|
|
10
|
+
// If process.argv[2] is provided, use that as the workspace root instead.
|
|
11
|
+
const ACTIVE_SESSION_MAX_AGE_MS = 4 * 60 * 60 * 1000;
|
|
12
|
+
export function resolveWorkspaceRoot(argv = process.argv, cwd = process.cwd()) {
|
|
13
|
+
// 1. Explicit environment variable (bulletproof across all shells/spawners)
|
|
14
|
+
if (process.env.HEGEL_WORKSPACE_ROOT) {
|
|
15
|
+
return process.env.HEGEL_WORKSPACE_ROOT;
|
|
16
|
+
}
|
|
17
|
+
// 2. Fallback to argument parsing
|
|
18
|
+
// When run via npx, argv looks like:
|
|
19
|
+
// [0] node
|
|
20
|
+
// [1] .../mcp.js
|
|
21
|
+
// [2] hegel-mcp (sometimes, depending on npx version/args)
|
|
22
|
+
// [3] C:\Projects\CopybarasCircle
|
|
23
|
+
// Find the first argument that looks like an absolute path or exists after the script name
|
|
24
|
+
const pathArg = argv.slice(2).find(arg => arg !== "hegel-mcp" && arg !== "--");
|
|
25
|
+
return pathArg ? (isAbsolute(pathArg) ? pathArg : join(cwd, pathArg)) : cwd;
|
|
26
|
+
}
|
|
27
|
+
export function stateDirForWorkspace(workspaceRoot) {
|
|
28
|
+
return join(workspaceRoot, ".hegel-state");
|
|
29
|
+
}
|
|
30
|
+
export async function getMostRecentSession(stateDir, now = Date.now()) {
|
|
31
|
+
try {
|
|
32
|
+
const files = await readdir(stateDir);
|
|
33
|
+
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
34
|
+
if (jsonFiles.length === 0)
|
|
35
|
+
return null;
|
|
36
|
+
const stats = await Promise.all(jsonFiles.map(async (f) => {
|
|
37
|
+
const fullPath = join(stateDir, f);
|
|
38
|
+
const s = await stat(fullPath);
|
|
39
|
+
return { name: f, fullPath, mtime: s.mtimeMs };
|
|
40
|
+
}));
|
|
41
|
+
stats.sort((a, b) => b.mtime - a.mtime);
|
|
42
|
+
const raw = await readFile(stats[0].fullPath, "utf-8");
|
|
43
|
+
const session = JSON.parse(raw);
|
|
44
|
+
if (now - session.startedAt > ACTIVE_SESSION_MAX_AGE_MS) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return session;
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
// console.error(`Failed to read state dir ${STATE_DIR}:`, err);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function buildStatusText(session) {
|
|
55
|
+
const duration = Math.round(sessionDurationMinutes(session));
|
|
56
|
+
const activeConcerns = session.concerns.slice(-5).reverse();
|
|
57
|
+
let statusText = `Hegel Session Status (ID: ${session.conversationId.slice(0, 8)})\n`;
|
|
58
|
+
statusText += `Duration: ${duration}m | Turns: ${session.turnCount} | Compactions: ${session.compactionCount}\n\n`;
|
|
59
|
+
if (activeConcerns.length === 0) {
|
|
60
|
+
statusText += "Health: CLEAN\nNo recent concerns detected.";
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
const criticalCount = session.concerns.filter(c => c.severity === "critical").length;
|
|
64
|
+
const warningCount = session.concerns.filter(c => c.severity === "warning").length;
|
|
65
|
+
statusText += `Health: ${criticalCount > 0 ? "CRITICAL" : warningCount > 0 ? "WARNING" : "INFO"}\n`;
|
|
66
|
+
statusText += `Total Concerns: ${session.concerns.length} (${criticalCount} critical, ${warningCount} warning)\n\n`;
|
|
67
|
+
statusText += "Recent Concerns:\n";
|
|
68
|
+
for (const c of activeConcerns) {
|
|
69
|
+
statusText += `- [${c.severity.toUpperCase()}] ${c.category}: ${c.message}\n`;
|
|
70
|
+
if (c.suggestion)
|
|
71
|
+
statusText += ` Suggestion: ${c.suggestion}\n`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return statusText;
|
|
75
|
+
}
|
|
76
|
+
export function buildReviewText(session) {
|
|
77
|
+
const duration = Math.round(sessionDurationMinutes(session));
|
|
78
|
+
const filesEdited = totalFilesEdited(session);
|
|
79
|
+
const linesChanged = totalLinesChanged(session);
|
|
80
|
+
let reviewText = `Hegel Comprehensive Session Review (ID: ${session.conversationId.slice(0, 8)})\n`;
|
|
81
|
+
reviewText += `Duration: ${duration}m | Turns: ${session.turnCount} | Files Edited: ${filesEdited} | Lines Changed: ${linesChanged} | Compactions: ${session.compactionCount}\n\n`;
|
|
82
|
+
if (session.concerns.length === 0) {
|
|
83
|
+
reviewText += "Session was completely clean. Excellent workflow!";
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
const byCategory = new Map();
|
|
87
|
+
for (const c of session.concerns) {
|
|
88
|
+
byCategory.set(c.category, (byCategory.get(c.category) || 0) + 1);
|
|
89
|
+
}
|
|
90
|
+
reviewText += "Concern Categories Summary:\n";
|
|
91
|
+
for (const [cat, count] of byCategory.entries()) {
|
|
92
|
+
reviewText += `- ${cat}: ${count} occurrences\n`;
|
|
93
|
+
}
|
|
94
|
+
reviewText += "\nDetailed Concerns Log:\n";
|
|
95
|
+
for (const c of session.concerns) {
|
|
96
|
+
reviewText += `- [${c.severity.toUpperCase()}] ${c.category}: ${c.message}\n`;
|
|
97
|
+
if (c.suggestion)
|
|
98
|
+
reviewText += ` Suggestion: ${c.suggestion}\n`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return reviewText;
|
|
102
|
+
}
|
|
103
|
+
export function createServer(stateDir) {
|
|
104
|
+
const server = new Server({
|
|
105
|
+
name: "hegel-mcp",
|
|
106
|
+
version: "1.0.0",
|
|
107
|
+
}, {
|
|
108
|
+
capabilities: {
|
|
109
|
+
tools: {},
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
113
|
+
return {
|
|
114
|
+
tools: [
|
|
115
|
+
{
|
|
116
|
+
name: "hegel-status",
|
|
117
|
+
description: "Fetch the real-time health status of the current Hegel session. Use this mid-task to check for context drift, prompt degradation, or other concerns.",
|
|
118
|
+
inputSchema: {
|
|
119
|
+
type: "object",
|
|
120
|
+
properties: {},
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: "hegel-review",
|
|
125
|
+
description: "Fetch a comprehensive retrospective of the current Hegel session. Use this at the end of a major task to summarize the session's health and workflow.",
|
|
126
|
+
inputSchema: {
|
|
127
|
+
type: "object",
|
|
128
|
+
properties: {},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
135
|
+
const session = await getMostRecentSession(stateDir);
|
|
136
|
+
if (!session) {
|
|
137
|
+
return {
|
|
138
|
+
content: [
|
|
139
|
+
{
|
|
140
|
+
type: "text",
|
|
141
|
+
text: "No active Hegel session found. Ensure you are in a Cursor workspace with Hegel initialized.",
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
if (request.params.name === "hegel-status") {
|
|
147
|
+
return {
|
|
148
|
+
content: [{ type: "text", text: buildStatusText(session) }],
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
if (request.params.name === "hegel-review") {
|
|
152
|
+
return {
|
|
153
|
+
content: [{ type: "text", text: buildReviewText(session) }],
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
throw new Error(`Unknown tool: ${request.params.name}`);
|
|
157
|
+
});
|
|
158
|
+
return server;
|
|
159
|
+
}
|
|
160
|
+
export async function runMcpServer(stateDir = stateDirForWorkspace(resolveWorkspaceRoot())) {
|
|
161
|
+
const server = createServer(stateDir);
|
|
162
|
+
const transport = new StdioServerTransport();
|
|
163
|
+
await server.connect(transport);
|
|
164
|
+
}
|
|
165
|
+
function isEntrypoint() {
|
|
166
|
+
return !process.env.VITEST &&
|
|
167
|
+
!!process.argv[1] &&
|
|
168
|
+
import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
169
|
+
}
|
|
170
|
+
if (isEntrypoint()) {
|
|
171
|
+
runMcpServer().catch(console.error);
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM prompt templates for Hegel's Layer 2 deep analysis.
|
|
3
|
+
*
|
|
4
|
+
* Prompt-based hooks in Cursor return { ok: boolean, reason?: string }.
|
|
5
|
+
* When ok=false, Cursor blocks the action and shows the reason.
|
|
6
|
+
* $ARGUMENTS is auto-replaced with the hook input JSON.
|
|
7
|
+
*/
|
|
8
|
+
export type StrictnessLevel = "relaxed" | "balanced" | "strict";
|
|
9
|
+
export declare function buildPromptAnalysisPrompt(strictness: StrictnessLevel, bypass: boolean): string;
|
|
10
|
+
export declare function buildResponseAnalysisPrompt(strictness: StrictnessLevel, bypass: boolean): string;
|
|
11
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;AAWhE,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAqC9F;AAED,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAmChG"}
|
package/dist/prompts.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM prompt templates for Hegel's Layer 2 deep analysis.
|
|
3
|
+
*
|
|
4
|
+
* Prompt-based hooks in Cursor return { ok: boolean, reason?: string }.
|
|
5
|
+
* When ok=false, Cursor blocks the action and shows the reason.
|
|
6
|
+
* $ARGUMENTS is auto-replaced with the hook input JSON.
|
|
7
|
+
*/
|
|
8
|
+
const STRICTNESS_GUIDANCE = {
|
|
9
|
+
relaxed: "Only flag serious issues — vague one-word prompts, clearly dangerous operations, or missing context that will definitely cause problems. Let most prompts through.",
|
|
10
|
+
balanced: "Flag prompts that lack specificity, miss acceptance criteria for significant tasks, or skip verification after major changes. Allow clear, purposeful prompts even if brief.",
|
|
11
|
+
strict: "Scrutinize every prompt rigorously. Question assumptions, demand explicit acceptance criteria, flag any missing context, and challenge prompts that don't reference specific files or behaviors.",
|
|
12
|
+
};
|
|
13
|
+
export function buildPromptAnalysisPrompt(strictness, bypass) {
|
|
14
|
+
const bypassBlock = bypass
|
|
15
|
+
? `## OBSERVE-ONLY MODE (ACTIVE)
|
|
16
|
+
|
|
17
|
+
You are in observe-only mode. This is a hard rule that overrides everything below.
|
|
18
|
+
- **You MUST always return ok=true.** Never return ok=false. Never block the prompt.
|
|
19
|
+
- Still provide your full analysis in the reason field so it gets logged for tuning.
|
|
20
|
+
- Format the reason as: "OBSERVE: <your analysis here>"
|
|
21
|
+
|
|
22
|
+
`
|
|
23
|
+
: "";
|
|
24
|
+
return `You are Hegel, a dialectical critical thinking companion for AI-assisted software development.
|
|
25
|
+
|
|
26
|
+
Your role: analyze the developer's prompt BEFORE it reaches the AI coding assistant. You are the antithesis — challenging the thesis (the prompt) so the developer reaches a better synthesis.
|
|
27
|
+
|
|
28
|
+
${bypassBlock}## Evaluation criteria
|
|
29
|
+
|
|
30
|
+
1. **Clarity**: Is the intent specific enough for an AI to act on without guessing?
|
|
31
|
+
2. **Context**: Does the prompt reference concrete files, functions, behaviors, or error messages — or does it rely on ambiguous pronouns and implicit context?
|
|
32
|
+
3. **Scope**: Is the task well-bounded, or could it spiral into uncontrolled changes?
|
|
33
|
+
4. **Verification**: For significant changes (refactoring, architecture, security), does the developer mention how to verify the result?
|
|
34
|
+
5. **Critical thinking**: Is the developer blindly continuing from a previous AI response without questioning it?
|
|
35
|
+
|
|
36
|
+
## Strictness level: ${strictness}
|
|
37
|
+
${STRICTNESS_GUIDANCE[strictness]}
|
|
38
|
+
|
|
39
|
+
## Instructions
|
|
40
|
+
|
|
41
|
+
Analyze the user prompt provided in $ARGUMENTS (the "prompt" field).
|
|
42
|
+
|
|
43
|
+
- If the prompt is adequate for its purpose, return ok=true.
|
|
44
|
+
- If there are genuine concerns, return ok=false with a concise reason (1-2 sentences) explaining what's missing and how to improve it.
|
|
45
|
+
- Do NOT be pedantic about short prompts if they are clear in context (e.g., "yes, proceed" after a detailed plan is fine).
|
|
46
|
+
- Do NOT flag prompts that are questions or requests for explanation.
|
|
47
|
+
- Do NOT flag follow-up directives that reference items from a previous AI response (e.g., "fix #3 and #5" referencing a numbered list the AI just provided).
|
|
48
|
+
- Focus on prompts that will lead to CODE CHANGES without sufficient guidance.`;
|
|
49
|
+
}
|
|
50
|
+
export function buildResponseAnalysisPrompt(strictness, bypass) {
|
|
51
|
+
const bypassBlock = bypass
|
|
52
|
+
? `## OBSERVE-ONLY MODE (ACTIVE)
|
|
53
|
+
|
|
54
|
+
You are in observe-only mode. This is a hard rule that overrides everything below.
|
|
55
|
+
- **You MUST always return ok=true.** Never return ok=false. Never block the response.
|
|
56
|
+
- Still provide your full analysis in the reason field so it gets logged for tuning.
|
|
57
|
+
- Format the reason as: "OBSERVE: <your analysis here>"
|
|
58
|
+
|
|
59
|
+
`
|
|
60
|
+
: "";
|
|
61
|
+
return `You are Hegel, a dialectical critical thinking companion reviewing an AI coding assistant's response.
|
|
62
|
+
|
|
63
|
+
Your role: identify red flags in the AI's output that the developer should be aware of before accepting the changes.
|
|
64
|
+
|
|
65
|
+
${bypassBlock}## What to look for
|
|
66
|
+
|
|
67
|
+
1. **Overconfidence**: Claims like "this will definitely work" or "all issues resolved" without caveats
|
|
68
|
+
2. **Missing edge cases**: The AI solved the happy path but didn't mention error handling, boundary conditions, or failure modes
|
|
69
|
+
3. **Scope creep**: The AI changed more than what was asked for, or made architectural decisions without explicit approval
|
|
70
|
+
4. **Untested claims**: Significant changes proposed without any mention of testing or verification
|
|
71
|
+
5. **Security blind spots**: Changes touching auth, permissions, secrets, or user data without security considerations
|
|
72
|
+
6. **Sycophancy**: The AI agrees with everything the developer says without pushing back on questionable decisions
|
|
73
|
+
|
|
74
|
+
## Strictness level: ${strictness}
|
|
75
|
+
${STRICTNESS_GUIDANCE[strictness]}
|
|
76
|
+
|
|
77
|
+
## Instructions
|
|
78
|
+
|
|
79
|
+
Analyze the AI assistant's response provided in $ARGUMENTS (the "text" field).
|
|
80
|
+
|
|
81
|
+
- If the response appears reasonable and well-considered, return ok=true.
|
|
82
|
+
- If there are red flags the developer should notice, return ok=false with a concise reason (1-2 sentences) describing the concern.
|
|
83
|
+
- Be practical — not every response needs a lecture. Focus on things that could lead to real problems.`;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,mBAAmB,GAAoC;IAC3D,OAAO,EACL,oKAAoK;IACtK,QAAQ,EACN,8KAA8K;IAChL,MAAM,EACJ,kMAAkM;CACrM,CAAC;AAEF,MAAM,UAAU,yBAAyB,CAAC,UAA2B,EAAE,MAAe;IACpF,MAAM,WAAW,GAAG,MAAM;QACxB,CAAC,CAAC;;;;;;;CAOL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;EAIP,WAAW;;;;;;;;uBAQU,UAAU;EAC/B,mBAAmB,CAAC,UAAU,CAAC;;;;;;;;;;;+EAW8C,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,UAA2B,EAAE,MAAe;IACtF,MAAM,WAAW,GAAG,MAAM;QACxB,CAAC,CAAC;;;;;;;CAOL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;EAIP,WAAW;;;;;;;;;uBASU,UAAU;EAC/B,mBAAmB,CAAC,UAAU,CAAC;;;;;;;;uGAQsE,CAAC;AACxG,CAAC"}
|
package/dist/setup.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { mkdir, writeFile, readdir, readFile, access } from "node:fs/promises";
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { writeHooksFile } from "./hooks-generator.js";
|
|
5
|
+
import type { HegelConfig } from "./config.js";
|
|
6
|
+
export declare const COMPANION_RULE = "# Hegel Companion Rule\n\nYou are working in a project that uses Hegel, a dialectical companion for AI-assisted development.\nHegel monitors your prompts and responses for quality, context drift, and session health.\n\n## MCP Tools Available\n\nYou have access to the `hegel-mcp` server which provides two tools:\n1. `hegel-status`: Fetch the real-time health status of the current session.\n2. `hegel-review`: Fetch a comprehensive retrospective of the session.\n\n## When to use these tools\n\n- **Proactive Self-Correction**: If the user seems frustrated, repeats the same prompt, or if you feel the conversation is losing focus, call `hegel-status` to check if Hegel has flagged `context-drift` or `prompt-degradation`. Adjust your behavior accordingly.\n- **End-of-Task Summaries**: When completing a significant multi-step task, call `hegel-review` and append a brief session health summary to your final response.\n- **Transparency**: If Hegel blocks a prompt or flags a critical concern, acknowledge it and help the user formulate a better prompt.\n";
|
|
7
|
+
interface SetupDeps {
|
|
8
|
+
loadConfig: (workspaceRoot?: string) => Promise<HegelConfig>;
|
|
9
|
+
writeHooksFile: typeof writeHooksFile;
|
|
10
|
+
mkdir: typeof mkdir;
|
|
11
|
+
writeFile: typeof writeFile;
|
|
12
|
+
readdir: typeof readdir;
|
|
13
|
+
readFile: typeof readFile;
|
|
14
|
+
access: typeof access;
|
|
15
|
+
execFileSync: typeof execFileSync;
|
|
16
|
+
log: (message: string) => void;
|
|
17
|
+
error: (message: string) => void;
|
|
18
|
+
resolveHegelRoot: () => string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Walks up from `startDir` (exclusive) looking for an ancestor that already
|
|
22
|
+
* contains a Hegel install (hegel.config.json + .cursor/hooks.json).
|
|
23
|
+
* Returns the ancestor path if found, or null. Stops at the filesystem root.
|
|
24
|
+
*/
|
|
25
|
+
export declare function findAncestorHegelInstall(startDir: string, accessFn?: typeof access): Promise<string | null>;
|
|
26
|
+
export declare function runSetup(argv?: string[], deps?: SetupDeps): Promise<number>;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAAE,cAAc,EAAc,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,eAAO,MAAM,cAAc,siCAgB1B,CAAC;AAEF,UAAU,SAAS;IACjB,UAAU,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7D,cAAc,EAAE,OAAO,cAAc,CAAC;IACtC,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,OAAO,EAAE,OAAO,OAAO,CAAC;IACxB,QAAQ,EAAE,OAAO,QAAQ,CAAC;IAC1B,MAAM,EAAE,OAAO,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,gBAAgB,EAAE,MAAM,MAAM,CAAC;CAChC;AAgBD;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,OAAO,MAAe,GAC/B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkBxB;AAED,wBAAsB,QAAQ,CAC5B,IAAI,GAAE,MAAM,EAAiB,EAC7B,IAAI,GAAE,SAAuB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAuLjB"}
|
package/dist/setup.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve, join, dirname, parse } from "node:path";
|
|
3
|
+
import { mkdir, writeFile, readdir, readFile, access } from "node:fs/promises";
|
|
4
|
+
import { execFileSync } from "node:child_process";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
+
import { loadConfig } from "./config.js";
|
|
7
|
+
import { writeHooksFile, configHash } from "./hooks-generator.js";
|
|
8
|
+
export const COMPANION_RULE = `# Hegel Companion Rule
|
|
9
|
+
|
|
10
|
+
You are working in a project that uses Hegel, a dialectical companion for AI-assisted development.
|
|
11
|
+
Hegel monitors your prompts and responses for quality, context drift, and session health.
|
|
12
|
+
|
|
13
|
+
## MCP Tools Available
|
|
14
|
+
|
|
15
|
+
You have access to the \`hegel-mcp\` server which provides two tools:
|
|
16
|
+
1. \`hegel-status\`: Fetch the real-time health status of the current session.
|
|
17
|
+
2. \`hegel-review\`: Fetch a comprehensive retrospective of the session.
|
|
18
|
+
|
|
19
|
+
## When to use these tools
|
|
20
|
+
|
|
21
|
+
- **Proactive Self-Correction**: If the user seems frustrated, repeats the same prompt, or if you feel the conversation is losing focus, call \`hegel-status\` to check if Hegel has flagged \`context-drift\` or \`prompt-degradation\`. Adjust your behavior accordingly.
|
|
22
|
+
- **End-of-Task Summaries**: When completing a significant multi-step task, call \`hegel-review\` and append a brief session health summary to your final response.
|
|
23
|
+
- **Transparency**: If Hegel blocks a prompt or flags a critical concern, acknowledge it and help the user formulate a better prompt.
|
|
24
|
+
`;
|
|
25
|
+
const defaultDeps = {
|
|
26
|
+
loadConfig,
|
|
27
|
+
writeHooksFile,
|
|
28
|
+
mkdir,
|
|
29
|
+
writeFile,
|
|
30
|
+
readdir,
|
|
31
|
+
readFile,
|
|
32
|
+
access,
|
|
33
|
+
execFileSync,
|
|
34
|
+
log: console.log,
|
|
35
|
+
error: console.error,
|
|
36
|
+
resolveHegelRoot: () => resolve(join(dirname(fileURLToPath(import.meta.url)), "..")),
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Walks up from `startDir` (exclusive) looking for an ancestor that already
|
|
40
|
+
* contains a Hegel install (hegel.config.json + .cursor/hooks.json).
|
|
41
|
+
* Returns the ancestor path if found, or null. Stops at the filesystem root.
|
|
42
|
+
*/
|
|
43
|
+
export async function findAncestorHegelInstall(startDir, accessFn = access) {
|
|
44
|
+
const root = parse(startDir).root;
|
|
45
|
+
let current = dirname(startDir);
|
|
46
|
+
while (current && current !== root) {
|
|
47
|
+
try {
|
|
48
|
+
await accessFn(join(current, "hegel.config.json"));
|
|
49
|
+
await accessFn(join(current, ".cursor", "hooks.json"));
|
|
50
|
+
return current;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// keep walking up
|
|
54
|
+
}
|
|
55
|
+
const parent = dirname(current);
|
|
56
|
+
if (parent === current)
|
|
57
|
+
break;
|
|
58
|
+
current = parent;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
export async function runSetup(argv = process.argv, deps = defaultDeps) {
|
|
63
|
+
const rest = argv.slice(2);
|
|
64
|
+
const forceFlag = rest.includes("--force");
|
|
65
|
+
const positional = rest.filter((a) => !a.startsWith("--"));
|
|
66
|
+
let targetDir = positional[0];
|
|
67
|
+
if (targetDir === "init" && positional[1]) {
|
|
68
|
+
targetDir = positional[1];
|
|
69
|
+
}
|
|
70
|
+
// Catch the common typo `npx hegel-companion init init` — argv[3]==="init"
|
|
71
|
+
// was being treated as the target path, scaffolding into ./init/.
|
|
72
|
+
if (targetDir === "init") {
|
|
73
|
+
deps.error("Error: 'init' is not a valid project path.");
|
|
74
|
+
deps.error(" Did you mean: npx hegel-companion init .");
|
|
75
|
+
return 1;
|
|
76
|
+
}
|
|
77
|
+
if (!targetDir) {
|
|
78
|
+
deps.log("Usage: npx hegel-companion init <project-path>");
|
|
79
|
+
deps.log("");
|
|
80
|
+
deps.log("Generates .cursor/hooks.json in the target project with Hegel hooks.");
|
|
81
|
+
deps.log("Use '.' for the current directory. Pass --force to bypass safety checks.");
|
|
82
|
+
deps.log("");
|
|
83
|
+
deps.log("Current config:");
|
|
84
|
+
const config = await deps.loadConfig();
|
|
85
|
+
deps.log(` model: ${config.model}`);
|
|
86
|
+
deps.log(` enableLlmAnalysis: ${config.enableLlmAnalysis}`);
|
|
87
|
+
deps.log(` timeoutSeconds: ${config.timeoutSeconds}s`);
|
|
88
|
+
deps.log(` strictness: ${config.strictness}`);
|
|
89
|
+
deps.log(` observeOnly: ${config.observeOnly}`);
|
|
90
|
+
deps.log(` configHash: ${configHash(config)}`);
|
|
91
|
+
return 1;
|
|
92
|
+
}
|
|
93
|
+
const projectPath = resolve(targetDir);
|
|
94
|
+
// Refuse to nest a Hegel install inside another one. This catches e.g.
|
|
95
|
+
// `init hegel-mcp` being run from a workspace that already has Hegel set up,
|
|
96
|
+
// which would silently create an orphan .cursor/ and hegel.config.json that
|
|
97
|
+
// Cursor never reads.
|
|
98
|
+
const ancestor = await findAncestorHegelInstall(projectPath, deps.access);
|
|
99
|
+
if (ancestor && !forceFlag) {
|
|
100
|
+
deps.error(`Error: ${ancestor} already has a Hegel install.`);
|
|
101
|
+
deps.error(` Refusing to scaffold a nested install at ${projectPath}.`);
|
|
102
|
+
deps.error(` If this is intentional, rerun with --force.`);
|
|
103
|
+
return 1;
|
|
104
|
+
}
|
|
105
|
+
const config = await deps.loadConfig(projectPath);
|
|
106
|
+
const hooksFile = join(projectPath, ".cursor", "hooks.json");
|
|
107
|
+
const hegelRoot = deps.resolveHegelRoot();
|
|
108
|
+
// Source-repo mode: when `init` targets the Hegel repo itself, Cursor's
|
|
109
|
+
// MCP server lives at `<hegelRoot>/dist/mcp.js`, not at
|
|
110
|
+
// `node_modules/@hegel-dev/companion/dist/mcp.js`. Detect this and emit an
|
|
111
|
+
// absolute local path so running the CLI inside the source repo doesn't
|
|
112
|
+
// silently break the MCP config.
|
|
113
|
+
const isSourceRepo = resolve(projectPath) === resolve(hegelRoot);
|
|
114
|
+
// Pre-flight report: if an existing install is present, tell the user what
|
|
115
|
+
// we're about to touch before doing it. Without --force, a matching config
|
|
116
|
+
// hash makes hooks.json a no-op (see writeHooksFile); this prevents
|
|
117
|
+
// accidental rewrites that change `generatedAt` for no functional reason.
|
|
118
|
+
const existingHooks = await deps.readFile(hooksFile, "utf-8").catch(() => null);
|
|
119
|
+
if (existingHooks) {
|
|
120
|
+
deps.log(`Existing Hegel install detected at ${projectPath}.`);
|
|
121
|
+
if (isSourceRepo) {
|
|
122
|
+
deps.log(" (running against the Hegel source repo — will use local dist/ paths)");
|
|
123
|
+
}
|
|
124
|
+
if (!forceFlag) {
|
|
125
|
+
deps.log(" hooks.json will be rewritten only if the config hash differs.");
|
|
126
|
+
deps.log(" Pass --force to rewrite unconditionally.");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const hooksWritten = await deps.writeHooksFile(projectPath, config, forceFlag);
|
|
130
|
+
if (!hooksWritten && existingHooks) {
|
|
131
|
+
deps.log(`hooks.json is already up to date (config hash ${configHash(config)})`);
|
|
132
|
+
}
|
|
133
|
+
// Write the Hegel Companion rule
|
|
134
|
+
const rulesDir = join(projectPath, ".cursor", "rules");
|
|
135
|
+
await deps.mkdir(rulesDir, { recursive: true });
|
|
136
|
+
await deps.writeFile(join(rulesDir, "hegel-companion.mdc"), COMPANION_RULE, "utf-8");
|
|
137
|
+
// Scaffold hegel.config.json if it doesn't exist
|
|
138
|
+
const configPath = join(projectPath, "hegel.config.json");
|
|
139
|
+
try {
|
|
140
|
+
const existingConfig = await deps.readFile(configPath, "utf-8").catch(() => null);
|
|
141
|
+
if (!existingConfig) {
|
|
142
|
+
const defaultConfig = {
|
|
143
|
+
"$schema": isSourceRepo
|
|
144
|
+
? "./hegel.config.schema.json"
|
|
145
|
+
: "./node_modules/@hegel-dev/companion/hegel.config.schema.json",
|
|
146
|
+
"model": "auto",
|
|
147
|
+
"enableLlmAnalysis": true,
|
|
148
|
+
"timeoutSeconds": 15,
|
|
149
|
+
"strictness": "balanced",
|
|
150
|
+
"observeOnly": true
|
|
151
|
+
};
|
|
152
|
+
await deps.writeFile(configPath, JSON.stringify(defaultConfig, null, 2) + "\n", "utf-8");
|
|
153
|
+
deps.log(`✅ Default hegel.config.json created`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Ignore
|
|
158
|
+
}
|
|
159
|
+
// Register MCP server in .cursor/mcp.json
|
|
160
|
+
const mcpConfigPath = join(projectPath, ".cursor", "mcp.json");
|
|
161
|
+
try {
|
|
162
|
+
let mcpConfig = { mcpServers: {} };
|
|
163
|
+
const existingMcp = await deps.readFile(mcpConfigPath, "utf-8").catch(() => null);
|
|
164
|
+
if (existingMcp) {
|
|
165
|
+
mcpConfig = JSON.parse(existingMcp);
|
|
166
|
+
if (!mcpConfig.mcpServers)
|
|
167
|
+
mcpConfig.mcpServers = {};
|
|
168
|
+
}
|
|
169
|
+
// We use a direct node command rather than npx because Cursor's internal
|
|
170
|
+
// MCP spawner on Windows often fails to pass environment variables or
|
|
171
|
+
// trailing arguments correctly through npx. In source-repo mode we point
|
|
172
|
+
// at the local build; in consumer mode, at the node_modules install.
|
|
173
|
+
const mcpArgs = isSourceRepo
|
|
174
|
+
? [join(hegelRoot, "dist", "mcp.js").replace(/\\/g, "/")]
|
|
175
|
+
: ["node_modules/@hegel-dev/companion/dist/mcp.js"];
|
|
176
|
+
mcpConfig.mcpServers["hegel-mcp"] = {
|
|
177
|
+
command: "node",
|
|
178
|
+
args: mcpArgs,
|
|
179
|
+
env: {
|
|
180
|
+
"HEGEL_WORKSPACE_ROOT": projectPath
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
await deps.writeFile(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + "\n", "utf-8");
|
|
184
|
+
deps.log(`✅ MCP server registered in .cursor/mcp.json`);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
deps.log("Failed to register MCP server in .cursor/mcp.json");
|
|
188
|
+
}
|
|
189
|
+
// Find and install the VS Code extension
|
|
190
|
+
const vscodeDir = join(hegelRoot, "hegel-vscode");
|
|
191
|
+
try {
|
|
192
|
+
const files = await deps.readdir(vscodeDir);
|
|
193
|
+
const vsixFile = files.find(f => f.endsWith(".vsix"));
|
|
194
|
+
if (vsixFile) {
|
|
195
|
+
const vsixPath = join(vscodeDir, vsixFile);
|
|
196
|
+
deps.log(`Installing VS Code extension: ${vsixFile}...`);
|
|
197
|
+
deps.execFileSync("cursor", ["--install-extension", vsixPath], { stdio: "inherit" });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
deps.log("Could not install VS Code extension automatically.");
|
|
202
|
+
}
|
|
203
|
+
const model = config.model === "auto" ? "Cursor default" : config.model;
|
|
204
|
+
const mode = config.observeOnly ? "observe-only (silent — full analysis, no chat intervention)" : "active (will block on concerns)";
|
|
205
|
+
deps.log("");
|
|
206
|
+
deps.log(`✅ Hegel hooks written to ${hooksFile}`);
|
|
207
|
+
deps.log(`✅ Hegel Companion Rule written to ${join(rulesDir, "hegel-companion.mdc")}`);
|
|
208
|
+
deps.log(` Config hash: ${configHash(config)}`);
|
|
209
|
+
deps.log("");
|
|
210
|
+
deps.log(`Mode: ${mode}`);
|
|
211
|
+
deps.log("");
|
|
212
|
+
deps.log("Layers:");
|
|
213
|
+
deps.log(` Layer 1: Rule-based analysis (command hooks) — ${config.observeOnly ? "full analysis, no chat intervention" : "blocks on warning+"}`);
|
|
214
|
+
if (config.enableLlmAnalysis) {
|
|
215
|
+
deps.log(` Layer 2: LLM deep analysis (prompt hooks) — model: ${model} — ${config.observeOnly ? "full analysis, no chat intervention" : "blocks on concern"}`);
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
deps.log(" Layer 2: LLM deep analysis — disabled (enableLlmAnalysis=false)");
|
|
219
|
+
}
|
|
220
|
+
if (config.observeOnly) {
|
|
221
|
+
deps.log("");
|
|
222
|
+
deps.log(" observeOnly is ON — both layers run full analysis and collect stats,");
|
|
223
|
+
deps.log(" but the user never sees intervention in the chat.");
|
|
224
|
+
deps.log(" Set observeOnly=false in hegel.config.json to enable blocking.");
|
|
225
|
+
}
|
|
226
|
+
deps.log("");
|
|
227
|
+
deps.log("Hot-reload: config changes are auto-detected on the next prompt.");
|
|
228
|
+
deps.log(" Change hegel.config.json → hooks.json is regenerated on the next");
|
|
229
|
+
deps.log(" beforeSubmitPrompt hook. Model changes on Layer 2 prompt hooks");
|
|
230
|
+
deps.log(" usually require a full Cursor restart to take effect.");
|
|
231
|
+
return 0;
|
|
232
|
+
}
|
|
233
|
+
function isEntrypoint() {
|
|
234
|
+
return !process.env.VITEST &&
|
|
235
|
+
!!process.argv[1] &&
|
|
236
|
+
import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
237
|
+
}
|
|
238
|
+
if (isEntrypoint()) {
|
|
239
|
+
runSetup().then((exitCode) => {
|
|
240
|
+
if (exitCode !== 0)
|
|
241
|
+
process.exit(exitCode);
|
|
242
|
+
}).catch((err) => {
|
|
243
|
+
defaultDeps.error(`Setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
244
|
+
process.exit(1);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
|
package/dist/state.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SessionState, Concern, PromptRecord, ResponseRecord, FileEditRecord } from "./types.js";
|
|
2
|
+
export declare function isSafeConversationId(conversationId: string): boolean;
|
|
3
|
+
export declare function loadState(conversationId: string): Promise<SessionState>;
|
|
4
|
+
export declare function saveState(state: SessionState): Promise<void>;
|
|
5
|
+
export declare function addPrompt(state: SessionState, record: PromptRecord): void;
|
|
6
|
+
export declare function addResponse(state: SessionState, record: ResponseRecord): void;
|
|
7
|
+
export declare function addFileEdit(state: SessionState, record: FileEditRecord): void;
|
|
8
|
+
export declare function addConcern(state: SessionState, concern: Concern): void;
|
|
9
|
+
export declare function recentPrompts(state: SessionState, count?: number): PromptRecord[];
|
|
10
|
+
export declare function sessionDurationMinutes(state: SessionState): number;
|
|
11
|
+
export declare function totalFilesEdited(state: SessionState): number;
|
|
12
|
+
export declare function totalLinesChanged(state: SessionState): number;
|
|
13
|
+
export declare function recordModel(state: SessionState, model: string): void;
|
|
14
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EACZ,OAAO,EACP,YAAY,EACZ,cAAc,EACd,cAAc,EACf,MAAM,YAAY,CAAC;AAkBpB,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAEpE;AAOD,wBAAsB,SAAS,CAC7B,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,YAAY,CAAC,CAUvB;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAUlE;AAED,wBAAgB,SAAS,CACvB,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,YAAY,GACnB,IAAI,CAGN;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,cAAc,GACrB,IAAI,CAEN;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,cAAc,GACrB,IAAI,CAEN;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,OAAO,GACf,IAAI,CAEN;AAED,wBAAgB,aAAa,CAC3B,KAAK,EAAE,YAAY,EACnB,KAAK,GAAE,MAAU,GAChB,YAAY,EAAE,CAEhB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAElE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAG5D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAE7D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAKpE"}
|