@lssm/module.ai-chat 1.41.1 → 1.42.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.
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/dist/ai-chat.feature.d.ts +12 -0
- package/dist/ai-chat.feature.d.ts.map +1 -0
- package/dist/ai-chat.feature.js +95 -1
- package/dist/ai-chat.feature.js.map +1 -0
- package/dist/ai-chat.operations.d.ts +243 -0
- package/dist/ai-chat.operations.d.ts.map +1 -0
- package/dist/ai-chat.operations.js +174 -0
- package/dist/ai-chat.operations.js.map +1 -0
- package/dist/context/context-builder.d.ts +57 -0
- package/dist/context/context-builder.d.ts.map +1 -0
- package/dist/context/context-builder.js +148 -2
- package/dist/context/context-builder.js.map +1 -0
- package/dist/context/file-operations.d.ts +100 -0
- package/dist/context/file-operations.d.ts.map +1 -0
- package/dist/context/file-operations.js +175 -1
- package/dist/context/file-operations.js.map +1 -0
- package/dist/context/index.d.ts +4 -0
- package/dist/context/index.js +5 -1
- package/dist/context/workspace-context.d.ts +117 -0
- package/dist/context/workspace-context.d.ts.map +1 -0
- package/dist/context/workspace-context.js +124 -2
- package/dist/context/workspace-context.js.map +1 -0
- package/dist/core/chat-service.d.ts +73 -0
- package/dist/core/chat-service.d.ts.map +1 -0
- package/dist/core/chat-service.js +215 -2
- package/dist/core/chat-service.js.map +1 -0
- package/dist/core/conversation-store.d.ts +74 -0
- package/dist/core/conversation-store.d.ts.map +1 -0
- package/dist/core/conversation-store.js +109 -1
- package/dist/core/conversation-store.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.js +4 -1
- package/dist/core/message-types.d.ts +150 -0
- package/dist/core/message-types.d.ts.map +1 -0
- package/dist/events.d.ts +115 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +100 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +23 -1
- package/dist/libs/schema/dist/EnumType.js +2 -0
- package/dist/libs/schema/dist/FieldType.js +50 -0
- package/dist/libs/schema/dist/FieldType.js.map +1 -0
- package/dist/libs/schema/dist/ScalarTypeEnum.js +237 -0
- package/dist/libs/schema/dist/ScalarTypeEnum.js.map +1 -0
- package/dist/libs/schema/dist/SchemaModel.js +40 -0
- package/dist/libs/schema/dist/SchemaModel.js.map +1 -0
- package/dist/libs/schema/dist/entity/defineEntity.js +1 -0
- package/dist/libs/schema/dist/entity/index.js +2 -0
- package/dist/libs/schema/dist/entity/types.js +1 -0
- package/dist/libs/schema/dist/index.js +6 -0
- package/dist/presentation/components/ChatContainer.d.ts +21 -0
- package/dist/presentation/components/ChatContainer.d.ts.map +1 -0
- package/dist/presentation/components/ChatContainer.js +63 -1
- package/dist/presentation/components/ChatContainer.js.map +1 -0
- package/dist/presentation/components/ChatInput.d.ts +35 -0
- package/dist/presentation/components/ChatInput.d.ts.map +1 -0
- package/dist/presentation/components/ChatInput.js +149 -1
- package/dist/presentation/components/ChatInput.js.map +1 -0
- package/dist/presentation/components/ChatMessage.d.ts +24 -0
- package/dist/presentation/components/ChatMessage.d.ts.map +1 -0
- package/dist/presentation/components/ChatMessage.js +136 -1
- package/dist/presentation/components/ChatMessage.js.map +1 -0
- package/dist/presentation/components/CodePreview.d.ts +40 -0
- package/dist/presentation/components/CodePreview.d.ts.map +1 -0
- package/dist/presentation/components/CodePreview.js +127 -2
- package/dist/presentation/components/CodePreview.js.map +1 -0
- package/dist/presentation/components/ContextIndicator.d.ts +26 -0
- package/dist/presentation/components/ContextIndicator.d.ts.map +1 -0
- package/dist/presentation/components/ContextIndicator.js +97 -1
- package/dist/presentation/components/ContextIndicator.js.map +1 -0
- package/dist/presentation/components/ModelPicker.d.ts +39 -0
- package/dist/presentation/components/ModelPicker.d.ts.map +1 -0
- package/dist/presentation/components/ModelPicker.js +202 -1
- package/dist/presentation/components/ModelPicker.js.map +1 -0
- package/dist/presentation/components/index.d.ts +7 -0
- package/dist/presentation/components/index.js +8 -1
- package/dist/presentation/hooks/index.d.ts +3 -0
- package/dist/presentation/hooks/index.js +4 -1
- package/dist/presentation/hooks/useChat.d.ts +67 -0
- package/dist/presentation/hooks/useChat.d.ts.map +1 -0
- package/dist/presentation/hooks/useChat.js +172 -1
- package/dist/presentation/hooks/useChat.js.map +1 -0
- package/dist/presentation/hooks/useProviders.d.ts +38 -0
- package/dist/presentation/hooks/useProviders.d.ts.map +1 -0
- package/dist/presentation/hooks/useProviders.js +41 -1
- package/dist/presentation/hooks/useProviders.js.map +1 -0
- package/dist/presentation/index.d.ts +11 -0
- package/dist/presentation/index.js +12 -1
- package/dist/providers/chat-utilities.d.ts +15 -0
- package/dist/providers/chat-utilities.d.ts.map +1 -0
- package/dist/providers/chat-utilities.js +17 -1
- package/dist/providers/chat-utilities.js.map +1 -0
- package/dist/providers/index.d.ts +3 -0
- package/dist/providers/index.js +4 -1
- package/dist/schema.d.ts +222 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +102 -0
- package/dist/schema.js.map +1 -0
- package/package.json +29 -22
|
@@ -1,2 +1,148 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/context/context-builder.ts
|
|
2
|
+
/**
|
|
3
|
+
* Estimates token count from string (rough approximation)
|
|
4
|
+
*/
|
|
5
|
+
function estimateTokens(text) {
|
|
6
|
+
return Math.ceil(text.length / 4);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Calculate relevance score for a spec
|
|
10
|
+
*/
|
|
11
|
+
function scoreSpec(spec, query) {
|
|
12
|
+
if (!query) return .5;
|
|
13
|
+
const lowerQuery = query.toLowerCase();
|
|
14
|
+
let score = 0;
|
|
15
|
+
if (spec.name.toLowerCase().includes(lowerQuery)) score += .4;
|
|
16
|
+
if (spec.description?.toLowerCase().includes(lowerQuery)) score += .3;
|
|
17
|
+
if (spec.tags?.some((t) => t.toLowerCase().includes(lowerQuery))) score += .2;
|
|
18
|
+
return Math.min(score, 1);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Calculate relevance score for a file
|
|
22
|
+
*/
|
|
23
|
+
function scoreFile(file, query) {
|
|
24
|
+
if (!query) return .5;
|
|
25
|
+
const lowerQuery = query.toLowerCase();
|
|
26
|
+
let score = 0;
|
|
27
|
+
if (file.path.toLowerCase().includes(lowerQuery)) score += .5;
|
|
28
|
+
if (file.name.toLowerCase().includes(lowerQuery)) score += .3;
|
|
29
|
+
if (file.isSpec) score += .2;
|
|
30
|
+
return Math.min(score, 1);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Context builder for creating rich LLM context
|
|
34
|
+
*/
|
|
35
|
+
var ContextBuilder = class {
|
|
36
|
+
context;
|
|
37
|
+
constructor(context) {
|
|
38
|
+
this.context = context;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Build context for a chat message
|
|
42
|
+
*/
|
|
43
|
+
build(options = {}) {
|
|
44
|
+
const maxTokens = options.maxTokens ?? 4e3;
|
|
45
|
+
const entries = [];
|
|
46
|
+
let totalTokens = 0;
|
|
47
|
+
if (options.includeSpecs?.length) for (const specName of options.includeSpecs) {
|
|
48
|
+
const spec = this.context.getSpecs().find((s) => s.name === specName);
|
|
49
|
+
if (spec) {
|
|
50
|
+
const entry = {
|
|
51
|
+
type: "spec",
|
|
52
|
+
path: spec.path,
|
|
53
|
+
summary: `${spec.type}: ${spec.name}${spec.description ? ` - ${spec.description}` : ""}`,
|
|
54
|
+
relevance: 1
|
|
55
|
+
};
|
|
56
|
+
entries.push(entry);
|
|
57
|
+
totalTokens += estimateTokens(entry.summary ?? "");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (options.includeFiles?.length) for (const filePath of options.includeFiles) {
|
|
61
|
+
const file = this.context.getFiles().find((f) => f.path === filePath);
|
|
62
|
+
if (file) {
|
|
63
|
+
const entry = {
|
|
64
|
+
type: "file",
|
|
65
|
+
path: file.path,
|
|
66
|
+
summary: `File: ${file.relativePath}`,
|
|
67
|
+
relevance: 1
|
|
68
|
+
};
|
|
69
|
+
entries.push(entry);
|
|
70
|
+
totalTokens += estimateTokens(entry.summary ?? "");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (options.query) {
|
|
74
|
+
const scoredSpecs = this.context.getSpecs().map((spec) => ({
|
|
75
|
+
spec,
|
|
76
|
+
score: scoreSpec(spec, options.query)
|
|
77
|
+
})).filter(({ score }) => score > .2).sort((a, b) => b.score - a.score);
|
|
78
|
+
for (const { spec, score } of scoredSpecs) {
|
|
79
|
+
if (totalTokens >= maxTokens) break;
|
|
80
|
+
if (entries.some((e) => e.path === spec.path)) continue;
|
|
81
|
+
const entry = {
|
|
82
|
+
type: "spec",
|
|
83
|
+
path: spec.path,
|
|
84
|
+
summary: `${spec.type}: ${spec.name}${spec.description ? ` - ${spec.description}` : ""}`,
|
|
85
|
+
relevance: score
|
|
86
|
+
};
|
|
87
|
+
entries.push(entry);
|
|
88
|
+
totalTokens += estimateTokens(entry.summary ?? "");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (options.query) {
|
|
92
|
+
const scoredFiles = this.context.getFiles().map((file) => ({
|
|
93
|
+
file,
|
|
94
|
+
score: scoreFile(file, options.query)
|
|
95
|
+
})).filter(({ score }) => score > .2).sort((a, b) => b.score - a.score);
|
|
96
|
+
for (const { file, score } of scoredFiles) {
|
|
97
|
+
if (totalTokens >= maxTokens) break;
|
|
98
|
+
if (entries.some((e) => e.path === file.path)) continue;
|
|
99
|
+
const entry = {
|
|
100
|
+
type: "file",
|
|
101
|
+
path: file.path,
|
|
102
|
+
summary: `File: ${file.relativePath}`,
|
|
103
|
+
relevance: score
|
|
104
|
+
};
|
|
105
|
+
entries.push(entry);
|
|
106
|
+
totalTokens += estimateTokens(entry.summary ?? "");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const summary = this.buildSummary(entries);
|
|
110
|
+
return {
|
|
111
|
+
entries,
|
|
112
|
+
summary,
|
|
113
|
+
totalTokensEstimate: totalTokens + estimateTokens(summary)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Build a text summary of the context entries
|
|
118
|
+
*/
|
|
119
|
+
buildSummary(entries) {
|
|
120
|
+
if (entries.length === 0) return this.context.getContextSummary();
|
|
121
|
+
const parts = [];
|
|
122
|
+
const workspaceSummary = this.context.getSummary();
|
|
123
|
+
parts.push(`Workspace: ${workspaceSummary.name}`);
|
|
124
|
+
parts.push("");
|
|
125
|
+
const specs = entries.filter((e) => e.type === "spec");
|
|
126
|
+
if (specs.length > 0) {
|
|
127
|
+
parts.push("### Relevant Specs");
|
|
128
|
+
for (const entry of specs) parts.push(`- ${entry.summary}`);
|
|
129
|
+
parts.push("");
|
|
130
|
+
}
|
|
131
|
+
const files = entries.filter((e) => e.type === "file");
|
|
132
|
+
if (files.length > 0) {
|
|
133
|
+
parts.push("### Relevant Files");
|
|
134
|
+
for (const entry of files) parts.push(`- ${entry.summary}`);
|
|
135
|
+
}
|
|
136
|
+
return parts.join("\n");
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Create a context builder
|
|
141
|
+
*/
|
|
142
|
+
function createContextBuilder(context) {
|
|
143
|
+
return new ContextBuilder(context);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
//#endregion
|
|
147
|
+
export { ContextBuilder, createContextBuilder };
|
|
148
|
+
//# sourceMappingURL=context-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-builder.js","names":["entries: ContextEntry[]","entry: ContextEntry","parts: string[]"],"sources":["../../src/context/context-builder.ts"],"sourcesContent":["/**\n * Context builder for LLM prompts\n *\n * Builds rich context from workspace information for AI assistance.\n */\nimport type { WorkspaceContext, SpecInfo, FileInfo } from './workspace-context';\n\n/**\n * Context entry for a file or spec\n */\nexport interface ContextEntry {\n type: 'spec' | 'file' | 'reference';\n path: string;\n content?: string;\n summary?: string;\n relevance: number; // 0-1 score\n}\n\n/**\n * Built context for LLM\n */\nexport interface BuiltContext {\n entries: ContextEntry[];\n summary: string;\n totalTokensEstimate: number;\n}\n\n/**\n * Options for building context\n */\nexport interface ContextBuilderOptions {\n /** Maximum estimated tokens for context */\n maxTokens?: number;\n /** Query to use for relevance scoring */\n query?: string;\n /** Specific files to include */\n includeFiles?: string[];\n /** Specific specs to include */\n includeSpecs?: string[];\n}\n\n/**\n * Estimates token count from string (rough approximation)\n */\nfunction estimateTokens(text: string): number {\n // Rough estimate: ~4 characters per token\n return Math.ceil(text.length / 4);\n}\n\n/**\n * Calculate relevance score for a spec\n */\nfunction scoreSpec(spec: SpecInfo, query?: string): number {\n if (!query) return 0.5;\n\n const lowerQuery = query.toLowerCase();\n let score = 0;\n\n // Name match\n if (spec.name.toLowerCase().includes(lowerQuery)) {\n score += 0.4;\n }\n\n // Description match\n if (spec.description?.toLowerCase().includes(lowerQuery)) {\n score += 0.3;\n }\n\n // Tag match\n if (spec.tags?.some((t) => t.toLowerCase().includes(lowerQuery))) {\n score += 0.2;\n }\n\n return Math.min(score, 1);\n}\n\n/**\n * Calculate relevance score for a file\n */\nfunction scoreFile(file: FileInfo, query?: string): number {\n if (!query) return 0.5;\n\n const lowerQuery = query.toLowerCase();\n let score = 0;\n\n // Path match\n if (file.path.toLowerCase().includes(lowerQuery)) {\n score += 0.5;\n }\n\n // Name match\n if (file.name.toLowerCase().includes(lowerQuery)) {\n score += 0.3;\n }\n\n // Spec file bonus\n if (file.isSpec) {\n score += 0.2;\n }\n\n return Math.min(score, 1);\n}\n\n/**\n * Context builder for creating rich LLM context\n */\nexport class ContextBuilder {\n private readonly context: WorkspaceContext;\n\n constructor(context: WorkspaceContext) {\n this.context = context;\n }\n\n /**\n * Build context for a chat message\n */\n build(options: ContextBuilderOptions = {}): BuiltContext {\n const maxTokens = options.maxTokens ?? 4000;\n const entries: ContextEntry[] = [];\n let totalTokens = 0;\n\n // Add explicitly included specs\n if (options.includeSpecs?.length) {\n for (const specName of options.includeSpecs) {\n const spec = this.context.getSpecs().find((s) => s.name === specName);\n if (spec) {\n const entry: ContextEntry = {\n type: 'spec',\n path: spec.path,\n summary: `${spec.type}: ${spec.name}${spec.description ? ` - ${spec.description}` : ''}`,\n relevance: 1,\n };\n entries.push(entry);\n totalTokens += estimateTokens(entry.summary ?? '');\n }\n }\n }\n\n // Add explicitly included files\n if (options.includeFiles?.length) {\n for (const filePath of options.includeFiles) {\n const file = this.context.getFiles().find((f) => f.path === filePath);\n if (file) {\n const entry: ContextEntry = {\n type: 'file',\n path: file.path,\n summary: `File: ${file.relativePath}`,\n relevance: 1,\n };\n entries.push(entry);\n totalTokens += estimateTokens(entry.summary ?? '');\n }\n }\n }\n\n // Add relevant specs based on query\n if (options.query) {\n const scoredSpecs = this.context\n .getSpecs()\n .map((spec) => ({ spec, score: scoreSpec(spec, options.query) }))\n .filter(({ score }) => score > 0.2)\n .sort((a, b) => b.score - a.score);\n\n for (const { spec, score } of scoredSpecs) {\n if (totalTokens >= maxTokens) break;\n if (entries.some((e) => e.path === spec.path)) continue;\n\n const entry: ContextEntry = {\n type: 'spec',\n path: spec.path,\n summary: `${spec.type}: ${spec.name}${spec.description ? ` - ${spec.description}` : ''}`,\n relevance: score,\n };\n entries.push(entry);\n totalTokens += estimateTokens(entry.summary ?? '');\n }\n }\n\n // Add relevant files based on query\n if (options.query) {\n const scoredFiles = this.context\n .getFiles()\n .map((file) => ({ file, score: scoreFile(file, options.query) }))\n .filter(({ score }) => score > 0.2)\n .sort((a, b) => b.score - a.score);\n\n for (const { file, score } of scoredFiles) {\n if (totalTokens >= maxTokens) break;\n if (entries.some((e) => e.path === file.path)) continue;\n\n const entry: ContextEntry = {\n type: 'file',\n path: file.path,\n summary: `File: ${file.relativePath}`,\n relevance: score,\n };\n entries.push(entry);\n totalTokens += estimateTokens(entry.summary ?? '');\n }\n }\n\n // Build summary\n const summary = this.buildSummary(entries);\n\n return {\n entries,\n summary,\n totalTokensEstimate: totalTokens + estimateTokens(summary),\n };\n }\n\n /**\n * Build a text summary of the context entries\n */\n private buildSummary(entries: ContextEntry[]): string {\n if (entries.length === 0) {\n return this.context.getContextSummary();\n }\n\n const parts: string[] = [];\n\n // Workspace info\n const workspaceSummary = this.context.getSummary();\n parts.push(`Workspace: ${workspaceSummary.name}`);\n parts.push('');\n\n // Relevant specs\n const specs = entries.filter((e) => e.type === 'spec');\n if (specs.length > 0) {\n parts.push('### Relevant Specs');\n for (const entry of specs) {\n parts.push(`- ${entry.summary}`);\n }\n parts.push('');\n }\n\n // Relevant files\n const files = entries.filter((e) => e.type === 'file');\n if (files.length > 0) {\n parts.push('### Relevant Files');\n for (const entry of files) {\n parts.push(`- ${entry.summary}`);\n }\n }\n\n return parts.join('\\n');\n }\n}\n\n/**\n * Create a context builder\n */\nexport function createContextBuilder(\n context: WorkspaceContext\n): ContextBuilder {\n return new ContextBuilder(context);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
//#region src/context/file-operations.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* File operations for workspace context
|
|
4
|
+
*
|
|
5
|
+
* Provides read/write operations for files in the workspace.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Result of a file read operation
|
|
9
|
+
*/
|
|
10
|
+
interface FileReadResult {
|
|
11
|
+
success: boolean;
|
|
12
|
+
path: string;
|
|
13
|
+
content?: string;
|
|
14
|
+
error?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Result of a file write operation
|
|
18
|
+
*/
|
|
19
|
+
interface FileWriteResult {
|
|
20
|
+
success: boolean;
|
|
21
|
+
path: string;
|
|
22
|
+
error?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* File operation to perform
|
|
26
|
+
*/
|
|
27
|
+
interface FileOperation {
|
|
28
|
+
type: 'read' | 'write' | 'create' | 'delete';
|
|
29
|
+
path: string;
|
|
30
|
+
content?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Result of a file operation
|
|
34
|
+
*/
|
|
35
|
+
interface FileOperationResult {
|
|
36
|
+
operation: FileOperation;
|
|
37
|
+
success: boolean;
|
|
38
|
+
content?: string;
|
|
39
|
+
error?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Interface for file system operations
|
|
43
|
+
*/
|
|
44
|
+
interface FileSystem {
|
|
45
|
+
/**
|
|
46
|
+
* Read a file's contents
|
|
47
|
+
*/
|
|
48
|
+
readFile(path: string): Promise<string>;
|
|
49
|
+
/**
|
|
50
|
+
* Write content to a file
|
|
51
|
+
*/
|
|
52
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Check if a file exists
|
|
55
|
+
*/
|
|
56
|
+
exists(path: string): Promise<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* Delete a file
|
|
59
|
+
*/
|
|
60
|
+
deleteFile(path: string): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* List files in a directory
|
|
63
|
+
*/
|
|
64
|
+
listFiles(directory: string, options?: {
|
|
65
|
+
recursive?: boolean;
|
|
66
|
+
pattern?: string;
|
|
67
|
+
}): Promise<string[]>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* File operations executor
|
|
71
|
+
*/
|
|
72
|
+
declare class FileOperations {
|
|
73
|
+
private readonly fs;
|
|
74
|
+
private readonly workspacePath;
|
|
75
|
+
private readonly allowWrites;
|
|
76
|
+
constructor(fs: FileSystem, workspacePath: string, allowWrites?: boolean);
|
|
77
|
+
/**
|
|
78
|
+
* Read a file
|
|
79
|
+
*/
|
|
80
|
+
read(relativePath: string): Promise<FileReadResult>;
|
|
81
|
+
/**
|
|
82
|
+
* Write to a file
|
|
83
|
+
*/
|
|
84
|
+
write(relativePath: string, content: string): Promise<FileWriteResult>;
|
|
85
|
+
/**
|
|
86
|
+
* Execute multiple file operations
|
|
87
|
+
*/
|
|
88
|
+
execute(operations: FileOperation[]): Promise<FileOperationResult[]>;
|
|
89
|
+
/**
|
|
90
|
+
* Resolve a relative path to an absolute path
|
|
91
|
+
*/
|
|
92
|
+
private resolvePath;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Create a file operations instance with Node.js fs
|
|
96
|
+
*/
|
|
97
|
+
declare function createNodeFileOperations(workspacePath: string, allowWrites?: boolean): FileOperations;
|
|
98
|
+
//#endregion
|
|
99
|
+
export { FileOperation, FileOperationResult, FileOperations, FileReadResult, FileSystem, FileWriteResult, createNodeFileOperations };
|
|
100
|
+
//# sourceMappingURL=file-operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-operations.d.ts","names":[],"sources":["../../src/context/file-operations.ts"],"sourcesContent":[],"mappings":";;AASA;AAUA;AASA;AASA;AAUA;;;AAcwB,UApDP,cAAA,CAoDO;EAKI,OAAA,EAAA,OAAA;EAQvB,IAAA,EAAA,MAAA;EAAO,OAAA,CAAA,EAAA,MAAA;EAMC,KAAA,CAAA,EAAA,MAAA;;;;;AA4ByC,UAzFrC,eAAA,CAyFqC;EA0B1B,OAAA,EAAA,OAAA;EAA0B,IAAA,EAAA,MAAA;EAAR,KAAA,CAAA,EAAA,MAAA;;AAyF9C;;;UAnMiB,aAAA;;;;;;;;UASA,mBAAA;aACJ;;;;;;;;UASI,UAAA;;;;0BAIS;;;;4CAKkB;;;;wBAKpB;;;;4BAKI;;;;;;;MAQvB;;;;;cAMQ,cAAA;;;;kBAEY;;;;8BAQW,QAAQ;;;;gDAkBU,QAAQ;;;;sBA0BlC,kBAAkB,QAAQ;;;;;;;;;iBAyFtC,wBAAA,gDAGb"}
|
|
@@ -1 +1,175 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/context/file-operations.ts
|
|
2
|
+
/**
|
|
3
|
+
* File operations executor
|
|
4
|
+
*/
|
|
5
|
+
var FileOperations = class {
|
|
6
|
+
constructor(fs, workspacePath, allowWrites = false) {
|
|
7
|
+
this.fs = fs;
|
|
8
|
+
this.workspacePath = workspacePath;
|
|
9
|
+
this.allowWrites = allowWrites;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Read a file
|
|
13
|
+
*/
|
|
14
|
+
async read(relativePath) {
|
|
15
|
+
const fullPath = this.resolvePath(relativePath);
|
|
16
|
+
try {
|
|
17
|
+
return {
|
|
18
|
+
success: true,
|
|
19
|
+
path: relativePath,
|
|
20
|
+
content: await this.fs.readFile(fullPath)
|
|
21
|
+
};
|
|
22
|
+
} catch (error) {
|
|
23
|
+
return {
|
|
24
|
+
success: false,
|
|
25
|
+
path: relativePath,
|
|
26
|
+
error: error instanceof Error ? error.message : String(error)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Write to a file
|
|
32
|
+
*/
|
|
33
|
+
async write(relativePath, content) {
|
|
34
|
+
if (!this.allowWrites) return {
|
|
35
|
+
success: false,
|
|
36
|
+
path: relativePath,
|
|
37
|
+
error: "File writes are not enabled"
|
|
38
|
+
};
|
|
39
|
+
const fullPath = this.resolvePath(relativePath);
|
|
40
|
+
try {
|
|
41
|
+
await this.fs.writeFile(fullPath, content);
|
|
42
|
+
return {
|
|
43
|
+
success: true,
|
|
44
|
+
path: relativePath
|
|
45
|
+
};
|
|
46
|
+
} catch (error) {
|
|
47
|
+
return {
|
|
48
|
+
success: false,
|
|
49
|
+
path: relativePath,
|
|
50
|
+
error: error instanceof Error ? error.message : String(error)
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Execute multiple file operations
|
|
56
|
+
*/
|
|
57
|
+
async execute(operations) {
|
|
58
|
+
const results = [];
|
|
59
|
+
for (const operation of operations) {
|
|
60
|
+
let result;
|
|
61
|
+
switch (operation.type) {
|
|
62
|
+
case "read": {
|
|
63
|
+
const readResult = await this.read(operation.path);
|
|
64
|
+
result = {
|
|
65
|
+
operation,
|
|
66
|
+
success: readResult.success,
|
|
67
|
+
content: readResult.content,
|
|
68
|
+
error: readResult.error
|
|
69
|
+
};
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
case "write":
|
|
73
|
+
case "create":
|
|
74
|
+
if (!operation.content) result = {
|
|
75
|
+
operation,
|
|
76
|
+
success: false,
|
|
77
|
+
error: "Content is required for write operations"
|
|
78
|
+
};
|
|
79
|
+
else {
|
|
80
|
+
const writeResult = await this.write(operation.path, operation.content);
|
|
81
|
+
result = {
|
|
82
|
+
operation,
|
|
83
|
+
success: writeResult.success,
|
|
84
|
+
error: writeResult.error
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
break;
|
|
88
|
+
case "delete":
|
|
89
|
+
if (!this.allowWrites) result = {
|
|
90
|
+
operation,
|
|
91
|
+
success: false,
|
|
92
|
+
error: "File writes are not enabled"
|
|
93
|
+
};
|
|
94
|
+
else try {
|
|
95
|
+
await this.fs.deleteFile(this.resolvePath(operation.path));
|
|
96
|
+
result = {
|
|
97
|
+
operation,
|
|
98
|
+
success: true
|
|
99
|
+
};
|
|
100
|
+
} catch (error) {
|
|
101
|
+
result = {
|
|
102
|
+
operation,
|
|
103
|
+
success: false,
|
|
104
|
+
error: error instanceof Error ? error.message : String(error)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
default: result = {
|
|
109
|
+
operation,
|
|
110
|
+
success: false,
|
|
111
|
+
error: `Unknown operation type: ${operation.type}`
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
results.push(result);
|
|
115
|
+
}
|
|
116
|
+
return results;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Resolve a relative path to an absolute path
|
|
120
|
+
*/
|
|
121
|
+
resolvePath(relativePath) {
|
|
122
|
+
const normalized = relativePath.replace(/\.\./g, "").replace(/^\//, "");
|
|
123
|
+
return `${this.workspacePath}/${normalized}`;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Create a file operations instance with Node.js fs
|
|
128
|
+
*/
|
|
129
|
+
function createNodeFileOperations(workspacePath, allowWrites = false) {
|
|
130
|
+
return new FileOperations({
|
|
131
|
+
async readFile(path) {
|
|
132
|
+
const { readFile } = await import("node:fs/promises");
|
|
133
|
+
return readFile(path, "utf-8");
|
|
134
|
+
},
|
|
135
|
+
async writeFile(path, content) {
|
|
136
|
+
const { writeFile, mkdir } = await import("node:fs/promises");
|
|
137
|
+
const { dirname } = await import("node:path");
|
|
138
|
+
await mkdir(dirname(path), { recursive: true });
|
|
139
|
+
await writeFile(path, content, "utf-8");
|
|
140
|
+
},
|
|
141
|
+
async exists(path) {
|
|
142
|
+
const { access } = await import("node:fs/promises");
|
|
143
|
+
try {
|
|
144
|
+
await access(path);
|
|
145
|
+
return true;
|
|
146
|
+
} catch {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
async deleteFile(path) {
|
|
151
|
+
const { unlink } = await import("node:fs/promises");
|
|
152
|
+
await unlink(path);
|
|
153
|
+
},
|
|
154
|
+
async listFiles(directory, options) {
|
|
155
|
+
const { readdir } = await import("node:fs/promises");
|
|
156
|
+
const { join } = await import("node:path");
|
|
157
|
+
const files = [];
|
|
158
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
159
|
+
for (const entry of entries) {
|
|
160
|
+
const fullPath = join(directory, entry.name);
|
|
161
|
+
if (entry.isDirectory() && options?.recursive) {
|
|
162
|
+
const subFiles = await this.listFiles(fullPath, options);
|
|
163
|
+
files.push(...subFiles);
|
|
164
|
+
} else if (entry.isFile()) {
|
|
165
|
+
if (!options?.pattern || entry.name.match(new RegExp(options.pattern))) files.push(fullPath);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return files;
|
|
169
|
+
}
|
|
170
|
+
}, workspacePath, allowWrites);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
//#endregion
|
|
174
|
+
export { FileOperations, createNodeFileOperations };
|
|
175
|
+
//# sourceMappingURL=file-operations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-operations.js","names":["fs: FileSystem","workspacePath: string","results: FileOperationResult[]","result: FileOperationResult","files: string[]"],"sources":["../../src/context/file-operations.ts"],"sourcesContent":["/**\n * File operations for workspace context\n *\n * Provides read/write operations for files in the workspace.\n */\n\n/**\n * Result of a file read operation\n */\nexport interface FileReadResult {\n success: boolean;\n path: string;\n content?: string;\n error?: string;\n}\n\n/**\n * Result of a file write operation\n */\nexport interface FileWriteResult {\n success: boolean;\n path: string;\n error?: string;\n}\n\n/**\n * File operation to perform\n */\nexport interface FileOperation {\n type: 'read' | 'write' | 'create' | 'delete';\n path: string;\n content?: string;\n}\n\n/**\n * Result of a file operation\n */\nexport interface FileOperationResult {\n operation: FileOperation;\n success: boolean;\n content?: string;\n error?: string;\n}\n\n/**\n * Interface for file system operations\n */\nexport interface FileSystem {\n /**\n * Read a file's contents\n */\n readFile(path: string): Promise<string>;\n\n /**\n * Write content to a file\n */\n writeFile(path: string, content: string): Promise<void>;\n\n /**\n * Check if a file exists\n */\n exists(path: string): Promise<boolean>;\n\n /**\n * Delete a file\n */\n deleteFile(path: string): Promise<void>;\n\n /**\n * List files in a directory\n */\n listFiles(\n directory: string,\n options?: { recursive?: boolean; pattern?: string }\n ): Promise<string[]>;\n}\n\n/**\n * File operations executor\n */\nexport class FileOperations {\n constructor(\n private readonly fs: FileSystem,\n private readonly workspacePath: string,\n private readonly allowWrites = false\n ) {}\n\n /**\n * Read a file\n */\n async read(relativePath: string): Promise<FileReadResult> {\n const fullPath = this.resolvePath(relativePath);\n\n try {\n const content = await this.fs.readFile(fullPath);\n return { success: true, path: relativePath, content };\n } catch (error) {\n return {\n success: false,\n path: relativePath,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n /**\n * Write to a file\n */\n async write(relativePath: string, content: string): Promise<FileWriteResult> {\n if (!this.allowWrites) {\n return {\n success: false,\n path: relativePath,\n error: 'File writes are not enabled',\n };\n }\n\n const fullPath = this.resolvePath(relativePath);\n\n try {\n await this.fs.writeFile(fullPath, content);\n return { success: true, path: relativePath };\n } catch (error) {\n return {\n success: false,\n path: relativePath,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n /**\n * Execute multiple file operations\n */\n async execute(operations: FileOperation[]): Promise<FileOperationResult[]> {\n const results: FileOperationResult[] = [];\n\n for (const operation of operations) {\n let result: FileOperationResult;\n\n switch (operation.type) {\n case 'read': {\n const readResult = await this.read(operation.path);\n result = {\n operation,\n success: readResult.success,\n content: readResult.content,\n error: readResult.error,\n };\n break;\n }\n\n case 'write':\n case 'create': {\n if (!operation.content) {\n result = {\n operation,\n success: false,\n error: 'Content is required for write operations',\n };\n } else {\n const writeResult = await this.write(\n operation.path,\n operation.content\n );\n result = {\n operation,\n success: writeResult.success,\n error: writeResult.error,\n };\n }\n break;\n }\n\n case 'delete': {\n if (!this.allowWrites) {\n result = {\n operation,\n success: false,\n error: 'File writes are not enabled',\n };\n } else {\n try {\n await this.fs.deleteFile(this.resolvePath(operation.path));\n result = { operation, success: true };\n } catch (error) {\n result = {\n operation,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n break;\n }\n\n default:\n result = {\n operation,\n success: false,\n error: `Unknown operation type: ${(operation as FileOperation).type}`,\n };\n }\n\n results.push(result);\n }\n\n return results;\n }\n\n /**\n * Resolve a relative path to an absolute path\n */\n private resolvePath(relativePath: string): string {\n // Prevent path traversal\n const normalized = relativePath.replace(/\\.\\./g, '').replace(/^\\//, '');\n return `${this.workspacePath}/${normalized}`;\n }\n}\n\n/**\n * Create a file operations instance with Node.js fs\n */\nexport function createNodeFileOperations(\n workspacePath: string,\n allowWrites = false\n): FileOperations {\n // Dynamic import to avoid issues in browser environments\n const fs: FileSystem = {\n async readFile(path: string): Promise<string> {\n const { readFile } = await import('node:fs/promises');\n return readFile(path, 'utf-8');\n },\n async writeFile(path: string, content: string): Promise<void> {\n const { writeFile, mkdir } = await import('node:fs/promises');\n const { dirname } = await import('node:path');\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, content, 'utf-8');\n },\n async exists(path: string): Promise<boolean> {\n const { access } = await import('node:fs/promises');\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n },\n async deleteFile(path: string): Promise<void> {\n const { unlink } = await import('node:fs/promises');\n await unlink(path);\n },\n async listFiles(\n directory: string,\n options?: { recursive?: boolean; pattern?: string }\n ): Promise<string[]> {\n const { readdir } = await import('node:fs/promises');\n const { join } = await import('node:path');\n\n const files: string[] = [];\n const entries = await readdir(directory, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(directory, entry.name);\n if (entry.isDirectory() && options?.recursive) {\n const subFiles = await this.listFiles(fullPath, options);\n files.push(...subFiles);\n } else if (entry.isFile()) {\n if (\n !options?.pattern ||\n entry.name.match(new RegExp(options.pattern))\n ) {\n files.push(fullPath);\n }\n }\n }\n\n return files;\n },\n };\n\n return new FileOperations(fs, workspacePath, allowWrites);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { FileInfo, SpecInfo, WorkspaceContext, WorkspaceContextConfig, WorkspaceSummary, createWorkspaceContext } from "./workspace-context.js";
|
|
2
|
+
import { BuiltContext, ContextBuilder, ContextBuilderOptions, ContextEntry, createContextBuilder } from "./context-builder.js";
|
|
3
|
+
import { FileOperation, FileOperationResult, FileOperations, FileReadResult, FileSystem, FileWriteResult, createNodeFileOperations } from "./file-operations.js";
|
|
4
|
+
export { BuiltContext, ContextBuilder, ContextBuilderOptions, ContextEntry, FileInfo, FileOperation, FileOperationResult, FileOperations, FileReadResult, FileSystem, FileWriteResult, SpecInfo, WorkspaceContext, WorkspaceContextConfig, WorkspaceSummary, createContextBuilder, createNodeFileOperations, createWorkspaceContext };
|
package/dist/context/index.js
CHANGED
|
@@ -1 +1,5 @@
|
|
|
1
|
-
import{WorkspaceContext
|
|
1
|
+
import { WorkspaceContext, createWorkspaceContext } from "./workspace-context.js";
|
|
2
|
+
import { ContextBuilder, createContextBuilder } from "./context-builder.js";
|
|
3
|
+
import { FileOperations, createNodeFileOperations } from "./file-operations.js";
|
|
4
|
+
|
|
5
|
+
export { ContextBuilder, FileOperations, WorkspaceContext, createContextBuilder, createNodeFileOperations, createWorkspaceContext };
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
//#region src/context/workspace-context.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Workspace context management
|
|
4
|
+
*
|
|
5
|
+
* Provides access to specs, files, and codebase information
|
|
6
|
+
* for context-aware AI chat assistance.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Spec information for context
|
|
10
|
+
*/
|
|
11
|
+
interface SpecInfo {
|
|
12
|
+
name: string;
|
|
13
|
+
version: number;
|
|
14
|
+
type: 'command' | 'query' | 'event' | 'presentation';
|
|
15
|
+
path: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
tags?: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* File information for context
|
|
21
|
+
*/
|
|
22
|
+
interface FileInfo {
|
|
23
|
+
path: string;
|
|
24
|
+
relativePath: string;
|
|
25
|
+
name: string;
|
|
26
|
+
extension: string;
|
|
27
|
+
size: number;
|
|
28
|
+
isSpec: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Workspace summary for context
|
|
32
|
+
*/
|
|
33
|
+
interface WorkspaceSummary {
|
|
34
|
+
name: string;
|
|
35
|
+
path: string;
|
|
36
|
+
specs: {
|
|
37
|
+
total: number;
|
|
38
|
+
commands: number;
|
|
39
|
+
queries: number;
|
|
40
|
+
events: number;
|
|
41
|
+
presentations: number;
|
|
42
|
+
};
|
|
43
|
+
files: {
|
|
44
|
+
total: number;
|
|
45
|
+
typescript: number;
|
|
46
|
+
specFiles: number;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Configuration for workspace context
|
|
51
|
+
*/
|
|
52
|
+
interface WorkspaceContextConfig {
|
|
53
|
+
/** Root path of the workspace */
|
|
54
|
+
workspacePath: string;
|
|
55
|
+
/** File patterns to include */
|
|
56
|
+
includePatterns?: string[];
|
|
57
|
+
/** File patterns to exclude */
|
|
58
|
+
excludePatterns?: string[];
|
|
59
|
+
/** Maximum file size to read (bytes) */
|
|
60
|
+
maxFileSize?: number;
|
|
61
|
+
/** Whether to enable file writes */
|
|
62
|
+
allowWrites?: boolean;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Workspace context for AI chat
|
|
66
|
+
*/
|
|
67
|
+
declare class WorkspaceContext {
|
|
68
|
+
readonly workspacePath: string;
|
|
69
|
+
readonly allowWrites: boolean;
|
|
70
|
+
private specs;
|
|
71
|
+
private files;
|
|
72
|
+
private initialized;
|
|
73
|
+
constructor(config: WorkspaceContextConfig);
|
|
74
|
+
/**
|
|
75
|
+
* Initialize the workspace context by scanning files
|
|
76
|
+
*/
|
|
77
|
+
initialize(): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Get all discovered specs
|
|
80
|
+
*/
|
|
81
|
+
getSpecs(): SpecInfo[];
|
|
82
|
+
/**
|
|
83
|
+
* Get all discovered files
|
|
84
|
+
*/
|
|
85
|
+
getFiles(): FileInfo[];
|
|
86
|
+
/**
|
|
87
|
+
* Add specs to the context
|
|
88
|
+
*/
|
|
89
|
+
addSpecs(specs: SpecInfo[]): void;
|
|
90
|
+
/**
|
|
91
|
+
* Add files to the context
|
|
92
|
+
*/
|
|
93
|
+
addFiles(files: FileInfo[]): void;
|
|
94
|
+
/**
|
|
95
|
+
* Get a summary of the workspace for context
|
|
96
|
+
*/
|
|
97
|
+
getSummary(): WorkspaceSummary;
|
|
98
|
+
/**
|
|
99
|
+
* Get a context summary for LLM prompts
|
|
100
|
+
*/
|
|
101
|
+
getContextSummary(): string;
|
|
102
|
+
/**
|
|
103
|
+
* Find specs matching a query
|
|
104
|
+
*/
|
|
105
|
+
findSpecs(query: string): SpecInfo[];
|
|
106
|
+
/**
|
|
107
|
+
* Find files matching a query
|
|
108
|
+
*/
|
|
109
|
+
findFiles(query: string): FileInfo[];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Create a workspace context from a path
|
|
113
|
+
*/
|
|
114
|
+
declare function createWorkspaceContext(path: string, options?: Partial<WorkspaceContextConfig>): Promise<WorkspaceContext>;
|
|
115
|
+
//#endregion
|
|
116
|
+
export { FileInfo, SpecInfo, WorkspaceContext, WorkspaceContextConfig, WorkspaceSummary, createWorkspaceContext };
|
|
117
|
+
//# sourceMappingURL=workspace-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-context.d.ts","names":[],"sources":["../../src/context/workspace-context.ts"],"sourcesContent":[],"mappings":";;AAUA;AAYA;AAYA;AAoBA;AAgBA;;;;AAkCc,UA9FG,QAAA,CA8FH;EAOI,IAAA,EAAA,MAAA;EAOA,OAAA,EAAA,MAAA;EAOF,IAAA,EAAA,SAAA,GAAA,OAAA,GAAA,OAAA,GAAA,cAAA;EA8DY,IAAA,EAAA,MAAA;EAaA,WAAA,CAAA,EAAA,MAAA;EAAQ,IAAA,CAAA,EAAA,MAAA,EAAA;AAapC;;;;AAGG,UAlMc,QAAA,CAkMd;EAAO,IAAA,EAAA,MAAA;;;;;;;;;;UAtLO,gBAAA;;;;;;;;;;;;;;;;;;;UAoBA,sBAAA;;;;;;;;;;;;;;;cAgBJ,gBAAA;;;;;;sBAQS;;;;gBAQA;;;;cAWR;;;;cAOA;;;;kBAOI;;;;kBAOA;;;;gBAOF;;;;;;;;4BA8DY;;;;4BAaA;;;;;iBAaN,sBAAA,yBAEV,QAAQ,0BACjB,QAAQ"}
|