@quanvo99/ai-rules 0.1.3 → 0.1.5

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 (45) hide show
  1. package/README.md +67 -105
  2. package/dist/cli/commands/generate-questions.d.ts +7 -0
  3. package/dist/cli/commands/generate-questions.d.ts.map +1 -0
  4. package/dist/cli/commands/generate-questions.js +120 -0
  5. package/dist/cli/commands/generate-questions.js.map +1 -0
  6. package/dist/cli/commands/init.d.ts.map +1 -1
  7. package/dist/cli/commands/init.js +45 -0
  8. package/dist/cli/commands/init.js.map +1 -1
  9. package/dist/cli/lib/files.d.ts +8 -0
  10. package/dist/cli/lib/files.d.ts.map +1 -1
  11. package/dist/cli/lib/files.js +19 -0
  12. package/dist/cli/lib/files.js.map +1 -1
  13. package/dist/cli/lib/github.d.ts +9 -0
  14. package/dist/cli/lib/github.d.ts.map +1 -1
  15. package/dist/cli/lib/github.js +20 -0
  16. package/dist/cli/lib/github.js.map +1 -1
  17. package/dist/cli/lib/ollama-client.d.ts +66 -0
  18. package/dist/cli/lib/ollama-client.d.ts.map +1 -0
  19. package/dist/cli/lib/ollama-client.js +198 -0
  20. package/dist/cli/lib/ollama-client.js.map +1 -0
  21. package/dist/cli/lib/question-prompt.d.ts +37 -0
  22. package/dist/cli/lib/question-prompt.d.ts.map +1 -0
  23. package/dist/cli/lib/question-prompt.js +204 -0
  24. package/dist/cli/lib/question-prompt.js.map +1 -0
  25. package/dist/cli/lib/question-schema.d.ts +84 -0
  26. package/dist/cli/lib/question-schema.d.ts.map +1 -0
  27. package/dist/cli/lib/question-schema.js +135 -0
  28. package/dist/cli/lib/question-schema.js.map +1 -0
  29. package/dist/cli/lib/question-types.d.ts +72 -0
  30. package/dist/cli/lib/question-types.d.ts.map +1 -0
  31. package/dist/cli/lib/question-types.js +28 -0
  32. package/dist/cli/lib/question-types.js.map +1 -0
  33. package/dist/cli/lib/types.d.ts +2 -1
  34. package/dist/cli/lib/types.d.ts.map +1 -1
  35. package/dist/cli/lib/types.js +1 -0
  36. package/dist/cli/lib/types.js.map +1 -1
  37. package/dist/lib/question-types.d.ts +69 -0
  38. package/dist/lib/question-types.d.ts.map +1 -0
  39. package/dist/lib/question-types.js +3 -0
  40. package/dist/lib/question-types.js.map +1 -0
  41. package/dist/server/types.d.ts +47 -1
  42. package/dist/server/types.d.ts.map +1 -1
  43. package/dist/server/types.js +2 -1
  44. package/dist/server/types.js.map +1 -1
  45. package/package.json +1 -1
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Ollama LLM client for generating questions
3
+ * Handles connection, API calls, and response parsing
4
+ */
5
+ /**
6
+ * Configuration for Ollama client
7
+ */
8
+ interface OllamaConfig {
9
+ /** Ollama server URL */
10
+ baseUrl: string;
11
+ /** Default model to use */
12
+ defaultModel: string;
13
+ /** Request timeout in milliseconds */
14
+ timeout: number;
15
+ }
16
+ /**
17
+ * Error class for Ollama-specific errors
18
+ */
19
+ export declare class OllamaError extends Error {
20
+ statusCode?: number | undefined;
21
+ constructor(message: string, statusCode?: number | undefined);
22
+ }
23
+ /**
24
+ * Checks if Ollama server is running and accessible
25
+ * @param config - Ollama configuration
26
+ * @returns Promise that resolves to true if server is accessible, false on any error
27
+ */
28
+ export declare function checkOllamaHealth(config?: OllamaConfig): Promise<boolean>;
29
+ /**
30
+ * Calls Ollama API to generate text
31
+ * @param prompt - The prompt to send to the LLM
32
+ * @param model - Model to use (defaults to config default)
33
+ * @param config - Ollama configuration
34
+ * @returns Promise that resolves to the generated text
35
+ */
36
+ export declare function callOllama(prompt: string, model?: string, config?: OllamaConfig): Promise<string>;
37
+ /**
38
+ * Extracts JSON from LLM response text
39
+ * Handles cases where LLM returns pure JSON or wraps it in markdown code blocks
40
+ *
41
+ * @example
42
+ * // Pure JSON object
43
+ * extractJsonFromResponse('{"questions": [{"id": "1", "text": "test"}]}')
44
+ *
45
+ * // Pure JSON array
46
+ * extractJsonFromResponse('[{"id": "1", "text": "test"}]')
47
+ *
48
+ * // JSON in markdown code block
49
+ * extractJsonFromResponse('```json\n{"questions": []}\n```')
50
+ *
51
+ * // JSON with extra text
52
+ * extractJsonFromResponse('Here is the JSON: {"id": "1"}')
53
+ *
54
+ * @param response - Raw response from LLM
55
+ * @returns Extracted JSON string or null if not found
56
+ */
57
+ export declare function extractJsonFromResponse(response: string): string | null;
58
+ /**
59
+ * Generates questions using Ollama with error handling
60
+ * @param prompt - The prompt to send to the LLM
61
+ * @param model - Model to use (optional)
62
+ * @returns Promise that resolves to the generated JSON string
63
+ */
64
+ export declare function generateQuestionsWithOllama(prompt: string, model?: string): Promise<string>;
65
+ export {};
66
+ //# sourceMappingURL=ollama-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama-client.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/ollama-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,UAAU,YAAY;IACrB,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;CAChB;AAoCD;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;IAG7B,UAAU,CAAC,EAAE,MAAM;gBAD1B,OAAO,EAAE,MAAM,EACR,UAAU,CAAC,EAAE,MAAM,YAAA;CAK3B;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,GAAE,YAA6B,GAAG,OAAO,CAAC,OAAO,CAAC,CAkB/F;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC/B,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,EACd,MAAM,GAAE,YAA6B,GACnC,OAAO,CAAC,MAAM,CAAC,CAkDjB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmDvE;AAED;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBjG"}
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ /**
3
+ * Ollama LLM client for generating questions
4
+ * Handles connection, API calls, and response parsing
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.OllamaError = void 0;
8
+ exports.checkOllamaHealth = checkOllamaHealth;
9
+ exports.callOllama = callOllama;
10
+ exports.extractJsonFromResponse = extractJsonFromResponse;
11
+ exports.generateQuestionsWithOllama = generateQuestionsWithOllama;
12
+ /**
13
+ * Default configuration
14
+ */
15
+ const DEFAULT_CONFIG = {
16
+ baseUrl: "http://localhost:11434",
17
+ defaultModel: process.env.OLLAMA_MODEL || "llama3.2",
18
+ timeout: parseInt(process.env.OLLAMA_TIMEOUT || "180000", 10), // 3 minutes default, configurable via env
19
+ };
20
+ /**
21
+ * Error class for Ollama-specific errors
22
+ */
23
+ class OllamaError extends Error {
24
+ constructor(message, statusCode) {
25
+ super(message);
26
+ this.statusCode = statusCode;
27
+ this.name = "OllamaError";
28
+ }
29
+ }
30
+ exports.OllamaError = OllamaError;
31
+ /**
32
+ * Checks if Ollama server is running and accessible
33
+ * @param config - Ollama configuration
34
+ * @returns Promise that resolves to true if server is accessible, false on any error
35
+ */
36
+ async function checkOllamaHealth(config = DEFAULT_CONFIG) {
37
+ const controller = new AbortController();
38
+ const timeoutId = setTimeout(() => controller.abort(), config.timeout);
39
+ try {
40
+ const response = await fetch(`${config.baseUrl}/api/tags`, {
41
+ method: "GET",
42
+ signal: controller.signal,
43
+ });
44
+ clearTimeout(timeoutId);
45
+ return response.ok;
46
+ }
47
+ catch (error) {
48
+ clearTimeout(timeoutId);
49
+ if (error instanceof Error && error.name === "AbortError") {
50
+ return false; // Timeout occurred
51
+ }
52
+ return false; // Any other error means server is not accessible
53
+ }
54
+ }
55
+ /**
56
+ * Calls Ollama API to generate text
57
+ * @param prompt - The prompt to send to the LLM
58
+ * @param model - Model to use (defaults to config default)
59
+ * @param config - Ollama configuration
60
+ * @returns Promise that resolves to the generated text
61
+ */
62
+ async function callOllama(prompt, model, config = DEFAULT_CONFIG) {
63
+ const modelToUse = model || config.defaultModel;
64
+ const requestBody = {
65
+ model: modelToUse,
66
+ prompt,
67
+ stream: false,
68
+ options: {
69
+ temperature: 0.7,
70
+ max_tokens: 1500,
71
+ top_p: 0.9,
72
+ frequency_penalty: 0.5,
73
+ },
74
+ };
75
+ const controller = new AbortController();
76
+ const timeoutId = setTimeout(() => {
77
+ controller.abort();
78
+ }, config.timeout);
79
+ let response;
80
+ try {
81
+ response = await fetch(`${config.baseUrl}/api/generate`, {
82
+ method: "POST",
83
+ headers: {
84
+ "Content-Type": "application/json",
85
+ },
86
+ body: JSON.stringify(requestBody),
87
+ signal: controller.signal,
88
+ });
89
+ }
90
+ catch (error) {
91
+ clearTimeout(timeoutId);
92
+ if (error instanceof Error && error.name === "AbortError") {
93
+ throw new OllamaError(`Request timeout after ${config.timeout}ms`);
94
+ }
95
+ throw new OllamaError(`Request failed: ${error instanceof Error ? error.message : "Unknown error"}`);
96
+ }
97
+ clearTimeout(timeoutId);
98
+ if (!response.ok) {
99
+ throw new OllamaError(`HTTP ${response.status}: ${response.statusText}`, response.status);
100
+ }
101
+ try {
102
+ const data = (await response.json());
103
+ return data.response;
104
+ }
105
+ catch (error) {
106
+ throw new OllamaError(`Failed to parse JSON response: ${error instanceof Error ? error.message : "Unknown error"}`);
107
+ }
108
+ }
109
+ /**
110
+ * Extracts JSON from LLM response text
111
+ * Handles cases where LLM returns pure JSON or wraps it in markdown code blocks
112
+ *
113
+ * @example
114
+ * // Pure JSON object
115
+ * extractJsonFromResponse('{"questions": [{"id": "1", "text": "test"}]}')
116
+ *
117
+ * // Pure JSON array
118
+ * extractJsonFromResponse('[{"id": "1", "text": "test"}]')
119
+ *
120
+ * // JSON in markdown code block
121
+ * extractJsonFromResponse('```json\n{"questions": []}\n```')
122
+ *
123
+ * // JSON with extra text
124
+ * extractJsonFromResponse('Here is the JSON: {"id": "1"}')
125
+ *
126
+ * @param response - Raw response from LLM
127
+ * @returns Extracted JSON string or null if not found
128
+ */
129
+ function extractJsonFromResponse(response) {
130
+ // Trim whitespace first
131
+ const trimmed = response.trim();
132
+ // Case 1: Response is pure JSON (starts and ends with {})
133
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
134
+ try {
135
+ // Try to parse to validate it's valid JSON
136
+ JSON.parse(trimmed);
137
+ return trimmed;
138
+ }
139
+ catch {
140
+ // Not valid JSON, continue to other methods
141
+ }
142
+ }
143
+ // Case 2: Response is pure JSON array (starts and ends with [])
144
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
145
+ try {
146
+ // Try to parse to validate it's valid JSON
147
+ JSON.parse(trimmed);
148
+ return trimmed;
149
+ }
150
+ catch {
151
+ // Not valid JSON, continue to other methods
152
+ }
153
+ }
154
+ // Case 3: JSON wrapped in markdown code blocks
155
+ const codeBlockMatch = response.match(/```(?:json)?\s*(\{[\s\S]*?\})\s*```/);
156
+ if (codeBlockMatch) {
157
+ return codeBlockMatch[1] ?? null;
158
+ }
159
+ // Case 4: JSON array wrapped in markdown code blocks
160
+ const arrayCodeBlockMatch = response.match(/```(?:json)?\s*(\[[\s\S]*?\])\s*```/);
161
+ if (arrayCodeBlockMatch) {
162
+ return arrayCodeBlockMatch[1] ?? null;
163
+ }
164
+ // Case 5: Find JSON object anywhere in the text (fallback)
165
+ const jsonObjectMatch = response.match(/\{[\s\S]*\}/);
166
+ if (jsonObjectMatch) {
167
+ return jsonObjectMatch[0] ?? null;
168
+ }
169
+ // Case 6: Find JSON array anywhere in the text (fallback)
170
+ const jsonArrayMatch = response.match(/\[[\s\S]*\]/);
171
+ if (jsonArrayMatch) {
172
+ return jsonArrayMatch[0] ?? null;
173
+ }
174
+ return null;
175
+ }
176
+ /**
177
+ * Generates questions using Ollama with error handling
178
+ * @param prompt - The prompt to send to the LLM
179
+ * @param model - Model to use (optional)
180
+ * @returns Promise that resolves to the generated JSON string
181
+ */
182
+ async function generateQuestionsWithOllama(prompt, model) {
183
+ const isHealthy = await checkOllamaHealth();
184
+ if (!isHealthy) {
185
+ throw new OllamaError("Ollama server is not running or not accessible at http://localhost:11434\n" +
186
+ "Please start Ollama and ensure the server is running.");
187
+ }
188
+ const response = await callOllama(prompt, model);
189
+ const jsonString = extractJsonFromResponse(response);
190
+ if (!jsonString) {
191
+ throw new OllamaError("LLM response does not contain valid JSON.\n" +
192
+ "Response received:\n" +
193
+ response.substring(0, 500) +
194
+ (response.length > 500 ? "..." : ""));
195
+ }
196
+ return jsonString;
197
+ }
198
+ //# sourceMappingURL=ollama-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama-client.js","sourceRoot":"","sources":["../../../../src/cli/lib/ollama-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Prompt builder for question generation
3
+ * Reads rule content and builds structured prompts for LLM
4
+ */
5
+ import type { Manifest } from "../../server/types";
6
+ /**
7
+ * Rule content structure for prompt building
8
+ */
9
+ interface RuleContent {
10
+ /** Rule manifest metadata */
11
+ manifest: Manifest;
12
+ /** Content of all rule files */
13
+ files: Array<{
14
+ path: string;
15
+ content: string;
16
+ }>;
17
+ }
18
+ /**
19
+ * Reads rule content from the repository
20
+ * @param rulePath - The path to the rule directory (e.g., 'rules/cursor/brainstorming')
21
+ * @returns Rule content with manifest and files
22
+ */
23
+ export declare function readRuleContent(rulePath: string): RuleContent;
24
+ /**
25
+ * Builds context string from rule metadata and content
26
+ * @param ruleContent - Rule content structure
27
+ * @returns Formatted context string for LLM
28
+ */
29
+ export declare function buildRuleContext(ruleContent: RuleContent): string;
30
+ /**
31
+ * Builds the complete prompt for LLM question generation
32
+ * @param rulePath - The path to the rule directory
33
+ * @returns Complete prompt string
34
+ */
35
+ export declare function buildQuestionPrompt(rulePath: string): string;
36
+ export {};
37
+ //# sourceMappingURL=question-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"question-prompt.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/question-prompt.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;GAEG;AACH,UAAU,WAAW;IACpB,6BAA6B;IAC7B,QAAQ,EAAE,QAAQ,CAAC;IACnB,gCAAgC;IAChC,KAAK,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACH;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CA+B7D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAcjE;AAmID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAU5D"}
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ /**
3
+ * Prompt builder for question generation
4
+ * Reads rule content and builds structured prompts for LLM
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.readRuleContent = readRuleContent;
8
+ exports.buildRuleContext = buildRuleContext;
9
+ exports.buildQuestionPrompt = buildQuestionPrompt;
10
+ const node_fs_1 = require("node:fs");
11
+ const node_path_1 = require("node:path");
12
+ /**
13
+ * Reads rule content from the repository
14
+ * @param rulePath - The path to the rule directory (e.g., 'rules/cursor/brainstorming')
15
+ * @returns Rule content with manifest and files
16
+ */
17
+ function readRuleContent(rulePath) {
18
+ // Resolve the rule directory path
19
+ const ruleDir = rulePath.startsWith("/") ? rulePath : (0, node_path_1.join)(process.cwd(), rulePath);
20
+ if (!(0, node_fs_1.existsSync)(ruleDir)) {
21
+ throw new Error(`Rule directory not found: ${ruleDir}`);
22
+ }
23
+ // Read manifest
24
+ const manifestPath = (0, node_path_1.join)(ruleDir, "manifest.json");
25
+ if (!(0, node_fs_1.existsSync)(manifestPath)) {
26
+ throw new Error(`Manifest not found: ${manifestPath}`);
27
+ }
28
+ const manifest = JSON.parse((0, node_fs_1.readFileSync)(manifestPath, "utf-8"));
29
+ // Read all rule files
30
+ const files = manifest.files.map((file) => {
31
+ const filePath = (0, node_path_1.join)(ruleDir, file.path);
32
+ if (!(0, node_fs_1.existsSync)(filePath)) {
33
+ throw new Error(`Rule file not found: ${filePath}`);
34
+ }
35
+ const content = (0, node_fs_1.readFileSync)(filePath, "utf-8");
36
+ return {
37
+ path: file.path,
38
+ content,
39
+ };
40
+ });
41
+ return { manifest, files };
42
+ }
43
+ /**
44
+ * Builds context string from rule metadata and content
45
+ * @param ruleContent - Rule content structure
46
+ * @returns Formatted context string for LLM
47
+ */
48
+ function buildRuleContext(ruleContent) {
49
+ const { manifest, files } = ruleContent;
50
+ const context = `
51
+ Rule ID: ${manifest.id}
52
+ Category: ${manifest.category}
53
+ Tags: ${manifest.tags.join(", ")}
54
+ Description: ${manifest.description}
55
+
56
+ Rule Content:
57
+ ${files.map((file) => `--- ${file.path} ---\n${file.content}`).join("\n\n")}
58
+ `;
59
+ return context.trim();
60
+ }
61
+ /**
62
+ * System prompt for question generation
63
+ * Includes instructions, schema, and examples
64
+ */
65
+ const SYSTEM_PROMPT = `You are a question generation assistant for an AI rules library.
66
+
67
+ Your task: Generate 3-5 questions that identify if developers want/need help from this rule.
68
+
69
+ Context: Questions build context for fuzzy search rule discovery. User describes project → answers questions → keywords added to context → context searches rules.
70
+
71
+ Question Types:
72
+ 1. yes-no: Binary questions. Must include "keywords" array (added to search context if user answers yes)
73
+ 2. choice: Multiple choice. Must include "options" array with text and keywords for each
74
+ 3. open-ended: Free text. Full answer added to search context.
75
+
76
+ All questions MUST include:
77
+ - "id": Unique identifier in kebab-case
78
+ - "text": Clear, concise question text
79
+ - "type": One of: yes-no, choice, open-ended
80
+ - "tags": Array of relevant search tags (technology names, concepts, patterns)
81
+
82
+ Requirements:
83
+ - ALWAYS lead with 1-2 high-level need/intent questions
84
+ - High-level questions should directly ask about wanting/needing help (e.g., "Do you want rules to help with X?")
85
+ - Then follow with specific usage or technical questions
86
+ - Questions can ask about current usage OR needs - both add keywords to context
87
+ - For core technologies (e.g., TypeScript, React, Next.js, Node.js), the FIRST question MUST be a usage-detection yes/no (e.g., "Are you using TypeScript?") when the rule clearly targets that technology
88
+ - Focus on what will help identify if this rule solves their problems
89
+ - Tags should match common terms developers use
90
+ - Keywords should include aliases and variations
91
+ - Keep questions clear and unambiguous
92
+
93
+ Return valid JSON matching this schema:
94
+ {
95
+ "questions": [
96
+ {
97
+ "id": "string (kebab-case, unique)",
98
+ "text": "string (the question)",
99
+ "type": "yes-no | choice | open-ended",
100
+ "tags": ["string", "..."],
101
+ "keywords": ["string", "..."], // for yes-no only
102
+ "options": [ // for choice only
103
+ { "text": "string", "keywords": ["string", "..."] }
104
+ ]
105
+ }
106
+ ]
107
+ }
108
+
109
+ Examples:
110
+
111
+ Example for a TypeScript rule (usage detection MUST be first):
112
+ {
113
+ "id": "uses-typescript",
114
+ "text": "Are you using TypeScript?",
115
+ "type": "yes-no",
116
+ "tags": ["typescript", "language", "type-system"],
117
+ "keywords": ["typescript", "ts"]
118
+ }
119
+
120
+ Example for a React hooks rule (usage detection):
121
+ {
122
+ "id": "uses-react-hooks",
123
+ "text": "Are you using React hooks in your project?",
124
+ "type": "yes-no",
125
+ "tags": ["react", "hooks", "frontend"],
126
+ "keywords": ["react", "hooks", "useState", "useEffect"]
127
+ }
128
+
129
+ Example for a CSS framework choice:
130
+ {
131
+ "id": "css-framework",
132
+ "text": "What CSS framework are you using?",
133
+ "type": "choice",
134
+ "tags": ["css", "styling", "framework"],
135
+ "options": [
136
+ { "text": "Tailwind CSS", "keywords": ["tailwind", "tailwindcss"] },
137
+ { "text": "styled-components", "keywords": ["styled-components"] },
138
+ { "text": "CSS Modules", "keywords": ["css-modules"] }
139
+ ]
140
+ }
141
+
142
+ Example for a brainstorming rule (high-level need):
143
+ {
144
+ "id": "wants-brainstorming-help",
145
+ "text": "Do you want rules to help you brainstorm and document ideas methodically?",
146
+ "type": "yes-no",
147
+ "tags": ["brainstorming", "problem-solving", "documentation"],
148
+ "keywords": ["brainstorming", "structured-thinking", "documentation", "problem-definition"]
149
+ }
150
+
151
+ Example for open-ended (exploration):
152
+ {
153
+ "id": "project-challenges",
154
+ "text": "What are the main challenges you face in your development process?",
155
+ "type": "open-ended",
156
+ "tags": ["challenges", "problems", "workflow"]
157
+ }
158
+
159
+ Example for a React Server Components rule (usage detection):
160
+ {
161
+ "id": "uses-nextjs-app-router",
162
+ "text": "Are you using Next.js App Router?",
163
+ "type": "yes-no",
164
+ "tags": ["nextjs", "react", "app-router", "server-components"],
165
+ "keywords": ["nextjs", "app-router", "server-components", "next.js"]
166
+ }
167
+
168
+ Example for a React Server Components rule (architecture choice):
169
+ {
170
+ "id": "component-architecture",
171
+ "text": "What component architecture are you using?",
172
+ "type": "choice",
173
+ "tags": ["react", "architecture", "components"],
174
+ "options": [
175
+ { "text": "Server Components with App Router", "keywords": ["server-components", "app-router", "rsc"] },
176
+ { "text": "Client Components only", "keywords": ["client-components", "spa"] },
177
+ { "text": "Pages Router", "keywords": ["pages-router", "getServerSideProps"] }
178
+ ]
179
+ }
180
+
181
+ Example for a Server Components rule (need for guidance):
182
+ {
183
+ "id": "needs-server-component-patterns",
184
+ "text": "Do you need help with Server Component patterns and best practices?",
185
+ "type": "yes-no",
186
+ "tags": ["react", "server-components", "patterns", "best-practices"],
187
+ "keywords": ["server-components", "client-server-separation", "data-fetching", "composition"]
188
+ }`;
189
+ /**
190
+ * Builds the complete prompt for LLM question generation
191
+ * @param rulePath - The path to the rule directory
192
+ * @returns Complete prompt string
193
+ */
194
+ function buildQuestionPrompt(rulePath) {
195
+ const ruleContent = readRuleContent(rulePath);
196
+ const context = buildRuleContext(ruleContent);
197
+ return `${SYSTEM_PROMPT}
198
+
199
+ Rule to analyze:
200
+ ${context}
201
+
202
+ Generate 3-5 relevant questions for this rule. Return only valid JSON.`;
203
+ }
204
+ //# sourceMappingURL=question-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"question-prompt.js","sourceRoot":"","sources":["../../../../src/cli/lib/question-prompt.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAwBH,0CA+BC;AAOD,4CAcC;AAwID,kDAUC;AA5ND,qCAAmD;AACnD,yCAAiC;AAgBjC;;;;GAIG;AACH,SAAgB,eAAe,CAAC,QAAgB;IAC/C,kCAAkC;IAClC,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAA,gBAAI,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;IAEpF,IAAI,CAAC,IAAA,oBAAU,EAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,gBAAgB;IAChB,MAAM,YAAY,GAAG,IAAA,gBAAI,EAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IACpD,IAAI,CAAC,IAAA,oBAAU,EAAC,YAAY,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,uBAAuB,YAAY,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,QAAQ,GAAa,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IAE3E,sBAAsB;IACtB,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACzC,MAAM,QAAQ,GAAG,IAAA,gBAAI,EAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAA,oBAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,wBAAwB,QAAQ,EAAE,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,OAAO,GAAG,IAAA,sBAAY,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO;YACN,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO;SACP,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,WAAwB;IACxD,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC;IAExC,MAAM,OAAO,GAAG;WACN,QAAQ,CAAC,EAAE;YACV,QAAQ,CAAC,QAAQ;QACrB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;eACjB,QAAQ,CAAC,WAAW;;;EAGjC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,CAAC,IAAI,SAAS,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;CAC1E,CAAC;IAED,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2HpB,CAAC;AAEH;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,QAAgB;IACnD,MAAM,WAAW,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAE9C,OAAO,GAAG,aAAa;;;EAGtB,OAAO;;uEAE8D,CAAC;AACxE,CAAC"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Zod schemas for validating question generation responses
3
+ * Provides type-safe validation with detailed error messages
4
+ */
5
+ import type { Question, QuestionResponse } from "src/lib/question-types";
6
+ import { z } from "zod";
7
+ /**
8
+ * Discriminated union schema for all question types
9
+ * Automatically validates based on the 'type' field
10
+ */
11
+ export declare const QuestionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
12
+ id: z.ZodString;
13
+ text: z.ZodString;
14
+ tags: z.ZodArray<z.ZodString>;
15
+ type: z.ZodLiteral<"yes-no">;
16
+ keywords: z.ZodArray<z.ZodString>;
17
+ }, z.core.$strip>, z.ZodObject<{
18
+ id: z.ZodString;
19
+ text: z.ZodString;
20
+ tags: z.ZodArray<z.ZodString>;
21
+ type: z.ZodLiteral<"choice">;
22
+ options: z.ZodArray<z.ZodObject<{
23
+ text: z.ZodString;
24
+ keywords: z.ZodArray<z.ZodString>;
25
+ }, z.core.$strip>>;
26
+ }, z.core.$strip>, z.ZodObject<{
27
+ id: z.ZodString;
28
+ text: z.ZodString;
29
+ tags: z.ZodArray<z.ZodString>;
30
+ type: z.ZodLiteral<"open-ended">;
31
+ }, z.core.$strip>], "type">;
32
+ /**
33
+ * Schema for the complete response containing questions array
34
+ */
35
+ export declare const QuestionResponseSchema: z.ZodObject<{
36
+ questions: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
37
+ id: z.ZodString;
38
+ text: z.ZodString;
39
+ tags: z.ZodArray<z.ZodString>;
40
+ type: z.ZodLiteral<"yes-no">;
41
+ keywords: z.ZodArray<z.ZodString>;
42
+ }, z.core.$strip>, z.ZodObject<{
43
+ id: z.ZodString;
44
+ text: z.ZodString;
45
+ tags: z.ZodArray<z.ZodString>;
46
+ type: z.ZodLiteral<"choice">;
47
+ options: z.ZodArray<z.ZodObject<{
48
+ text: z.ZodString;
49
+ keywords: z.ZodArray<z.ZodString>;
50
+ }, z.core.$strip>>;
51
+ }, z.core.$strip>, z.ZodObject<{
52
+ id: z.ZodString;
53
+ text: z.ZodString;
54
+ tags: z.ZodArray<z.ZodString>;
55
+ type: z.ZodLiteral<"open-ended">;
56
+ }, z.core.$strip>], "type">>;
57
+ }, z.core.$strip>;
58
+ /**
59
+ * Validates a question response and returns typed result
60
+ * @param data - Raw data to validate
61
+ * @returns Success result with typed data or error details
62
+ */
63
+ export declare function validateQuestionResponse(data: unknown): {
64
+ success: true;
65
+ data: QuestionResponse;
66
+ } | {
67
+ success: false;
68
+ error: string;
69
+ details?: z.ZodError;
70
+ };
71
+ /**
72
+ * Validates a single question
73
+ * @param data - Raw data to validate
74
+ * @returns Success result with typed question or error details
75
+ */
76
+ export declare function validateQuestion(data: unknown): {
77
+ success: true;
78
+ data: Question;
79
+ } | {
80
+ success: false;
81
+ error: string;
82
+ details?: z.ZodError;
83
+ };
84
+ //# sourceMappingURL=question-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"question-schema.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/question-schema.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAsDxB;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;2BAIzB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;iBAKjC,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,OAAO,GACnD;IACA,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,gBAAgB,CAAC;CACtB,GACD;IACA,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC;CACpB,CAyBH;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAC3C;IACA,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;CACd,GACD;IACA,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC;CACpB,CAyBH"}