agentic-knowledge-mcp 0.0.1 → 0.1.2
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/package.json +5 -5
- package/packages/cli/dist/cli.d.ts +2 -3
- package/packages/cli/dist/cli.js +15 -14
- package/packages/cli/dist/commands/create.js +13 -7
- package/packages/cli/dist/commands/init.js +117 -167
- package/packages/cli/dist/commands/refresh.js +248 -290
- package/packages/cli/dist/commands/status.js +185 -239
- package/packages/cli/dist/exports.d.ts +6 -0
- package/packages/cli/dist/exports.js +6 -0
- package/packages/cli/dist/index.d.ts +5 -4
- package/packages/cli/dist/index.js +30 -4
- package/packages/cli/package.json +9 -8
- package/packages/content-loader/dist/content/api-documentation-loader.js +27 -35
- package/packages/content-loader/dist/content/documentation-site-loader.js +27 -35
- package/packages/content-loader/dist/content/metadata-manager.d.ts +46 -56
- package/packages/content-loader/dist/content/metadata-manager.js +150 -147
- package/packages/content-loader/package.json +1 -1
- package/packages/core/dist/config/loader.js +162 -186
- package/packages/core/dist/config/manager.js +128 -160
- package/packages/core/dist/index.js +2 -16
- package/packages/core/dist/paths/calculator.d.ts +7 -0
- package/packages/core/dist/paths/calculator.js +143 -103
- package/packages/core/dist/paths/symlinks.d.ts +21 -0
- package/packages/core/dist/paths/symlinks.js +93 -0
- package/packages/core/dist/types.d.ts +35 -15
- package/packages/core/package.json +1 -1
- package/packages/mcp-server/dist/server.js +5 -5
- package/packages/mcp-server/package.json +2 -2
- package/packages/content-loader/dist/__tests__/debug-filtering.d.ts +0 -1
- package/packages/content-loader/dist/__tests__/debug-filtering.js +0 -17
- package/packages/content-loader/dist/__tests__/test-filtering.d.ts +0 -1
- package/packages/content-loader/dist/__tests__/test-filtering.js +0 -19
- package/packages/core/dist/content/api-documentation-loader.d.ts +0 -26
- package/packages/core/dist/content/api-documentation-loader.js +0 -45
- package/packages/core/dist/content/content-processor.d.ts +0 -44
- package/packages/core/dist/content/content-processor.js +0 -81
- package/packages/core/dist/content/documentation-site-loader.d.ts +0 -26
- package/packages/core/dist/content/documentation-site-loader.js +0 -45
- package/packages/core/dist/content/git-repo-loader.d.ts +0 -54
- package/packages/core/dist/content/git-repo-loader.js +0 -264
- package/packages/core/dist/content/index.d.ts +0 -9
- package/packages/core/dist/content/index.js +0 -9
- package/packages/core/dist/content/loader.d.ts +0 -50
- package/packages/core/dist/content/loader.js +0 -7
- package/packages/core/dist/content/metadata-manager.d.ts +0 -65
- package/packages/core/dist/content/metadata-manager.js +0 -160
|
@@ -10,171 +10,139 @@ import { findConfigPath } from "./discovery.js";
|
|
|
10
10
|
* Central configuration manager for all config file operations
|
|
11
11
|
*/
|
|
12
12
|
export class ConfigManager {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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 (this.configCache &&
|
|
24
|
+
now - this.configCache.loadTime < this.CONFIG_CACHE_TTL) {
|
|
25
|
+
return {
|
|
26
|
+
config: this.configCache.config,
|
|
27
|
+
configPath: this.configCache.configPath,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// Find and load fresh config
|
|
31
|
+
const configPath = await findConfigPath(startDir);
|
|
32
|
+
if (!configPath) {
|
|
33
|
+
throw new KnowledgeError(ErrorType.CONFIG_NOT_FOUND, "No configuration file found. Please ensure .knowledge/config.yaml exists in your project.", { searchPath: startDir || process.cwd() });
|
|
34
|
+
}
|
|
35
|
+
const config = await this.loadConfigFromPath(configPath);
|
|
36
|
+
// Cache the result
|
|
37
|
+
this.configCache = {
|
|
38
|
+
config,
|
|
39
|
+
configPath,
|
|
40
|
+
loadTime: now,
|
|
41
|
+
};
|
|
42
|
+
return { config, configPath };
|
|
40
43
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
);
|
|
44
|
+
/**
|
|
45
|
+
* Load configuration from specific file path
|
|
46
|
+
* @param configPath - Path to configuration file
|
|
47
|
+
* @returns Parsed configuration
|
|
48
|
+
*/
|
|
49
|
+
async loadConfigFromPath(configPath) {
|
|
50
|
+
try {
|
|
51
|
+
const content = await fs.readFile(configPath, "utf-8");
|
|
52
|
+
const parsed = load(content);
|
|
53
|
+
if (!validateConfig(parsed)) {
|
|
54
|
+
throw new KnowledgeError(ErrorType.CONFIG_INVALID, "Configuration file contains invalid structure", { configPath, parsed });
|
|
55
|
+
}
|
|
56
|
+
return parsed;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (error instanceof KnowledgeError) {
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
if (error.code === "ENOENT") {
|
|
63
|
+
throw new KnowledgeError(ErrorType.CONFIG_NOT_FOUND, `Configuration file not found: ${configPath}`, { configPath });
|
|
64
|
+
}
|
|
65
|
+
throw new KnowledgeError(ErrorType.CONFIG_INVALID, `Failed to parse configuration file: ${error instanceof Error ? error.message : String(error)}`, { configPath, originalError: error });
|
|
66
|
+
}
|
|
83
67
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Save configuration to file
|
|
70
|
+
* @param config - Configuration to save
|
|
71
|
+
* @param configPath - Path to save to (optional, uses cached path if available)
|
|
72
|
+
*/
|
|
73
|
+
async saveConfig(config, configPath) {
|
|
74
|
+
const targetPath = configPath || this.configCache?.configPath;
|
|
75
|
+
if (!targetPath) {
|
|
76
|
+
throw new KnowledgeError(ErrorType.CONFIG_INVALID, "No configuration path available. Load config first or provide explicit path.", { configPath });
|
|
77
|
+
}
|
|
78
|
+
// Validate config before saving
|
|
79
|
+
if (!validateConfig(config)) {
|
|
80
|
+
throw new KnowledgeError(ErrorType.CONFIG_INVALID, "Cannot save invalid configuration", { config });
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const yamlContent = dump(config, {
|
|
84
|
+
indent: 2,
|
|
85
|
+
lineWidth: 120,
|
|
86
|
+
noRefs: true,
|
|
87
|
+
});
|
|
88
|
+
await fs.writeFile(targetPath, yamlContent, "utf-8");
|
|
89
|
+
// Invalidate cache since config changed
|
|
90
|
+
this.configCache = null;
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
throw new KnowledgeError(ErrorType.CONFIG_INVALID, `Failed to save configuration: ${error instanceof Error ? error.message : String(error)}`, { configPath: targetPath, originalError: error });
|
|
94
|
+
}
|
|
98
95
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Update paths for a specific docset with discovered files
|
|
98
|
+
* @param docsetId - ID of docset to update
|
|
99
|
+
* @param discoveredPaths - Array of file paths that were discovered
|
|
100
|
+
* @returns Updated configuration
|
|
101
|
+
*/
|
|
102
|
+
async updateDocsetPaths(docsetId, discoveredPaths) {
|
|
103
|
+
const { config } = await this.loadConfig();
|
|
104
|
+
// Find the docset to update
|
|
105
|
+
const docset = config.docsets.find((d) => d.id === docsetId);
|
|
106
|
+
if (!docset) {
|
|
107
|
+
throw new KnowledgeError(ErrorType.CONFIG_INVALID, `Docset '${docsetId}' not found in configuration`, { docsetId, availableDocsets: config.docsets.map((d) => d.id) });
|
|
108
|
+
}
|
|
109
|
+
// Update sources with discovered paths
|
|
110
|
+
if (docset.sources) {
|
|
111
|
+
for (const source of docset.sources) {
|
|
112
|
+
if (source.type === "git_repo") {
|
|
113
|
+
// Add or update the paths in options
|
|
114
|
+
if (!source.paths) {
|
|
115
|
+
source.paths = [];
|
|
116
|
+
}
|
|
117
|
+
source.paths = discoveredPaths;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Save updated configuration
|
|
122
|
+
await this.saveConfig(config);
|
|
123
|
+
return config;
|
|
106
124
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
);
|
|
125
|
+
/**
|
|
126
|
+
* Find configuration file path
|
|
127
|
+
* @param startDir - Directory to start searching from
|
|
128
|
+
* @returns Path to config file or null if not found
|
|
129
|
+
*/
|
|
130
|
+
async findConfigPath(startDir) {
|
|
131
|
+
return await findConfigPath(startDir);
|
|
122
132
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
);
|
|
133
|
+
/**
|
|
134
|
+
* Clear configuration cache (useful for testing)
|
|
135
|
+
*/
|
|
136
|
+
clearCache() {
|
|
137
|
+
this.configCache = null;
|
|
140
138
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
webSource.options.paths = discoveredPaths;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
139
|
+
/**
|
|
140
|
+
* Check if configuration exists
|
|
141
|
+
* @param startDir - Directory to start searching from
|
|
142
|
+
* @returns True if config file exists
|
|
143
|
+
*/
|
|
144
|
+
async configExists(startDir) {
|
|
145
|
+
const path = await this.findConfigPath(startDir);
|
|
146
|
+
return path !== null;
|
|
152
147
|
}
|
|
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
148
|
}
|
|
@@ -11,20 +11,6 @@ export { findConfigPath, findConfigPathSync } from "./config/discovery.js";
|
|
|
11
11
|
export { loadConfig, loadConfigSync, validateConfig } from "./config/loader.js";
|
|
12
12
|
export { ConfigManager } from "./config/manager.js";
|
|
13
13
|
// Export path calculation utilities
|
|
14
|
-
export {
|
|
15
|
-
calculateLocalPath,
|
|
16
|
-
formatPath,
|
|
17
|
-
validatePath,
|
|
18
|
-
validatePathSync,
|
|
19
|
-
getRelativePath,
|
|
20
|
-
ensureKnowledgeGitignore,
|
|
21
|
-
ensureKnowledgeGitignoreSync,
|
|
22
|
-
} from "./paths/calculator.js";
|
|
14
|
+
export { calculateLocalPath, formatPath, validatePath, validatePathSync, getRelativePath, ensureKnowledgeGitignore, ensureKnowledgeGitignoreSync, } from "./paths/calculator.js";
|
|
23
15
|
// Export template processing
|
|
24
|
-
export {
|
|
25
|
-
processTemplate,
|
|
26
|
-
getEffectiveTemplate,
|
|
27
|
-
validateTemplate,
|
|
28
|
-
extractVariables,
|
|
29
|
-
createTemplateContext,
|
|
30
|
-
} from "./templates/processor.js";
|
|
16
|
+
export { processTemplate, getEffectiveTemplate, validateTemplate, extractVariables, createTemplateContext, } from "./templates/processor.js";
|
|
@@ -9,6 +9,13 @@ import type { DocsetConfig } from "../types.js";
|
|
|
9
9
|
* @returns Calculated local path
|
|
10
10
|
*/
|
|
11
11
|
export declare function calculateLocalPath(docset: DocsetConfig, configPath: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Calculate the local path for a docset and create symlinks if needed
|
|
14
|
+
* @param docset - Docset configuration
|
|
15
|
+
* @param configPath - Path to the configuration file
|
|
16
|
+
* @returns Calculated local path
|
|
17
|
+
*/
|
|
18
|
+
export declare function calculateLocalPathWithSymlinks(docset: DocsetConfig, configPath: string): Promise<string>;
|
|
12
19
|
/**
|
|
13
20
|
* Ensure .knowledge/.gitignore exists with docsets/ ignored
|
|
14
21
|
* @param configPath - Path to the configuration file
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Path calculation utilities
|
|
3
3
|
*/
|
|
4
|
-
import { resolve, dirname, isAbsolute, join, normalize } from "node:path";
|
|
4
|
+
import { resolve, dirname, isAbsolute, join, normalize, relative, } from "node:path";
|
|
5
5
|
import { promises as fs } from "node:fs";
|
|
6
6
|
import * as fsSync from "node:fs";
|
|
7
7
|
import * as pathModule from "node:path";
|
|
8
8
|
import { KnowledgeError, ErrorType } from "../types.js";
|
|
9
|
+
import { createSymlinks } from "./symlinks.js";
|
|
9
10
|
/**
|
|
10
11
|
* Calculate the local path for a docset
|
|
11
12
|
* @param docset - Docset configuration
|
|
@@ -13,109 +14,146 @@ import { KnowledgeError, ErrorType } from "../types.js";
|
|
|
13
14
|
* @returns Calculated local path
|
|
14
15
|
*/
|
|
15
16
|
export function calculateLocalPath(docset, configPath) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
try {
|
|
18
|
+
const configDir = dirname(configPath); // This is the .knowledge directory
|
|
19
|
+
const projectRoot = dirname(configDir); // This is the project root
|
|
20
|
+
if (!docset.sources || docset.sources.length === 0) {
|
|
21
|
+
throw new Error(`Docset '${docset.id}' must have sources configured`);
|
|
22
|
+
}
|
|
23
|
+
// For now, use the first source to determine the path
|
|
24
|
+
const primarySource = docset.sources[0];
|
|
25
|
+
if (!primarySource) {
|
|
26
|
+
throw new Error(`Docset '${docset.id}' has no sources configured`);
|
|
27
|
+
}
|
|
28
|
+
if (primarySource.type === "local_folder") {
|
|
29
|
+
// For local folders, return relative path from project root
|
|
30
|
+
if (!primarySource.paths || primarySource.paths.length === 0) {
|
|
31
|
+
throw new Error(`Local folder source for docset '${docset.id}' has no paths configured`);
|
|
32
|
+
}
|
|
33
|
+
const firstPath = primarySource.paths[0];
|
|
34
|
+
if (!firstPath) {
|
|
35
|
+
throw new Error(`Local folder source for docset '${docset.id}' has empty path`);
|
|
36
|
+
}
|
|
37
|
+
if (isAbsolute(firstPath)) {
|
|
38
|
+
// If absolute path, return as-is
|
|
39
|
+
return normalize(firstPath);
|
|
40
|
+
}
|
|
41
|
+
// If relative path, resolve from project root and return relative
|
|
42
|
+
const resolvedPath = resolve(projectRoot, firstPath);
|
|
43
|
+
return relative(projectRoot, resolvedPath) || ".";
|
|
44
|
+
}
|
|
45
|
+
if (primarySource.type === "git_repo") {
|
|
46
|
+
// For git repos, use standardized path: .knowledge/docsets/{id}
|
|
47
|
+
return join(configDir, "docsets", docset.id);
|
|
48
|
+
}
|
|
49
|
+
throw new Error(`Unsupported source type: ${primarySource.type}`);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
throw new KnowledgeError(ErrorType.PATH_INVALID, `Failed to calculate local path for docset '${docset.id}': ${error.message}`, { docset, configPath, error });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Calculate the local path for a docset and create symlinks if needed
|
|
57
|
+
* @param docset - Docset configuration
|
|
58
|
+
* @param configPath - Path to the configuration file
|
|
59
|
+
* @returns Calculated local path
|
|
60
|
+
*/
|
|
61
|
+
export async function calculateLocalPathWithSymlinks(docset, configPath) {
|
|
62
|
+
const configDir = dirname(configPath);
|
|
63
|
+
const projectRoot = dirname(configDir);
|
|
64
|
+
if (!docset.sources || docset.sources.length === 0) {
|
|
65
|
+
throw new Error(`Docset '${docset.id}' must have sources configured`);
|
|
66
|
+
}
|
|
67
|
+
const primarySource = docset.sources[0];
|
|
68
|
+
if (!primarySource) {
|
|
69
|
+
throw new Error(`Docset '${docset.id}' has no sources configured`);
|
|
21
70
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
71
|
+
if (primarySource.type === "local_folder") {
|
|
72
|
+
// Create symlinks in .knowledge/docsets/{id}/
|
|
73
|
+
const symlinkDir = join(configDir, "docsets", docset.id);
|
|
74
|
+
if (!primarySource.paths || primarySource.paths.length === 0) {
|
|
75
|
+
throw new Error(`Local folder source for docset '${docset.id}' has no paths configured`);
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
await createSymlinks(primarySource.paths, symlinkDir, projectRoot);
|
|
79
|
+
// Return relative path to symlink directory
|
|
80
|
+
return relative(projectRoot, symlinkDir) || ".";
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
throw new KnowledgeError(ErrorType.PATH_INVALID, `Failed to create symlinks for docset '${docset.id}': ${error.message}`, { docset, configPath, error });
|
|
84
|
+
}
|
|
27
85
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return normalize(docset.local_path);
|
|
86
|
+
if (primarySource.type === "git_repo") {
|
|
87
|
+
// For git repos, use standardized path: .knowledge/docsets/{id}
|
|
88
|
+
return join(configDir, "docsets", docset.id);
|
|
32
89
|
}
|
|
33
|
-
|
|
34
|
-
const resolvedPath = resolve(projectRoot, docset.local_path);
|
|
35
|
-
return normalize(resolvedPath);
|
|
36
|
-
} catch (error) {
|
|
37
|
-
throw new KnowledgeError(
|
|
38
|
-
ErrorType.PATH_INVALID,
|
|
39
|
-
`Failed to calculate local path for docset '${docset.id}': ${error.message}`,
|
|
40
|
-
{ docset, configPath, error },
|
|
41
|
-
);
|
|
42
|
-
}
|
|
90
|
+
throw new Error(`Unsupported source type: ${primarySource.type}`);
|
|
43
91
|
}
|
|
44
92
|
/**
|
|
45
93
|
* Ensure .knowledge/.gitignore exists with docsets/ ignored
|
|
46
94
|
* @param configPath - Path to the configuration file
|
|
47
95
|
*/
|
|
48
96
|
export async function ensureKnowledgeGitignore(configPath) {
|
|
49
|
-
try {
|
|
50
|
-
const configDir = dirname(configPath);
|
|
51
|
-
const gitignorePath = join(configDir, ".gitignore");
|
|
52
|
-
// Check if .gitignore already exists
|
|
53
97
|
try {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
98
|
+
const configDir = dirname(configPath);
|
|
99
|
+
const gitignorePath = join(configDir, ".gitignore");
|
|
100
|
+
// Check if .gitignore already exists
|
|
101
|
+
try {
|
|
102
|
+
const content = await fs.readFile(gitignorePath, "utf-8");
|
|
103
|
+
// Check if it already contains docsets/ ignore rule
|
|
104
|
+
if (content.includes("docsets/")) {
|
|
105
|
+
return; // Already configured
|
|
106
|
+
}
|
|
107
|
+
// Append to existing file
|
|
108
|
+
await fs.appendFile(gitignorePath, "\n# Agentic Knowledge - Downloaded docsets\ndocsets/\n");
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
// File doesn't exist, create it
|
|
112
|
+
if (error.code === "ENOENT") {
|
|
113
|
+
await fs.writeFile(gitignorePath, "# Agentic Knowledge - Downloaded docsets\ndocsets/\n");
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
// Don't fail the entire operation if gitignore creation fails
|
|
122
|
+
console.warn(`Warning: Could not create .knowledge/.gitignore: ${error.message}`);
|
|
74
123
|
}
|
|
75
|
-
} catch (error) {
|
|
76
|
-
// Don't fail the entire operation if gitignore creation fails
|
|
77
|
-
console.warn(
|
|
78
|
-
`Warning: Could not create .knowledge/.gitignore: ${error.message}`,
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
124
|
}
|
|
82
125
|
/**
|
|
83
126
|
* Synchronous version of ensureKnowledgeGitignore
|
|
84
127
|
* @param configPath - Path to the configuration file
|
|
85
128
|
*/
|
|
86
129
|
export function ensureKnowledgeGitignoreSync(configPath) {
|
|
87
|
-
try {
|
|
88
|
-
const configDir = dirname(configPath);
|
|
89
|
-
const gitignorePath = join(configDir, ".gitignore");
|
|
90
|
-
// Check if .gitignore already exists
|
|
91
130
|
try {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
131
|
+
const configDir = dirname(configPath);
|
|
132
|
+
const gitignorePath = join(configDir, ".gitignore");
|
|
133
|
+
// Check if .gitignore already exists
|
|
134
|
+
try {
|
|
135
|
+
const content = fsSync.readFileSync(gitignorePath, "utf-8");
|
|
136
|
+
// Check if it already contains docsets/ ignore rule
|
|
137
|
+
if (content.includes("docsets/")) {
|
|
138
|
+
return; // Already configured
|
|
139
|
+
}
|
|
140
|
+
// Append to existing file
|
|
141
|
+
fsSync.appendFileSync(gitignorePath, "\n# Agentic Knowledge - Downloaded docsets\ndocsets/\n");
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
// File doesn't exist, create it
|
|
145
|
+
if (error.code === "ENOENT") {
|
|
146
|
+
fsSync.writeFileSync(gitignorePath, "# Agentic Knowledge - Downloaded docsets\ndocsets/\n");
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
// Don't fail the entire operation if gitignore creation fails
|
|
155
|
+
console.warn(`Warning: Could not create .knowledge/.gitignore: ${error.message}`);
|
|
112
156
|
}
|
|
113
|
-
} catch (error) {
|
|
114
|
-
// Don't fail the entire operation if gitignore creation fails
|
|
115
|
-
console.warn(
|
|
116
|
-
`Warning: Could not create .knowledge/.gitignore: ${error.message}`,
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
157
|
}
|
|
120
158
|
/**
|
|
121
159
|
* Format a path for use in instructions (normalize separators, etc.)
|
|
@@ -123,11 +161,11 @@ export function ensureKnowledgeGitignoreSync(configPath) {
|
|
|
123
161
|
* @returns Formatted path
|
|
124
162
|
*/
|
|
125
163
|
export function formatPath(path) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
164
|
+
// Normalize path separators and remove redundant separators
|
|
165
|
+
const normalized = normalize(path);
|
|
166
|
+
// Ensure path ends with separator for directory paths (if it looks like a directory)
|
|
167
|
+
// This helps with search instructions that need to specify directories
|
|
168
|
+
return normalized;
|
|
131
169
|
}
|
|
132
170
|
/**
|
|
133
171
|
* Validate that a path is accessible and exists
|
|
@@ -135,12 +173,13 @@ export function formatPath(path) {
|
|
|
135
173
|
* @returns True if path exists and is accessible
|
|
136
174
|
*/
|
|
137
175
|
export async function validatePath(path) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
176
|
+
try {
|
|
177
|
+
await fs.access(path);
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
144
183
|
}
|
|
145
184
|
/**
|
|
146
185
|
* Synchronous version of validatePath
|
|
@@ -148,12 +187,13 @@ export async function validatePath(path) {
|
|
|
148
187
|
* @returns True if path exists and is accessible
|
|
149
188
|
*/
|
|
150
189
|
export function validatePathSync(path) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
190
|
+
try {
|
|
191
|
+
fsSync.accessSync(path);
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
157
197
|
}
|
|
158
198
|
/**
|
|
159
199
|
* Get relative path from one location to another (useful for instructions)
|
|
@@ -162,5 +202,5 @@ export function validatePathSync(path) {
|
|
|
162
202
|
* @returns Relative path from 'from' to 'to'
|
|
163
203
|
*/
|
|
164
204
|
export function getRelativePath(from, to) {
|
|
165
|
-
|
|
205
|
+
return pathModule.relative(from, to);
|
|
166
206
|
}
|