@djangocfg/nextjs 2.1.7 → 2.1.9

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 CHANGED
@@ -44,9 +44,9 @@ yarn add @djangocfg/nextjs
44
44
  Search DjangoCFG documentation from the terminal:
45
45
 
46
46
  ```bash
47
- # CLI
48
- pnpm ai-docs search "database configuration"
49
- pnpm ai-docs mcp
47
+ # CLI (works anywhere via npx)
48
+ npx @djangocfg/nextjs ai-docs search "database configuration"
49
+ npx @djangocfg/nextjs ai-docs mcp
50
50
  ```
51
51
 
52
52
  Or use the TypeScript API:
package/dist/ai/cli.mjs CHANGED
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/ai/cli.ts
4
+ import { consola } from "consola";
5
+
3
6
  // src/ai/constants.ts
4
7
  var MCP_BASE_URL = "https://mcp.djangocfg.com";
5
8
  var MCP_SERVER_URL = `${MCP_BASE_URL}/mcp`;
@@ -112,58 +115,80 @@ function getMcpConfig() {
112
115
  var args = process.argv.slice(2);
113
116
  var command = args[0];
114
117
  var query = args.slice(1).join(" ");
118
+ function wrapText(text, indent = 3, maxWidth) {
119
+ const width = maxWidth || process.stdout.columns || 80;
120
+ const effectiveWidth = width - indent;
121
+ const prefix = " ".repeat(indent);
122
+ const cleaned = text.replace(/\s+/g, " ").trim();
123
+ if (cleaned.length <= effectiveWidth) {
124
+ return prefix + cleaned;
125
+ }
126
+ const words = cleaned.split(" ");
127
+ const lines = [];
128
+ let currentLine = "";
129
+ for (const word of words) {
130
+ if (currentLine.length + word.length + 1 <= effectiveWidth) {
131
+ currentLine += (currentLine ? " " : "") + word;
132
+ } else {
133
+ if (currentLine) lines.push(prefix + currentLine);
134
+ currentLine = word;
135
+ }
136
+ }
137
+ if (currentLine) lines.push(prefix + currentLine);
138
+ return lines.join("\n");
139
+ }
115
140
  async function main() {
116
141
  switch (command) {
117
142
  case "search":
118
143
  case "s":
119
144
  if (!query) {
120
- console.error('Usage: ai-docs search "your query"');
145
+ consola.error('Usage: djangocfg-docs search "your query"');
121
146
  process.exit(1);
122
147
  }
123
- console.log(`
124
- \u{1F50D} Searching: ${query}
148
+ consola.info(`Searching: ${query}
125
149
  `);
126
150
  try {
127
151
  const results = await search(query, { limit: 5 });
128
152
  if (results.length === 0) {
129
- console.log("No results found.");
153
+ consola.warn("No results found.");
130
154
  } else {
131
155
  results.forEach((r, i) => {
132
- console.log(`${i + 1}. ${r.title}`);
133
- console.log(` ${r.content.slice(0, 150)}...`);
134
- if (r.url) console.log(` \u{1F4D6} ${r.url}`);
135
- console.log("");
156
+ consola.success(`${i + 1}. ${r.title}`);
157
+ const contentPreview = r.content.slice(0, 200);
158
+ console.log(wrapText(contentPreview + "..."));
159
+ if (r.url) consola.log(` ${r.url}`);
160
+ consola.log("");
136
161
  });
137
162
  }
138
163
  } catch (err) {
139
- console.error("Error:", err instanceof Error ? err.message : err);
164
+ consola.error("Error:", err instanceof Error ? err.message : err);
140
165
  process.exit(1);
141
166
  }
142
167
  break;
143
168
  case "mcp":
144
- console.log("\n\u{1F4E1} MCP Server Configuration:\n");
145
- console.log(JSON.stringify(getMcpConfig(), null, 2));
146
- console.log("\nAdd this to your AI assistant configuration.");
169
+ consola.box("MCP Server Configuration");
170
+ consola.log(JSON.stringify(getMcpConfig(), null, 2));
171
+ consola.info("Add this to your AI assistant configuration.");
147
172
  break;
148
173
  case "info":
149
174
  case "i":
150
- console.log("\n\u{1F916} DjangoCFG AI Documentation\n");
151
- console.log(`MCP Server: ${MCP_SERVER_URL}`);
152
- console.log(`Search API: ${MCP_API_URL}`);
153
- console.log("\nUsage:");
154
- console.log(' pnpm exec ai-docs search "database configuration"');
155
- console.log(" pnpm exec ai-docs mcp");
175
+ consola.box("DjangoCFG AI Documentation");
176
+ consola.info(`MCP Server: ${MCP_SERVER_URL}`);
177
+ consola.info(`Search API: ${MCP_API_URL}`);
178
+ consola.log("\nUsage:");
179
+ consola.log(' npx djangocfg-docs search "database configuration"');
180
+ consola.log(" npx djangocfg-docs mcp");
156
181
  break;
157
182
  default:
158
- console.log("\u{1F916} DjangoCFG AI Documentation CLI\n");
159
- console.log("Commands:");
160
- console.log(" search <query> Search documentation");
161
- console.log(" mcp Show MCP server config");
162
- console.log(" info Show help\n");
163
- console.log("Examples:");
164
- console.log(' pnpm exec ai-docs search "database configuration"');
165
- console.log(' pnpm exec ai-docs search "redis cache"');
166
- console.log(" pnpm exec ai-docs mcp");
183
+ consola.box("DjangoCFG AI Documentation CLI");
184
+ consola.log("Commands:");
185
+ consola.log(" search <query> Search documentation");
186
+ consola.log(" mcp Show MCP server config");
187
+ consola.log(" info Show help\n");
188
+ consola.log("Examples:");
189
+ consola.log(' npx djangocfg-docs search "database configuration"');
190
+ consola.log(' npx djangocfg-docs search "redis cache"');
191
+ consola.log(" npx djangocfg-docs mcp");
167
192
  break;
168
193
  }
169
194
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ai/constants.ts","../../src/ai/client.ts","../../src/ai/cli.ts"],"sourcesContent":["/**\n * AI Documentation Constants\n */\n\n// MCP Server URLs\nexport const MCP_BASE_URL = 'https://mcp.djangocfg.com';\nexport const MCP_SERVER_URL = `${MCP_BASE_URL}/mcp`;\nexport const MCP_API_URL = `${MCP_BASE_URL}/api/search`;\n\n// API Endpoints\nexport const API_SEARCH_ENDPOINT = '/api/search';\nexport const API_INFO_ENDPOINT = '/api/info';\nexport const DEFAULT_TIMEOUT = 10000; // ms\n\n// AI Hint for console output\nexport const AI_DOCS_HINT = `šŸ¤– AI Docs: ${MCP_SERVER_URL} | pnpm ai-docs search \"query\"`;\n\n// Full AI Hint description\nexport const AI_HINT = `\nDjangoCFG Documentation is available via MCP server.\n\nTo get help with DjangoCFG configuration:\n1. Use the MCP server: ${MCP_SERVER_URL}\n2. Or search directly: ${MCP_API_URL}?q=YOUR_QUERY&limit=5\n\nExample queries:\n- \"How to configure PostgreSQL database?\"\n- \"What is DatabaseConfig?\"\n- \"How to setup Redis cache?\"\n- \"Email configuration with SMTP\"\n`;\n","/**\n * DjangoCFG Documentation Client\n *\n * HTTP client for accessing DjangoCFG documentation via MCP server API.\n */\n\nimport {\n MCP_BASE_URL,\n API_SEARCH_ENDPOINT,\n API_INFO_ENDPOINT,\n DEFAULT_TIMEOUT,\n} from './constants';\nimport type { SearchResult, SearchOptions, McpConfig, ApiSearchResponse } from './types';\n\n/**\n * Client for DjangoCFG Documentation API.\n */\nexport class DjangoCfgDocsClient {\n private baseUrl: string;\n private timeout: number;\n\n constructor(baseUrl: string = MCP_BASE_URL, timeout: number = DEFAULT_TIMEOUT) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.timeout = timeout;\n }\n\n private async makeRequest<T>(endpoint: string, params?: Record<string, string | number>): Promise<T> {\n let url = `${this.baseUrl}${endpoint}`;\n\n if (params) {\n const searchParams = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n searchParams.set(key, String(value));\n }\n url = `${url}?${searchParams.toString()}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n 'User-Agent': 'DjangoCFG-AI-Client/1.0',\n },\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP Error ${response.status}: ${response.statusText}`);\n }\n\n return await response.json();\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Search documentation.\n */\n async search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n const { limit = 5, category } = options;\n\n const params: Record<string, string | number> = { q: query, limit };\n if (category) {\n params.category = category;\n }\n\n const data = await this.makeRequest<ApiSearchResponse>(API_SEARCH_ENDPOINT, params);\n\n const results = data.results || (Array.isArray(data) ? data : []);\n\n return results.map((item) => ({\n title: item.title || '',\n content: item.content || item.snippet || '',\n url: item.url || '',\n score: item.score || 0,\n category: item.category || '',\n }));\n }\n\n /**\n * Get detailed info about a specific topic.\n */\n async getInfo(topic: string): Promise<Record<string, unknown>> {\n return this.makeRequest(API_INFO_ENDPOINT, { topic });\n }\n\n /**\n * Get MCP server configuration for AI assistants.\n */\n getMcpConfig(): McpConfig {\n return {\n mcpServers: {\n 'djangocfg-docs': {\n url: `${this.baseUrl}/mcp`,\n },\n },\n };\n }\n}\n\n// Default client instance\nlet defaultClient: DjangoCfgDocsClient | null = null;\n\nfunction getClient(): DjangoCfgDocsClient {\n if (!defaultClient) {\n defaultClient = new DjangoCfgDocsClient();\n }\n return defaultClient;\n}\n\n/**\n * Search DjangoCFG documentation.\n *\n * @example\n * ```ts\n * const results = await search('database configuration');\n * results.forEach(r => console.log(r.title, r.url));\n * ```\n */\nexport async function search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n return getClient().search(query, options);\n}\n\n/**\n * Get documentation as formatted text.\n *\n * @example\n * ```ts\n * const docs = await getDocs('How to configure PostgreSQL?');\n * console.log(docs);\n * ```\n */\nexport async function getDocs(query: string, limit: number = 3): Promise<string> {\n const results = await search(query, { limit });\n\n if (results.length === 0) {\n return `No documentation found for: ${query}`;\n }\n\n const output: string[] = [];\n\n results.forEach((r, i) => {\n output.push(`## ${i + 1}. ${r.title}`);\n output.push(r.content);\n if (r.url) {\n output.push(`šŸ“– Read more: ${r.url}`);\n }\n output.push('');\n });\n\n return output.join('\\n');\n}\n\n/**\n * Get detailed info about a topic.\n */\nexport async function getInfo(topic: string): Promise<Record<string, unknown>> {\n return getClient().getInfo(topic);\n}\n\n/**\n * Get MCP server configuration.\n */\nexport function getMcpConfig(): McpConfig {\n return getClient().getMcpConfig();\n}\n","#!/usr/bin/env node\n/**\n * DjangoCFG AI Docs CLI\n *\n * Usage:\n * pnpm exec ai-docs search \"database configuration\"\n * pnpm exec ai-docs mcp\n * npx @djangocfg/nextjs ai-docs search \"query\"\n */\n\nimport { search, getMcpConfig, MCP_SERVER_URL, MCP_API_URL } from './index';\n\nconst args = process.argv.slice(2);\nconst command = args[0];\nconst query = args.slice(1).join(' ');\n\nasync function main() {\n switch (command) {\n case 'search':\n case 's':\n if (!query) {\n console.error('Usage: ai-docs search \"your query\"');\n process.exit(1);\n }\n console.log(`\\nšŸ” Searching: ${query}\\n`);\n try {\n const results = await search(query, { limit: 5 });\n if (results.length === 0) {\n console.log('No results found.');\n } else {\n results.forEach((r, i) => {\n console.log(`${i + 1}. ${r.title}`);\n console.log(` ${r.content.slice(0, 150)}...`);\n if (r.url) console.log(` šŸ“– ${r.url}`);\n console.log('');\n });\n }\n } catch (err) {\n console.error('Error:', err instanceof Error ? err.message : err);\n process.exit(1);\n }\n break;\n\n case 'mcp':\n console.log('\\nšŸ“” MCP Server Configuration:\\n');\n console.log(JSON.stringify(getMcpConfig(), null, 2));\n console.log('\\nAdd this to your AI assistant configuration.');\n break;\n\n case 'info':\n case 'i':\n console.log('\\nšŸ¤– DjangoCFG AI Documentation\\n');\n console.log(`MCP Server: ${MCP_SERVER_URL}`);\n console.log(`Search API: ${MCP_API_URL}`);\n console.log('\\nUsage:');\n console.log(' pnpm exec ai-docs search \"database configuration\"');\n console.log(' pnpm exec ai-docs mcp');\n break;\n\n default:\n console.log('šŸ¤– DjangoCFG AI Documentation CLI\\n');\n console.log('Commands:');\n console.log(' search <query> Search documentation');\n console.log(' mcp Show MCP server config');\n console.log(' info Show help\\n');\n console.log('Examples:');\n console.log(' pnpm exec ai-docs search \"database configuration\"');\n console.log(' pnpm exec ai-docs search \"redis cache\"');\n console.log(' pnpm exec ai-docs mcp');\n break;\n }\n}\n\nmain();\n"],"mappings":";;;AAKO,IAAM,eAAe;AACrB,IAAM,iBAAiB,GAAG,YAAY;AACtC,IAAM,cAAc,GAAG,YAAY;AAGnC,IAAM,sBAAsB;AAC5B,IAAM,oBAAoB;AAC1B,IAAM,kBAAkB;AAGxB,IAAM,eAAe,sBAAe,cAAc;AAGlD,IAAM,UAAU;AAAA;AAAA;AAAA;AAAA,yBAIE,cAAc;AAAA,yBACd,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACN7B,IAAM,sBAAN,MAA0B;AAAA,EAI/B,YAAY,UAAkB,cAAc,UAAkB,iBAAiB;AAC7E,SAAK,UAAU,QAAQ,QAAQ,OAAO,EAAE;AACxC,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAc,YAAe,UAAkB,QAAsD;AACnG,QAAI,MAAM,GAAG,KAAK,OAAO,GAAG,QAAQ;AAEpC,QAAI,QAAQ;AACV,YAAM,eAAe,IAAI,gBAAgB;AACzC,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,qBAAa,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,MACrC;AACA,YAAM,GAAG,GAAG,IAAI,aAAa,SAAS,CAAC;AAAA,IACzC;AAEA,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,OAAO;AAEnE,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,QAAQ;AAAA,UACR,cAAc;AAAA,QAChB;AAAA,QACA,QAAQ,WAAW;AAAA,MACrB,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,MAAM,cAAc,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,MACzE;AAEA,aAAO,MAAM,SAAS,KAAK;AAAA,IAC7B,UAAE;AACA,mBAAa,SAAS;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAOA,QAAe,UAAyB,CAAC,GAA4B;AAChF,UAAM,EAAE,QAAQ,GAAG,SAAS,IAAI;AAEhC,UAAM,SAA0C,EAAE,GAAGA,QAAO,MAAM;AAClE,QAAI,UAAU;AACZ,aAAO,WAAW;AAAA,IACpB;AAEA,UAAM,OAAO,MAAM,KAAK,YAA+B,qBAAqB,MAAM;AAElF,UAAM,UAAU,KAAK,YAAY,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC;AAE/D,WAAO,QAAQ,IAAI,CAAC,UAAU;AAAA,MAC5B,OAAO,KAAK,SAAS;AAAA,MACrB,SAAS,KAAK,WAAW,KAAK,WAAW;AAAA,MACzC,KAAK,KAAK,OAAO;AAAA,MACjB,OAAO,KAAK,SAAS;AAAA,MACrB,UAAU,KAAK,YAAY;AAAA,IAC7B,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,OAAiD;AAC7D,WAAO,KAAK,YAAY,mBAAmB,EAAE,MAAM,CAAC;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKA,eAA0B;AACxB,WAAO;AAAA,MACL,YAAY;AAAA,QACV,kBAAkB;AAAA,UAChB,KAAK,GAAG,KAAK,OAAO;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAGA,IAAI,gBAA4C;AAEhD,SAAS,YAAiC;AACxC,MAAI,CAAC,eAAe;AAClB,oBAAgB,IAAI,oBAAoB;AAAA,EAC1C;AACA,SAAO;AACT;AAWA,eAAsB,OAAOA,QAAe,UAAyB,CAAC,GAA4B;AAChG,SAAO,UAAU,EAAE,OAAOA,QAAO,OAAO;AAC1C;AA0CO,SAAS,eAA0B;AACxC,SAAO,UAAU,EAAE,aAAa;AAClC;;;AC9JA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,UAAU,KAAK,CAAC;AACtB,IAAM,QAAQ,KAAK,MAAM,CAAC,EAAE,KAAK,GAAG;AAEpC,eAAe,OAAO;AACpB,UAAQ,SAAS;AAAA,IACf,KAAK;AAAA,IACL,KAAK;AACH,UAAI,CAAC,OAAO;AACV,gBAAQ,MAAM,oCAAoC;AAClD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,cAAQ,IAAI;AAAA,uBAAmB,KAAK;AAAA,CAAI;AACxC,UAAI;AACF,cAAM,UAAU,MAAM,OAAO,OAAO,EAAE,OAAO,EAAE,CAAC;AAChD,YAAI,QAAQ,WAAW,GAAG;AACxB,kBAAQ,IAAI,mBAAmB;AAAA,QACjC,OAAO;AACL,kBAAQ,QAAQ,CAAC,GAAG,MAAM;AACxB,oBAAQ,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE;AAClC,oBAAQ,IAAI,MAAM,EAAE,QAAQ,MAAM,GAAG,GAAG,CAAC,KAAK;AAC9C,gBAAI,EAAE,IAAK,SAAQ,IAAI,gBAAS,EAAE,GAAG,EAAE;AACvC,oBAAQ,IAAI,EAAE;AAAA,UAChB,CAAC;AAAA,QACH;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,GAAG;AAChE,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IAEF,KAAK;AACH,cAAQ,IAAI,yCAAkC;AAC9C,cAAQ,IAAI,KAAK,UAAU,aAAa,GAAG,MAAM,CAAC,CAAC;AACnD,cAAQ,IAAI,gDAAgD;AAC5D;AAAA,IAEF,KAAK;AAAA,IACL,KAAK;AACH,cAAQ,IAAI,0CAAmC;AAC/C,cAAQ,IAAI,eAAe,cAAc,EAAE;AAC3C,cAAQ,IAAI,eAAe,WAAW,EAAE;AACxC,cAAQ,IAAI,UAAU;AACtB,cAAQ,IAAI,qDAAqD;AACjE,cAAQ,IAAI,yBAAyB;AACrC;AAAA,IAEF;AACE,cAAQ,IAAI,4CAAqC;AACjD,cAAQ,IAAI,WAAW;AACvB,cAAQ,IAAI,wCAAwC;AACpD,cAAQ,IAAI,0CAA0C;AACtD,cAAQ,IAAI,+BAA+B;AAC3C,cAAQ,IAAI,WAAW;AACvB,cAAQ,IAAI,qDAAqD;AACjE,cAAQ,IAAI,0CAA0C;AACtD,cAAQ,IAAI,yBAAyB;AACrC;AAAA,EACJ;AACF;AAEA,KAAK;","names":["query"]}
1
+ {"version":3,"sources":["../../src/ai/cli.ts","../../src/ai/constants.ts","../../src/ai/client.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * DjangoCFG AI Docs CLI\n *\n * Usage:\n * npx djangocfg-docs search \"database configuration\"\n * npx djangocfg-docs mcp\n */\n\nimport { consola } from 'consola';\nimport { search, getMcpConfig, MCP_SERVER_URL, MCP_API_URL } from './index';\n\nconst args = process.argv.slice(2);\nconst command = args[0];\nconst query = args.slice(1).join(' ');\n\n/** Wrap text to terminal width with indent */\nfunction wrapText(text: string, indent = 3, maxWidth?: number): string {\n const width = maxWidth || process.stdout.columns || 80;\n const effectiveWidth = width - indent;\n const prefix = ' '.repeat(indent);\n\n // Clean up text - remove extra whitespace and newlines\n const cleaned = text.replace(/\\s+/g, ' ').trim();\n\n if (cleaned.length <= effectiveWidth) {\n return prefix + cleaned;\n }\n\n const words = cleaned.split(' ');\n const lines: string[] = [];\n let currentLine = '';\n\n for (const word of words) {\n if (currentLine.length + word.length + 1 <= effectiveWidth) {\n currentLine += (currentLine ? ' ' : '') + word;\n } else {\n if (currentLine) lines.push(prefix + currentLine);\n currentLine = word;\n }\n }\n if (currentLine) lines.push(prefix + currentLine);\n\n return lines.join('\\n');\n}\n\nasync function main() {\n switch (command) {\n case 'search':\n case 's':\n if (!query) {\n consola.error('Usage: djangocfg-docs search \"your query\"');\n process.exit(1);\n }\n consola.info(`Searching: ${query}\\n`);\n try {\n const results = await search(query, { limit: 5 });\n if (results.length === 0) {\n consola.warn('No results found.');\n } else {\n results.forEach((r, i) => {\n consola.success(`${i + 1}. ${r.title}`);\n // Wrap content to terminal width\n const contentPreview = r.content.slice(0, 200);\n console.log(wrapText(contentPreview + '...'));\n if (r.url) consola.log(` ${r.url}`);\n consola.log('');\n });\n }\n } catch (err) {\n consola.error('Error:', err instanceof Error ? err.message : err);\n process.exit(1);\n }\n break;\n\n case 'mcp':\n consola.box('MCP Server Configuration');\n consola.log(JSON.stringify(getMcpConfig(), null, 2));\n consola.info('Add this to your AI assistant configuration.');\n break;\n\n case 'info':\n case 'i':\n consola.box('DjangoCFG AI Documentation');\n consola.info(`MCP Server: ${MCP_SERVER_URL}`);\n consola.info(`Search API: ${MCP_API_URL}`);\n consola.log('\\nUsage:');\n consola.log(' npx djangocfg-docs search \"database configuration\"');\n consola.log(' npx djangocfg-docs mcp');\n break;\n\n default:\n consola.box('DjangoCFG AI Documentation CLI');\n consola.log('Commands:');\n consola.log(' search <query> Search documentation');\n consola.log(' mcp Show MCP server config');\n consola.log(' info Show help\\n');\n consola.log('Examples:');\n consola.log(' npx djangocfg-docs search \"database configuration\"');\n consola.log(' npx djangocfg-docs search \"redis cache\"');\n consola.log(' npx djangocfg-docs mcp');\n break;\n }\n}\n\nmain();\n","/**\n * AI Documentation Constants\n */\n\n// MCP Server URLs\nexport const MCP_BASE_URL = 'https://mcp.djangocfg.com';\nexport const MCP_SERVER_URL = `${MCP_BASE_URL}/mcp`;\nexport const MCP_API_URL = `${MCP_BASE_URL}/api/search`;\n\n// API Endpoints\nexport const API_SEARCH_ENDPOINT = '/api/search';\nexport const API_INFO_ENDPOINT = '/api/info';\nexport const DEFAULT_TIMEOUT = 10000; // ms\n\n// AI Hint for console output\nexport const AI_DOCS_HINT = `šŸ¤– AI Docs: ${MCP_SERVER_URL} | pnpm ai-docs search \"query\"`;\n\n// Full AI Hint description\nexport const AI_HINT = `\nDjangoCFG Documentation is available via MCP server.\n\nTo get help with DjangoCFG configuration:\n1. Use the MCP server: ${MCP_SERVER_URL}\n2. Or search directly: ${MCP_API_URL}?q=YOUR_QUERY&limit=5\n\nExample queries:\n- \"How to configure PostgreSQL database?\"\n- \"What is DatabaseConfig?\"\n- \"How to setup Redis cache?\"\n- \"Email configuration with SMTP\"\n`;\n","/**\n * DjangoCFG Documentation Client\n *\n * HTTP client for accessing DjangoCFG documentation via MCP server API.\n */\n\nimport {\n MCP_BASE_URL,\n API_SEARCH_ENDPOINT,\n API_INFO_ENDPOINT,\n DEFAULT_TIMEOUT,\n} from './constants';\nimport type { SearchResult, SearchOptions, McpConfig, ApiSearchResponse } from './types';\n\n/**\n * Client for DjangoCFG Documentation API.\n */\nexport class DjangoCfgDocsClient {\n private baseUrl: string;\n private timeout: number;\n\n constructor(baseUrl: string = MCP_BASE_URL, timeout: number = DEFAULT_TIMEOUT) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.timeout = timeout;\n }\n\n private async makeRequest<T>(endpoint: string, params?: Record<string, string | number>): Promise<T> {\n let url = `${this.baseUrl}${endpoint}`;\n\n if (params) {\n const searchParams = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n searchParams.set(key, String(value));\n }\n url = `${url}?${searchParams.toString()}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n 'User-Agent': 'DjangoCFG-AI-Client/1.0',\n },\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP Error ${response.status}: ${response.statusText}`);\n }\n\n return await response.json();\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Search documentation.\n */\n async search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n const { limit = 5, category } = options;\n\n const params: Record<string, string | number> = { q: query, limit };\n if (category) {\n params.category = category;\n }\n\n const data = await this.makeRequest<ApiSearchResponse>(API_SEARCH_ENDPOINT, params);\n\n const results = data.results || (Array.isArray(data) ? data : []);\n\n return results.map((item) => ({\n title: item.title || '',\n content: item.content || item.snippet || '',\n url: item.url || '',\n score: item.score || 0,\n category: item.category || '',\n }));\n }\n\n /**\n * Get detailed info about a specific topic.\n */\n async getInfo(topic: string): Promise<Record<string, unknown>> {\n return this.makeRequest(API_INFO_ENDPOINT, { topic });\n }\n\n /**\n * Get MCP server configuration for AI assistants.\n */\n getMcpConfig(): McpConfig {\n return {\n mcpServers: {\n 'djangocfg-docs': {\n url: `${this.baseUrl}/mcp`,\n },\n },\n };\n }\n}\n\n// Default client instance\nlet defaultClient: DjangoCfgDocsClient | null = null;\n\nfunction getClient(): DjangoCfgDocsClient {\n if (!defaultClient) {\n defaultClient = new DjangoCfgDocsClient();\n }\n return defaultClient;\n}\n\n/**\n * Search DjangoCFG documentation.\n *\n * @example\n * ```ts\n * const results = await search('database configuration');\n * results.forEach(r => console.log(r.title, r.url));\n * ```\n */\nexport async function search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n return getClient().search(query, options);\n}\n\n/**\n * Get documentation as formatted text.\n *\n * @example\n * ```ts\n * const docs = await getDocs('How to configure PostgreSQL?');\n * console.log(docs);\n * ```\n */\nexport async function getDocs(query: string, limit: number = 3): Promise<string> {\n const results = await search(query, { limit });\n\n if (results.length === 0) {\n return `No documentation found for: ${query}`;\n }\n\n const output: string[] = [];\n\n results.forEach((r, i) => {\n output.push(`## ${i + 1}. ${r.title}`);\n output.push(r.content);\n if (r.url) {\n output.push(`šŸ“– Read more: ${r.url}`);\n }\n output.push('');\n });\n\n return output.join('\\n');\n}\n\n/**\n * Get detailed info about a topic.\n */\nexport async function getInfo(topic: string): Promise<Record<string, unknown>> {\n return getClient().getInfo(topic);\n}\n\n/**\n * Get MCP server configuration.\n */\nexport function getMcpConfig(): McpConfig {\n return getClient().getMcpConfig();\n}\n"],"mappings":"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","names":["query"]}
@@ -14,7 +14,7 @@ var require_package = __commonJS({
14
14
  "package.json"(exports, module) {
15
15
  module.exports = {
16
16
  name: "@djangocfg/nextjs",
17
- version: "2.1.7",
17
+ version: "2.1.9",
18
18
  description: "Next.js server utilities: sitemap, health, OG images, contact forms, navigation, config",
19
19
  keywords: [
20
20
  "nextjs",
@@ -107,7 +107,7 @@ var require_package = __commonJS({
107
107
  "LICENSE"
108
108
  ],
109
109
  bin: {
110
- "ai-docs": "./dist/ai/cli.mjs"
110
+ "djangocfg-docs": "./dist/ai/cli.mjs"
111
111
  },
112
112
  scripts: {
113
113
  build: "tsup",