agentic-knowledge-mcp 0.0.1

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 (77) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +530 -0
  3. package/package.json +94 -0
  4. package/packages/cli/dist/cli.d.ts +5 -0
  5. package/packages/cli/dist/cli.js +21 -0
  6. package/packages/cli/dist/commands/create.d.ts +5 -0
  7. package/packages/cli/dist/commands/create.js +90 -0
  8. package/packages/cli/dist/commands/init.d.ts +5 -0
  9. package/packages/cli/dist/commands/init.js +182 -0
  10. package/packages/cli/dist/commands/refresh.d.ts +5 -0
  11. package/packages/cli/dist/commands/refresh.js +322 -0
  12. package/packages/cli/dist/commands/status.d.ts +5 -0
  13. package/packages/cli/dist/commands/status.js +268 -0
  14. package/packages/cli/dist/index.d.ts +6 -0
  15. package/packages/cli/dist/index.js +6 -0
  16. package/packages/cli/package.json +57 -0
  17. package/packages/content-loader/dist/__tests__/debug-filtering.d.ts +1 -0
  18. package/packages/content-loader/dist/__tests__/debug-filtering.js +17 -0
  19. package/packages/content-loader/dist/__tests__/test-filtering.d.ts +1 -0
  20. package/packages/content-loader/dist/__tests__/test-filtering.js +19 -0
  21. package/packages/content-loader/dist/content/api-documentation-loader.d.ts +26 -0
  22. package/packages/content-loader/dist/content/api-documentation-loader.js +45 -0
  23. package/packages/content-loader/dist/content/content-processor.d.ts +44 -0
  24. package/packages/content-loader/dist/content/content-processor.js +86 -0
  25. package/packages/content-loader/dist/content/documentation-site-loader.d.ts +26 -0
  26. package/packages/content-loader/dist/content/documentation-site-loader.js +45 -0
  27. package/packages/content-loader/dist/content/git-repo-loader.d.ts +79 -0
  28. package/packages/content-loader/dist/content/git-repo-loader.js +368 -0
  29. package/packages/content-loader/dist/content/index.d.ts +9 -0
  30. package/packages/content-loader/dist/content/index.js +9 -0
  31. package/packages/content-loader/dist/content/loader.d.ts +47 -0
  32. package/packages/content-loader/dist/content/loader.js +8 -0
  33. package/packages/content-loader/dist/content/metadata-manager.d.ts +65 -0
  34. package/packages/content-loader/dist/content/metadata-manager.js +160 -0
  35. package/packages/content-loader/dist/index.d.ts +5 -0
  36. package/packages/content-loader/dist/index.js +5 -0
  37. package/packages/content-loader/dist/types.d.ts +127 -0
  38. package/packages/content-loader/dist/types.js +48 -0
  39. package/packages/content-loader/package.json +50 -0
  40. package/packages/core/dist/config/discovery.d.ts +15 -0
  41. package/packages/core/dist/config/discovery.js +65 -0
  42. package/packages/core/dist/config/loader.d.ts +22 -0
  43. package/packages/core/dist/config/loader.js +236 -0
  44. package/packages/core/dist/config/manager.d.ts +55 -0
  45. package/packages/core/dist/config/manager.js +180 -0
  46. package/packages/core/dist/content/api-documentation-loader.d.ts +26 -0
  47. package/packages/core/dist/content/api-documentation-loader.js +45 -0
  48. package/packages/core/dist/content/content-processor.d.ts +44 -0
  49. package/packages/core/dist/content/content-processor.js +81 -0
  50. package/packages/core/dist/content/documentation-site-loader.d.ts +26 -0
  51. package/packages/core/dist/content/documentation-site-loader.js +45 -0
  52. package/packages/core/dist/content/git-repo-loader.d.ts +54 -0
  53. package/packages/core/dist/content/git-repo-loader.js +264 -0
  54. package/packages/core/dist/content/index.d.ts +9 -0
  55. package/packages/core/dist/content/index.js +9 -0
  56. package/packages/core/dist/content/loader.d.ts +50 -0
  57. package/packages/core/dist/content/loader.js +7 -0
  58. package/packages/core/dist/content/metadata-manager.d.ts +65 -0
  59. package/packages/core/dist/content/metadata-manager.js +160 -0
  60. package/packages/core/dist/index.d.ts +12 -0
  61. package/packages/core/dist/index.js +30 -0
  62. package/packages/core/dist/paths/calculator.d.ts +46 -0
  63. package/packages/core/dist/paths/calculator.js +166 -0
  64. package/packages/core/dist/templates/processor.d.ts +40 -0
  65. package/packages/core/dist/templates/processor.js +111 -0
  66. package/packages/core/dist/types.d.ts +129 -0
  67. package/packages/core/dist/types.js +79 -0
  68. package/packages/core/package.json +50 -0
  69. package/packages/mcp-server/dist/bin.d.ts +5 -0
  70. package/packages/mcp-server/dist/bin.js +10 -0
  71. package/packages/mcp-server/dist/cli.d.ts +7 -0
  72. package/packages/mcp-server/dist/cli.js +17 -0
  73. package/packages/mcp-server/dist/index.d.ts +8 -0
  74. package/packages/mcp-server/dist/index.js +9 -0
  75. package/packages/mcp-server/dist/server.d.ts +35 -0
  76. package/packages/mcp-server/dist/server.js +244 -0
  77. package/packages/mcp-server/package.json +54 -0
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Configuration loading and validation
3
+ */
4
+ import { promises as fs } from "node:fs";
5
+ import * as fsSync from "node:fs";
6
+ import { load } from "js-yaml";
7
+ import { KnowledgeError, ErrorType } from "../types.js";
8
+ import { validateTemplate } from "../templates/processor.js";
9
+ /**
10
+ * Load configuration from a YAML file with strict template validation
11
+ * @param configPath - Path to the configuration file
12
+ * @returns Parsed configuration object
13
+ */
14
+ export async function loadConfig(configPath) {
15
+ try {
16
+ const content = await fs.readFile(configPath, "utf-8");
17
+ const parsed = load(content);
18
+ if (!validateConfig(parsed)) {
19
+ throw new KnowledgeError(
20
+ ErrorType.CONFIG_INVALID,
21
+ "Configuration file contains invalid structure",
22
+ { configPath, parsed },
23
+ );
24
+ }
25
+ // Validate templates strictly at load time
26
+ validateAllTemplates(parsed, configPath);
27
+ return parsed;
28
+ } catch (error) {
29
+ if (error instanceof KnowledgeError) {
30
+ throw error;
31
+ }
32
+ if (error.code === "ENOENT") {
33
+ throw new KnowledgeError(
34
+ ErrorType.CONFIG_NOT_FOUND,
35
+ `Configuration file not found: ${configPath}`,
36
+ { configPath },
37
+ );
38
+ }
39
+ throw new KnowledgeError(
40
+ ErrorType.YAML_PARSE_ERROR,
41
+ `Failed to parse YAML configuration: ${error.message}`,
42
+ { configPath, error },
43
+ );
44
+ }
45
+ }
46
+ /**
47
+ * Synchronous version of loadConfig with strict template validation
48
+ * @param configPath - Path to the configuration file
49
+ * @returns Parsed configuration object
50
+ */
51
+ export function loadConfigSync(configPath) {
52
+ try {
53
+ const content = fsSync.readFileSync(configPath, "utf-8");
54
+ const parsed = load(content);
55
+ if (!validateConfig(parsed)) {
56
+ throw new KnowledgeError(
57
+ ErrorType.CONFIG_INVALID,
58
+ "Configuration file contains invalid structure",
59
+ { configPath, parsed },
60
+ );
61
+ }
62
+ // Validate templates strictly at load time
63
+ validateAllTemplates(parsed, configPath);
64
+ return parsed;
65
+ } catch (error) {
66
+ if (error instanceof KnowledgeError) {
67
+ throw error;
68
+ }
69
+ if (error.code === "ENOENT") {
70
+ throw new KnowledgeError(
71
+ ErrorType.CONFIG_NOT_FOUND,
72
+ `Configuration file not found: ${configPath}`,
73
+ { configPath },
74
+ );
75
+ }
76
+ throw new KnowledgeError(
77
+ ErrorType.YAML_PARSE_ERROR,
78
+ `Failed to parse YAML configuration: ${error.message}`,
79
+ { configPath, error },
80
+ );
81
+ }
82
+ }
83
+ /**
84
+ * Validate all templates in configuration at load time
85
+ * @param config - Configuration object to validate
86
+ * @param configPath - Path to config file for error context
87
+ */
88
+ function validateAllTemplates(config, configPath) {
89
+ // Validate global template if present
90
+ if (config.template) {
91
+ try {
92
+ validateTemplate(config.template);
93
+ } catch (error) {
94
+ throw new KnowledgeError(
95
+ ErrorType.TEMPLATE_ERROR,
96
+ `Invalid global template in configuration: ${error.message}`,
97
+ { configPath, template: config.template, originalError: error },
98
+ );
99
+ }
100
+ }
101
+ // Validate each docset template if present
102
+ for (const docset of config.docsets) {
103
+ if (docset.template) {
104
+ try {
105
+ validateTemplate(docset.template);
106
+ } catch (error) {
107
+ throw new KnowledgeError(
108
+ ErrorType.TEMPLATE_ERROR,
109
+ `Invalid template for docset '${docset.id}': ${error.message}`,
110
+ {
111
+ configPath,
112
+ docsetId: docset.id,
113
+ template: docset.template,
114
+ originalError: error,
115
+ },
116
+ );
117
+ }
118
+ }
119
+ }
120
+ }
121
+ /**
122
+ * Validate a configuration object
123
+ * @param config - Configuration to validate
124
+ * @returns True if valid, false if invalid
125
+ */
126
+ export function validateConfig(config) {
127
+ if (!config || typeof config !== "object") {
128
+ return false;
129
+ }
130
+ const obj = config;
131
+ // Check required fields
132
+ if (typeof obj["version"] !== "string") {
133
+ return false;
134
+ }
135
+ if (!Array.isArray(obj["docsets"])) {
136
+ return false;
137
+ }
138
+ // Validate each docset
139
+ for (const docset of obj["docsets"]) {
140
+ if (!validateDocset(docset)) {
141
+ return false;
142
+ }
143
+ }
144
+ // Optional template field
145
+ if (obj["template"] !== undefined && typeof obj["template"] !== "string") {
146
+ return false;
147
+ }
148
+ return true;
149
+ }
150
+ /**
151
+ * Validate a docset configuration object
152
+ * @param docset - Docset to validate
153
+ * @returns True if valid, false if invalid
154
+ */
155
+ function validateDocset(docset) {
156
+ if (!docset || typeof docset !== "object") {
157
+ return false;
158
+ }
159
+ const obj = docset;
160
+ // Check required fields
161
+ if (typeof obj["id"] !== "string" || obj["id"].toString().trim() === "") {
162
+ return false;
163
+ }
164
+ if (typeof obj["name"] !== "string" || obj["name"].toString().trim() === "") {
165
+ return false;
166
+ }
167
+ // local_path is optional if web_sources are provided
168
+ const hasWebSources =
169
+ Array.isArray(obj["web_sources"]) && obj["web_sources"].length > 0;
170
+ const hasLocalPath =
171
+ typeof obj["local_path"] === "string" &&
172
+ obj["local_path"].toString().trim() !== "";
173
+ if (!hasWebSources && !hasLocalPath) {
174
+ return false; // Must have either web_sources or local_path
175
+ }
176
+ if (
177
+ obj["local_path"] !== undefined &&
178
+ typeof obj["local_path"] !== "string"
179
+ ) {
180
+ return false; // If local_path is provided, it must be a valid string
181
+ }
182
+ // Check optional fields
183
+ if (
184
+ obj["description"] !== undefined &&
185
+ typeof obj["description"] !== "string"
186
+ ) {
187
+ return false;
188
+ }
189
+ if (obj["template"] !== undefined && typeof obj["template"] !== "string") {
190
+ return false;
191
+ }
192
+ // Check optional web_sources field
193
+ if (obj["web_sources"] !== undefined) {
194
+ if (!Array.isArray(obj["web_sources"])) {
195
+ return false;
196
+ }
197
+ // Validate each web source
198
+ for (const webSource of obj["web_sources"]) {
199
+ if (!validateWebSource(webSource)) {
200
+ return false;
201
+ }
202
+ }
203
+ }
204
+ return true;
205
+ }
206
+ /**
207
+ * Validate a web source configuration object
208
+ * @param webSource - Web source to validate
209
+ * @returns True if valid, false if invalid
210
+ */
211
+ function validateWebSource(webSource) {
212
+ if (!webSource || typeof webSource !== "object") {
213
+ return false;
214
+ }
215
+ const obj = webSource;
216
+ // Check required fields
217
+ if (typeof obj["url"] !== "string" || obj["url"].toString().trim() === "") {
218
+ return false;
219
+ }
220
+ if (typeof obj["type"] !== "string") {
221
+ return false;
222
+ }
223
+ // Validate type is one of the supported values
224
+ const validTypes = ["git_repo", "documentation_site", "api_documentation"];
225
+ if (!validTypes.includes(obj["type"])) {
226
+ return false;
227
+ }
228
+ // Check optional options field
229
+ if (
230
+ obj["options"] !== undefined &&
231
+ (typeof obj["options"] !== "object" || obj["options"] === null)
232
+ ) {
233
+ return false;
234
+ }
235
+ return true;
236
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Configuration management with read and write capabilities
3
+ */
4
+ import type { KnowledgeConfig } from "../types.js";
5
+ /**
6
+ * Central configuration manager for all config file operations
7
+ */
8
+ export declare class ConfigManager {
9
+ private configCache;
10
+ private readonly CONFIG_CACHE_TTL;
11
+ /**
12
+ * Load configuration with caching
13
+ * @param startDir - Directory to start searching from (defaults to cwd)
14
+ * @returns Configuration and path
15
+ */
16
+ loadConfig(startDir?: string): Promise<{
17
+ config: KnowledgeConfig;
18
+ configPath: string;
19
+ }>;
20
+ /**
21
+ * Load configuration from specific file path
22
+ * @param configPath - Path to configuration file
23
+ * @returns Parsed configuration
24
+ */
25
+ loadConfigFromPath(configPath: string): Promise<KnowledgeConfig>;
26
+ /**
27
+ * Save configuration to file
28
+ * @param config - Configuration to save
29
+ * @param configPath - Path to save to (optional, uses cached path if available)
30
+ */
31
+ saveConfig(config: KnowledgeConfig, configPath?: string): Promise<void>;
32
+ /**
33
+ * Update paths for a specific docset with discovered files
34
+ * @param docsetId - ID of docset to update
35
+ * @param discoveredPaths - Array of file paths that were discovered
36
+ * @returns Updated configuration
37
+ */
38
+ updateDocsetPaths(docsetId: string, discoveredPaths: string[]): Promise<KnowledgeConfig>;
39
+ /**
40
+ * Find configuration file path
41
+ * @param startDir - Directory to start searching from
42
+ * @returns Path to config file or null if not found
43
+ */
44
+ findConfigPath(startDir?: string): Promise<string | null>;
45
+ /**
46
+ * Clear configuration cache (useful for testing)
47
+ */
48
+ clearCache(): void;
49
+ /**
50
+ * Check if configuration exists
51
+ * @param startDir - Directory to start searching from
52
+ * @returns True if config file exists
53
+ */
54
+ configExists(startDir?: string): Promise<boolean>;
55
+ }
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Configuration management with read and write capabilities
3
+ */
4
+ import { promises as fs } from "node:fs";
5
+ import { load, dump } from "js-yaml";
6
+ import { KnowledgeError, ErrorType } from "../types.js";
7
+ import { validateConfig } from "./loader.js";
8
+ import { findConfigPath } from "./discovery.js";
9
+ /**
10
+ * Central configuration manager for all config file operations
11
+ */
12
+ export class ConfigManager {
13
+ configCache = null;
14
+ CONFIG_CACHE_TTL = 60000; // 1 minute cache
15
+ /**
16
+ * Load configuration with caching
17
+ * @param startDir - Directory to start searching from (defaults to cwd)
18
+ * @returns Configuration and path
19
+ */
20
+ async loadConfig(startDir) {
21
+ const now = Date.now();
22
+ // Return cached config if still valid
23
+ if (
24
+ this.configCache &&
25
+ now - this.configCache.loadTime < this.CONFIG_CACHE_TTL
26
+ ) {
27
+ return {
28
+ config: this.configCache.config,
29
+ configPath: this.configCache.configPath,
30
+ };
31
+ }
32
+ // Find and load fresh config
33
+ const configPath = await findConfigPath(startDir);
34
+ if (!configPath) {
35
+ throw new KnowledgeError(
36
+ ErrorType.CONFIG_NOT_FOUND,
37
+ "No configuration file found. Please ensure .knowledge/config.yaml exists in your project.",
38
+ { searchPath: startDir || process.cwd() },
39
+ );
40
+ }
41
+ const config = await this.loadConfigFromPath(configPath);
42
+ // Cache the result
43
+ this.configCache = {
44
+ config,
45
+ configPath,
46
+ loadTime: now,
47
+ };
48
+ return { config, configPath };
49
+ }
50
+ /**
51
+ * Load configuration from specific file path
52
+ * @param configPath - Path to configuration file
53
+ * @returns Parsed configuration
54
+ */
55
+ async loadConfigFromPath(configPath) {
56
+ try {
57
+ const content = await fs.readFile(configPath, "utf-8");
58
+ const parsed = load(content);
59
+ if (!validateConfig(parsed)) {
60
+ throw new KnowledgeError(
61
+ ErrorType.CONFIG_INVALID,
62
+ "Configuration file contains invalid structure",
63
+ { configPath, parsed },
64
+ );
65
+ }
66
+ return parsed;
67
+ } catch (error) {
68
+ if (error instanceof KnowledgeError) {
69
+ throw error;
70
+ }
71
+ if (error.code === "ENOENT") {
72
+ throw new KnowledgeError(
73
+ ErrorType.CONFIG_NOT_FOUND,
74
+ `Configuration file not found: ${configPath}`,
75
+ { configPath },
76
+ );
77
+ }
78
+ throw new KnowledgeError(
79
+ ErrorType.CONFIG_INVALID,
80
+ `Failed to parse configuration file: ${error instanceof Error ? error.message : String(error)}`,
81
+ { configPath, originalError: error },
82
+ );
83
+ }
84
+ }
85
+ /**
86
+ * Save configuration to file
87
+ * @param config - Configuration to save
88
+ * @param configPath - Path to save to (optional, uses cached path if available)
89
+ */
90
+ async saveConfig(config, configPath) {
91
+ const targetPath = configPath || this.configCache?.configPath;
92
+ if (!targetPath) {
93
+ throw new KnowledgeError(
94
+ ErrorType.CONFIG_INVALID,
95
+ "No configuration path available. Load config first or provide explicit path.",
96
+ { configPath },
97
+ );
98
+ }
99
+ // Validate config before saving
100
+ if (!validateConfig(config)) {
101
+ throw new KnowledgeError(
102
+ ErrorType.CONFIG_INVALID,
103
+ "Cannot save invalid configuration",
104
+ { config },
105
+ );
106
+ }
107
+ try {
108
+ const yamlContent = dump(config, {
109
+ indent: 2,
110
+ lineWidth: 120,
111
+ noRefs: true,
112
+ });
113
+ await fs.writeFile(targetPath, yamlContent, "utf-8");
114
+ // Invalidate cache since config changed
115
+ this.configCache = null;
116
+ } catch (error) {
117
+ throw new KnowledgeError(
118
+ ErrorType.CONFIG_INVALID,
119
+ `Failed to save configuration: ${error instanceof Error ? error.message : String(error)}`,
120
+ { configPath: targetPath, originalError: error },
121
+ );
122
+ }
123
+ }
124
+ /**
125
+ * Update paths for a specific docset with discovered files
126
+ * @param docsetId - ID of docset to update
127
+ * @param discoveredPaths - Array of file paths that were discovered
128
+ * @returns Updated configuration
129
+ */
130
+ async updateDocsetPaths(docsetId, discoveredPaths) {
131
+ const { config } = await this.loadConfig();
132
+ // Find the docset to update
133
+ const docset = config.docsets.find((d) => d.id === docsetId);
134
+ if (!docset) {
135
+ throw new KnowledgeError(
136
+ ErrorType.CONFIG_INVALID,
137
+ `Docset '${docsetId}' not found in configuration`,
138
+ { docsetId, availableDocsets: config.docsets.map((d) => d.id) },
139
+ );
140
+ }
141
+ // Update web sources with discovered paths
142
+ if (docset.web_sources) {
143
+ for (const webSource of docset.web_sources) {
144
+ if (webSource.type === "git_repo") {
145
+ // Add or update the paths in options
146
+ if (!webSource.options) {
147
+ webSource.options = {};
148
+ }
149
+ webSource.options.paths = discoveredPaths;
150
+ }
151
+ }
152
+ }
153
+ // Save updated configuration
154
+ await this.saveConfig(config);
155
+ return config;
156
+ }
157
+ /**
158
+ * Find configuration file path
159
+ * @param startDir - Directory to start searching from
160
+ * @returns Path to config file or null if not found
161
+ */
162
+ async findConfigPath(startDir) {
163
+ return await findConfigPath(startDir);
164
+ }
165
+ /**
166
+ * Clear configuration cache (useful for testing)
167
+ */
168
+ clearCache() {
169
+ this.configCache = null;
170
+ }
171
+ /**
172
+ * Check if configuration exists
173
+ * @param startDir - Directory to start searching from
174
+ * @returns True if config file exists
175
+ */
176
+ async configExists(startDir) {
177
+ const path = await this.findConfigPath(startDir);
178
+ return path !== null;
179
+ }
180
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * API documentation content loader (STUB - not implemented yet)
3
+ */
4
+ import { ContentLoader, type LoadResult } from "./loader.js";
5
+ import { WebSourceConfig } from "../types.js";
6
+ /**
7
+ * Content loader for API documentation (STUB IMPLEMENTATION)
8
+ */
9
+ export declare class ApiDocumentationLoader extends ContentLoader {
10
+ /**
11
+ * Check if this loader can handle the given web source type
12
+ */
13
+ canHandle(webSource: WebSourceConfig): boolean;
14
+ /**
15
+ * Validate the web source configuration
16
+ */
17
+ validateConfig(webSource: WebSourceConfig): true | string;
18
+ /**
19
+ * Load content from API documentation (NOT IMPLEMENTED)
20
+ */
21
+ load(webSource: WebSourceConfig, targetPath: string): Promise<LoadResult>;
22
+ /**
23
+ * Get content identifier (NOT IMPLEMENTED)
24
+ */
25
+ getContentId(webSource: WebSourceConfig): Promise<string>;
26
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * API documentation content loader (STUB - not implemented yet)
3
+ */
4
+ import { ContentLoader } from "./loader.js";
5
+ import { WebSourceType, KnowledgeError, ErrorType } from "../types.js";
6
+ /**
7
+ * Content loader for API documentation (STUB IMPLEMENTATION)
8
+ */
9
+ export class ApiDocumentationLoader extends ContentLoader {
10
+ /**
11
+ * Check if this loader can handle the given web source type
12
+ */
13
+ canHandle(webSource) {
14
+ return webSource.type === WebSourceType.API_DOCUMENTATION;
15
+ }
16
+ /**
17
+ * Validate the web source configuration
18
+ */
19
+ validateConfig(webSource) {
20
+ if (!webSource.url) {
21
+ return "API documentation URL is required";
22
+ }
23
+ return true;
24
+ }
25
+ /**
26
+ * Load content from API documentation (NOT IMPLEMENTED)
27
+ */
28
+ async load(webSource, targetPath) {
29
+ throw new KnowledgeError(
30
+ ErrorType.NOT_IMPLEMENTED,
31
+ "API documentation loading is not yet implemented. Use git_repo type for repositories with API documentation.",
32
+ { webSource: webSource.url, targetPath },
33
+ );
34
+ }
35
+ /**
36
+ * Get content identifier (NOT IMPLEMENTED)
37
+ */
38
+ async getContentId(webSource) {
39
+ throw new KnowledgeError(
40
+ ErrorType.NOT_IMPLEMENTED,
41
+ "API documentation content ID generation is not yet implemented.",
42
+ { webSource: webSource.url },
43
+ );
44
+ }
45
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Content processor for converting and preparing content
3
+ */
4
+ /**
5
+ * Options for content processing
6
+ */
7
+ export interface ProcessingOptions {
8
+ /** Add frontmatter with source metadata */
9
+ addFrontmatter?: boolean;
10
+ /** Source URL to include in frontmatter */
11
+ sourceUrl?: string;
12
+ /** Additional metadata to include */
13
+ metadata?: Record<string, unknown>;
14
+ }
15
+ /**
16
+ * Content processor for converting and preparing documentation content
17
+ */
18
+ export declare class ContentProcessor {
19
+ /**
20
+ * Process a file, optionally adding frontmatter metadata
21
+ * @param filePath - Path to the file to process
22
+ * @param options - Processing options
23
+ */
24
+ processFile(filePath: string, options?: ProcessingOptions): Promise<void>;
25
+ /**
26
+ * Add frontmatter to markdown content
27
+ * @param content - Original markdown content
28
+ * @param options - Processing options with metadata
29
+ * @returns Content with frontmatter added
30
+ */
31
+ private addFrontmatter;
32
+ /**
33
+ * Simple object to YAML conversion for frontmatter
34
+ * @param obj - Object to convert
35
+ * @returns YAML string
36
+ */
37
+ private objectToYaml;
38
+ /**
39
+ * Check if a file should be processed based on its extension
40
+ * @param filePath - Path to check
41
+ * @returns True if file should be processed
42
+ */
43
+ shouldProcess(filePath: string): boolean;
44
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Content processor for converting and preparing content
3
+ */
4
+ import { promises as fs } from "node:fs";
5
+ import * as path from "node:path";
6
+ /**
7
+ * Content processor for converting and preparing documentation content
8
+ */
9
+ export class ContentProcessor {
10
+ /**
11
+ * Process a file, optionally adding frontmatter metadata
12
+ * @param filePath - Path to the file to process
13
+ * @param options - Processing options
14
+ */
15
+ async processFile(filePath, options = {}) {
16
+ const content = await fs.readFile(filePath, "utf-8");
17
+ const extension = path.extname(filePath).toLowerCase();
18
+ // For markdown files, optionally add frontmatter
19
+ if (extension === ".md" || extension === ".mdx") {
20
+ if (options.addFrontmatter) {
21
+ const processedContent = this.addFrontmatter(content, options);
22
+ await fs.writeFile(filePath, processedContent, "utf-8");
23
+ }
24
+ }
25
+ // For other file types, we keep them as-is for now
26
+ // Future: HTML to Markdown conversion would go here
27
+ }
28
+ /**
29
+ * Add frontmatter to markdown content
30
+ * @param content - Original markdown content
31
+ * @param options - Processing options with metadata
32
+ * @returns Content with frontmatter added
33
+ */
34
+ addFrontmatter(content, options) {
35
+ // Check if frontmatter already exists
36
+ if (content.startsWith("---\n")) {
37
+ return content; // Don't modify existing frontmatter
38
+ }
39
+ const frontmatter = {};
40
+ if (options.sourceUrl) {
41
+ frontmatter["source_url"] = options.sourceUrl;
42
+ }
43
+ if (options.metadata) {
44
+ Object.assign(frontmatter, options.metadata);
45
+ }
46
+ // Add processed timestamp
47
+ frontmatter["processed_at"] = new Date().toISOString();
48
+ // Convert to YAML frontmatter
49
+ const yamlFrontmatter = this.objectToYaml(frontmatter);
50
+ return `---\n${yamlFrontmatter}---\n\n${content}`;
51
+ }
52
+ /**
53
+ * Simple object to YAML conversion for frontmatter
54
+ * @param obj - Object to convert
55
+ * @returns YAML string
56
+ */
57
+ objectToYaml(obj) {
58
+ return (
59
+ Object.entries(obj)
60
+ .map(([key, value]) => {
61
+ if (typeof value === "string") {
62
+ // Quote strings that contain special characters
63
+ const needsQuotes = /[:\n\r\t"']/.test(value);
64
+ return `${key}: ${needsQuotes ? `"${value.replace(/"/g, '\\"')}"` : value}`;
65
+ }
66
+ return `${key}: ${value}`;
67
+ })
68
+ .join("\n") + "\n"
69
+ );
70
+ }
71
+ /**
72
+ * Check if a file should be processed based on its extension
73
+ * @param filePath - Path to check
74
+ * @returns True if file should be processed
75
+ */
76
+ shouldProcess(filePath) {
77
+ const extension = path.extname(filePath).toLowerCase();
78
+ const processableExtensions = [".md", ".mdx", ".txt", ".rst"];
79
+ return processableExtensions.includes(extension);
80
+ }
81
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Documentation site content loader (STUB - not implemented yet)
3
+ */
4
+ import { ContentLoader, type LoadResult } from "./loader.js";
5
+ import { WebSourceConfig } from "../types.js";
6
+ /**
7
+ * Content loader for documentation websites (STUB IMPLEMENTATION)
8
+ */
9
+ export declare class DocumentationSiteLoader extends ContentLoader {
10
+ /**
11
+ * Check if this loader can handle the given web source type
12
+ */
13
+ canHandle(webSource: WebSourceConfig): boolean;
14
+ /**
15
+ * Validate the web source configuration
16
+ */
17
+ validateConfig(webSource: WebSourceConfig): true | string;
18
+ /**
19
+ * Load content from a documentation site (NOT IMPLEMENTED)
20
+ */
21
+ load(webSource: WebSourceConfig, targetPath: string): Promise<LoadResult>;
22
+ /**
23
+ * Get content identifier (NOT IMPLEMENTED)
24
+ */
25
+ getContentId(webSource: WebSourceConfig): Promise<string>;
26
+ }