@nanocollective/nanocoder 1.14.3 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -1
- package/dist/ai-sdk-client.d.ts +22 -0
- package/dist/ai-sdk-client.d.ts.map +1 -0
- package/dist/ai-sdk-client.js +385 -0
- package/dist/ai-sdk-client.js.map +1 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +1 -1
- package/dist/app.js.map +1 -1
- package/dist/client-factory.d.ts.map +1 -1
- package/dist/client-factory.js +5 -5
- package/dist/client-factory.js.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/recommendations.js +1 -1
- package/dist/commands/recommendations.js.map +1 -1
- package/dist/commands/streaming.d.ts +3 -0
- package/dist/commands/streaming.d.ts.map +1 -0
- package/dist/commands/streaming.js +23 -0
- package/dist/commands/streaming.js.map +1 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +17 -3
- package/dist/commands.js.map +1 -1
- package/dist/components/assistant-message.d.ts +0 -1
- package/dist/components/assistant-message.d.ts.map +1 -1
- package/dist/components/assistant-message.js +70 -122
- package/dist/components/assistant-message.js.map +1 -1
- package/dist/components/thinking-indicator.js +1 -1
- package/dist/components/thinking-indicator.js.map +1 -1
- package/dist/components/user-input.d.ts.map +1 -1
- package/dist/components/user-input.js +135 -27
- package/dist/components/user-input.js.map +1 -1
- package/dist/components/user-message.d.ts.map +1 -1
- package/dist/components/user-message.js +34 -1
- package/dist/components/user-message.js.map +1 -1
- package/dist/config/preferences.d.ts +2 -0
- package/dist/config/preferences.d.ts.map +1 -1
- package/dist/config/preferences.js +10 -0
- package/dist/config/preferences.js.map +1 -1
- package/dist/hooks/useAppInitialization.d.ts.map +1 -1
- package/dist/hooks/useAppInitialization.js +2 -1
- package/dist/hooks/useAppInitialization.js.map +1 -1
- package/dist/hooks/useChatHandler.d.ts +2 -0
- package/dist/hooks/useChatHandler.d.ts.map +1 -1
- package/dist/hooks/useChatHandler.js +59 -9
- package/dist/hooks/useChatHandler.js.map +1 -1
- package/dist/mcp/mcp-client.d.ts +20 -1
- package/dist/mcp/mcp-client.d.ts.map +1 -1
- package/dist/mcp/mcp-client.js +57 -0
- package/dist/mcp/mcp-client.js.map +1 -1
- package/dist/message-handler.d.ts.map +1 -1
- package/dist/message-handler.js +7 -2
- package/dist/message-handler.js.map +1 -1
- package/dist/tool-calling/index.d.ts +1 -1
- package/dist/tool-calling/index.d.ts.map +1 -1
- package/dist/tool-calling/index.js +1 -1
- package/dist/tool-calling/index.js.map +1 -1
- package/dist/tool-calling/json-parser.d.ts +19 -2
- package/dist/tool-calling/json-parser.d.ts.map +1 -1
- package/dist/tool-calling/json-parser.js +65 -28
- package/dist/tool-calling/json-parser.js.map +1 -1
- package/dist/tool-calling/json-parser.spec.d.ts +2 -0
- package/dist/tool-calling/json-parser.spec.d.ts.map +1 -0
- package/dist/tool-calling/json-parser.spec.js +518 -0
- package/dist/tool-calling/json-parser.spec.js.map +1 -0
- package/dist/tool-calling/tool-parser.d.ts +20 -0
- package/dist/tool-calling/tool-parser.d.ts.map +1 -0
- package/dist/tool-calling/tool-parser.js +58 -0
- package/dist/tool-calling/tool-parser.js.map +1 -0
- package/dist/tool-calling/tool-parser.spec.d.ts +2 -0
- package/dist/tool-calling/tool-parser.spec.d.ts.map +1 -0
- package/dist/tool-calling/tool-parser.spec.js +250 -0
- package/dist/tool-calling/tool-parser.spec.js.map +1 -0
- package/dist/tool-calling/xml-parser.d.ts +17 -0
- package/dist/tool-calling/xml-parser.d.ts.map +1 -1
- package/dist/tool-calling/xml-parser.js +101 -13
- package/dist/tool-calling/xml-parser.js.map +1 -1
- package/dist/tool-calling/xml-parser.spec.d.ts +2 -0
- package/dist/tool-calling/xml-parser.spec.d.ts.map +1 -0
- package/dist/tool-calling/xml-parser.spec.js +437 -0
- package/dist/tool-calling/xml-parser.spec.js.map +1 -0
- package/dist/tools/create-file.d.ts.map +1 -1
- package/dist/tools/create-file.js +26 -23
- package/dist/tools/create-file.js.map +1 -1
- package/dist/tools/delete-lines.d.ts.map +1 -1
- package/dist/tools/delete-lines.js +29 -27
- package/dist/tools/delete-lines.js.map +1 -1
- package/dist/tools/execute-bash.d.ts.map +1 -1
- package/dist/tools/execute-bash.js +21 -19
- package/dist/tools/execute-bash.js.map +1 -1
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +21 -19
- package/dist/tools/fetch-url.js.map +1 -1
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +8 -6
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/insert-lines.d.ts.map +1 -1
- package/dist/tools/insert-lines.js +29 -27
- package/dist/tools/insert-lines.js.map +1 -1
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +23 -19
- package/dist/tools/read-file.js.map +1 -1
- package/dist/tools/read-many-files.d.ts.map +1 -1
- package/dist/tools/read-many-files.js +24 -20
- package/dist/tools/read-many-files.js.map +1 -1
- package/dist/tools/replace-lines.d.ts.map +1 -1
- package/dist/tools/replace-lines.js +33 -31
- package/dist/tools/replace-lines.js.map +1 -1
- package/dist/tools/search-files.d.ts.map +1 -1
- package/dist/tools/search-files.js +33 -31
- package/dist/tools/search-files.js.map +1 -1
- package/dist/tools/tool-manager.d.ts +35 -19
- package/dist/tools/tool-manager.d.ts.map +1 -1
- package/dist/tools/tool-manager.js +63 -33
- package/dist/tools/tool-manager.js.map +1 -1
- package/dist/tools/tool-registry.d.ts +121 -0
- package/dist/tools/tool-registry.d.ts.map +1 -0
- package/dist/tools/tool-registry.js +195 -0
- package/dist/tools/tool-registry.js.map +1 -0
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +25 -23
- package/dist/tools/web-search.js.map +1 -1
- package/dist/types/config.d.ts +2 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/core.d.ts +58 -3
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/core.js +2 -0
- package/dist/types/core.js.map +1 -1
- package/dist/utils/file-autocomplete.d.ts +31 -0
- package/dist/utils/file-autocomplete.d.ts.map +1 -0
- package/dist/utils/file-autocomplete.js +156 -0
- package/dist/utils/file-autocomplete.js.map +1 -0
- package/dist/utils/file-autocomplete.spec.d.ts +2 -0
- package/dist/utils/file-autocomplete.spec.d.ts.map +1 -0
- package/dist/utils/file-autocomplete.spec.js +142 -0
- package/dist/utils/file-autocomplete.spec.js.map +1 -0
- package/dist/utils/file-content-loader.d.ts +31 -0
- package/dist/utils/file-content-loader.d.ts.map +1 -0
- package/dist/utils/file-content-loader.js +142 -0
- package/dist/utils/file-content-loader.js.map +1 -0
- package/dist/utils/file-content-loader.spec.d.ts +2 -0
- package/dist/utils/file-content-loader.spec.d.ts.map +1 -0
- package/dist/utils/file-content-loader.spec.js +140 -0
- package/dist/utils/file-content-loader.spec.js.map +1 -0
- package/dist/utils/file-mention-handler.d.ts +21 -0
- package/dist/utils/file-mention-handler.d.ts.map +1 -0
- package/dist/utils/file-mention-handler.js +59 -0
- package/dist/utils/file-mention-handler.js.map +1 -0
- package/dist/utils/file-mention-handler.spec.d.ts +2 -0
- package/dist/utils/file-mention-handler.spec.d.ts.map +1 -0
- package/dist/utils/file-mention-handler.spec.js +147 -0
- package/dist/utils/file-mention-handler.spec.js.map +1 -0
- package/dist/utils/file-mention-parser.d.ts +40 -0
- package/dist/utils/file-mention-parser.d.ts.map +1 -0
- package/dist/utils/file-mention-parser.js +122 -0
- package/dist/utils/file-mention-parser.js.map +1 -0
- package/dist/utils/file-mention-parser.spec.d.ts +2 -0
- package/dist/utils/file-mention-parser.spec.d.ts.map +1 -0
- package/dist/utils/file-mention-parser.spec.js +149 -0
- package/dist/utils/file-mention-parser.spec.js.map +1 -0
- package/dist/utils/fuzzy-matching.d.ts +13 -0
- package/dist/utils/fuzzy-matching.d.ts.map +1 -0
- package/dist/utils/fuzzy-matching.js +127 -0
- package/dist/utils/fuzzy-matching.js.map +1 -0
- package/dist/utils/fuzzy-matching.spec.d.ts +2 -0
- package/dist/utils/fuzzy-matching.spec.d.ts.map +1 -0
- package/dist/utils/fuzzy-matching.spec.js +123 -0
- package/dist/utils/fuzzy-matching.spec.js.map +1 -0
- package/dist/utils/prompt-assembly.spec.js +100 -2
- package/dist/utils/prompt-assembly.spec.js.map +1 -1
- package/dist/utils/prompt-processor.d.ts +2 -2
- package/dist/utils/prompt-processor.d.ts.map +1 -1
- package/dist/utils/prompt-processor.js +24 -41
- package/dist/utils/prompt-processor.js.map +1 -1
- package/package.json +7 -4
- package/dist/langgraph-client.d.ts +0 -19
- package/dist/langgraph-client.d.ts.map +0 -1
- package/dist/langgraph-client.js +0 -295
- package/dist/langgraph-client.js.map +0 -1
- package/dist/mcp/mcp-tool-adapter.d.ts +0 -22
- package/dist/mcp/mcp-tool-adapter.d.ts.map +0 -1
- package/dist/mcp/mcp-tool-adapter.js +0 -50
- package/dist/mcp/mcp-tool-adapter.js.map +0 -1
package/dist/types/core.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { tool, jsonSchema, type Tool as AISDKTool } from 'ai';
|
|
3
|
+
export { tool, jsonSchema };
|
|
4
|
+
export type AISDKCoreTool = AISDKTool<any, any>;
|
|
2
5
|
export interface Message {
|
|
3
6
|
role: 'user' | 'assistant' | 'system' | 'tool';
|
|
4
7
|
content: string;
|
|
@@ -37,9 +40,55 @@ export interface Tool {
|
|
|
37
40
|
};
|
|
38
41
|
}
|
|
39
42
|
export type ToolHandler = (input: any) => Promise<string>;
|
|
43
|
+
/**
|
|
44
|
+
* Tool formatter type for Ink UI
|
|
45
|
+
* Formats tool arguments and results for display in the CLI
|
|
46
|
+
*/
|
|
47
|
+
export type ToolFormatter = (args: any, result?: string) => string | Promise<string> | React.ReactElement | Promise<React.ReactElement>;
|
|
48
|
+
/**
|
|
49
|
+
* Tool validator type for pre-execution validation
|
|
50
|
+
* Returns validation result with optional error message
|
|
51
|
+
*/
|
|
52
|
+
export type ToolValidator = (args: any) => Promise<{
|
|
53
|
+
valid: true;
|
|
54
|
+
} | {
|
|
55
|
+
valid: false;
|
|
56
|
+
error: string;
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Unified tool entry interface
|
|
60
|
+
*
|
|
61
|
+
* Provides a structured way to manage all tool metadata in one place:
|
|
62
|
+
* - name: Tool name for registry and lookup
|
|
63
|
+
* - tool: Native AI SDK CoreTool (without execute for human-in-the-loop)
|
|
64
|
+
* - handler: Manual execution handler called after user confirmation
|
|
65
|
+
* - formatter: Optional React component for rich CLI UI display
|
|
66
|
+
* - validator: Optional pre-execution validation function
|
|
67
|
+
*/
|
|
68
|
+
export interface ToolEntry {
|
|
69
|
+
name: string;
|
|
70
|
+
tool: AISDKCoreTool;
|
|
71
|
+
handler: ToolHandler;
|
|
72
|
+
formatter?: ToolFormatter;
|
|
73
|
+
validator?: ToolValidator;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Nanocoder's extended tool definition
|
|
77
|
+
*
|
|
78
|
+
* Uses AI SDK's native CoreTool with Nanocoder-specific metadata:
|
|
79
|
+
* - name: Tool name (metadata for registry and lookup)
|
|
80
|
+
* - tool: Native AI SDK CoreTool (using tool() and jsonSchema()) WITHOUT execute function
|
|
81
|
+
* - handler: Manual execution function called after user confirmation (human-in-the-loop)
|
|
82
|
+
* - formatter: React component for rich UI display in terminal
|
|
83
|
+
* - validator: Optional pre-execution validation
|
|
84
|
+
* - requiresConfirmation: Whether to show confirmation UI (default: true)
|
|
85
|
+
*
|
|
86
|
+
* Note: We keep 'name' as metadata since AI SDK's Tool type doesn't expose it.
|
|
87
|
+
*/
|
|
40
88
|
export interface ToolDefinition {
|
|
89
|
+
name: string;
|
|
90
|
+
tool: AISDKCoreTool;
|
|
41
91
|
handler: ToolHandler;
|
|
42
|
-
config: Tool;
|
|
43
92
|
formatter?: (args: any, result?: string) => string | Promise<string> | React.ReactElement | Promise<React.ReactElement>;
|
|
44
93
|
requiresConfirmation?: boolean;
|
|
45
94
|
validator?: (args: any) => Promise<{
|
|
@@ -48,6 +97,7 @@ export interface ToolDefinition {
|
|
|
48
97
|
valid: false;
|
|
49
98
|
error: string;
|
|
50
99
|
}>;
|
|
100
|
+
config?: Tool;
|
|
51
101
|
}
|
|
52
102
|
interface LLMMessage {
|
|
53
103
|
role: 'assistant';
|
|
@@ -59,15 +109,20 @@ export interface LLMChatResponse {
|
|
|
59
109
|
message: LLMMessage;
|
|
60
110
|
}>;
|
|
61
111
|
}
|
|
112
|
+
export interface StreamCallbacks {
|
|
113
|
+
onToken?: (token: string) => void;
|
|
114
|
+
onToolCall?: (toolCall: ToolCall) => void;
|
|
115
|
+
onFinish?: () => void;
|
|
116
|
+
}
|
|
62
117
|
export interface LLMClient {
|
|
63
118
|
getCurrentModel(): string;
|
|
64
119
|
setModel(model: string): void;
|
|
65
120
|
getContextSize(): number;
|
|
66
121
|
getAvailableModels(): Promise<string[]>;
|
|
67
|
-
chat(messages: Message[], tools:
|
|
122
|
+
chat(messages: Message[], tools: Record<string, AISDKCoreTool>, signal?: AbortSignal): Promise<LLMChatResponse>;
|
|
123
|
+
chatStream?(messages: Message[], tools: Record<string, AISDKCoreTool>, callbacks: StreamCallbacks, signal?: AbortSignal): Promise<LLMChatResponse>;
|
|
68
124
|
clearContext(): Promise<void>;
|
|
69
125
|
}
|
|
70
126
|
export type DevelopmentMode = 'normal' | 'auto-accept' | 'plan';
|
|
71
127
|
export declare const DEVELOPMENT_MODE_LABELS: Record<DevelopmentMode, string>;
|
|
72
|
-
export {};
|
|
73
128
|
//# sourceMappingURL=core.d.ts.map
|
package/dist/types/core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../source/types/core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE;QACT,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,CAAC;CACF;AAED,MAAM,WAAW,UAAU;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,IAAI;IACpB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACT,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE;YACX,IAAI,EAAE,QAAQ,CAAC;YACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;YAChD,QAAQ,EAAE,MAAM,EAAE,CAAC;SACnB,CAAC;KACF,CAAC;CACF;AAID,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE1D,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../source/types/core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAC,IAAI,EAAE,UAAU,EAAE,KAAK,IAAI,IAAI,SAAS,EAAC,MAAM,IAAI,CAAC;AAE5D,OAAO,EAAC,IAAI,EAAE,UAAU,EAAC,CAAC;AAM1B,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAIhD,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE;QACT,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,CAAC;CACF;AAED,MAAM,WAAW,UAAU;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,IAAI;IACpB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACT,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE;YACX,IAAI,EAAE,QAAQ,CAAC;YACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;YAChD,QAAQ,EAAE,MAAM,EAAE,CAAC;SACnB,CAAC;KACF,CAAC;CACF;AAID,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE1D;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAE3B,IAAI,EAAE,GAAG,EACT,MAAM,CAAC,EAAE,MAAM,KAEb,MAAM,GACN,OAAO,CAAC,MAAM,CAAC,GACf,KAAK,CAAC,YAAY,GAClB,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;AAE/B;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAE3B,IAAI,EAAE,GAAG,KACL,OAAO,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAC,GAAG;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAAC,CAAC;AAE5D;;;;;;;;;GASG;AACH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,SAAS,CAAC,EAAE,aAAa,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,cAAc;IAE9B,IAAI,EAAE,MAAM,CAAC;IAEb,IAAI,EAAE,aAAa,CAAC;IAEpB,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,CAEX,IAAI,EAAE,GAAG,EACT,MAAM,CAAC,EAAE,MAAM,KAEb,MAAM,GACN,OAAO,CAAC,MAAM,CAAC,GACf,KAAK,CAAC,YAAY,GAClB,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC/B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,SAAS,CAAC,EAAE,CAEX,IAAI,EAAE,GAAG,KACL,OAAO,CAAC;QAAC,KAAK,EAAE,IAAI,CAAA;KAAC,GAAG;QAAC,KAAK,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IAE5D,MAAM,CAAC,EAAE,IAAI,CAAC;CACd;AAED,UAAU,UAAU;IACnB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,KAAK,CAAC;QACd,OAAO,EAAE,UAAU,CAAC;KACpB,CAAC,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC/B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACzB,eAAe,IAAI,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,IAAI,MAAM,CAAC;IACzB,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACxC,IAAI,CACH,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EACpC,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,eAAe,CAAC,CAAC;IAC5B,UAAU,CAAC,CACV,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EACpC,SAAS,EAAE,eAAe,EAC1B,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,eAAe,CAAC,CAAC;IAC5B,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,aAAa,GAAG,MAAM,CAAC;AAEhE,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAInE,CAAC"}
|
package/dist/types/core.js
CHANGED
package/dist/types/core.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../source/types/core.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../source/types/core.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,IAAI,EAAE,UAAU,EAAyB,MAAM,IAAI,CAAC;AAE5D,OAAO,EAAC,IAAI,EAAE,UAAU,EAAC,CAAC;AA8K1B,MAAM,CAAC,MAAM,uBAAuB,GAAoC;IACvE,MAAM,EAAE,kBAAkB;IAC1B,aAAa,EAAE,wBAAwB;IACvC,IAAI,EAAE,gBAAgB;CACtB,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
interface FileCompletion {
|
|
2
|
+
path: string;
|
|
3
|
+
displayPath: string;
|
|
4
|
+
score: number;
|
|
5
|
+
isDirectory: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Fuzzy match scoring algorithm for file paths
|
|
9
|
+
* Returns a score from 0 to 1000 (higher = better match)
|
|
10
|
+
* @deprecated Use fuzzyScoreFilePath from fuzzy-matching.ts instead
|
|
11
|
+
*/
|
|
12
|
+
export declare function fuzzyScore(filePath: string, query: string): number;
|
|
13
|
+
/**
|
|
14
|
+
* Extract the current @mention being typed at cursor position
|
|
15
|
+
* Returns the mention text and its position in the input
|
|
16
|
+
*/
|
|
17
|
+
export declare function getCurrentFileMention(input: string, cursorPosition?: number): {
|
|
18
|
+
mention: string;
|
|
19
|
+
startIndex: number;
|
|
20
|
+
endIndex: number;
|
|
21
|
+
} | null;
|
|
22
|
+
/**
|
|
23
|
+
* Get file completions for a partial path
|
|
24
|
+
*/
|
|
25
|
+
export declare function getFileCompletions(partialPath: string, cwd: string, maxResults?: number): Promise<FileCompletion[]>;
|
|
26
|
+
/**
|
|
27
|
+
* Clear the file list cache (useful for testing or when files change)
|
|
28
|
+
*/
|
|
29
|
+
export declare function clearFileListCache(): void;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=file-autocomplete.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-autocomplete.d.ts","sourceRoot":"","sources":["../../source/utils/file-autocomplete.ts"],"names":[],"mappings":"AASA,UAAU,cAAc;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;CACrB;AAqFD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,MAAM,GACrB;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,GAAG,IAAI,CA8ChE;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACvC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,EACX,UAAU,GAAE,MAAW,GACrB,OAAO,CAAC,cAAc,EAAE,CAAC,CAwB3B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { exec } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import ignore from 'ignore';
|
|
6
|
+
import { fuzzyScoreFilePath } from './fuzzy-matching.js';
|
|
7
|
+
const execAsync = promisify(exec);
|
|
8
|
+
/**
|
|
9
|
+
* Load and parse .gitignore file, returns an ignore instance
|
|
10
|
+
*/
|
|
11
|
+
function loadGitignore(cwd) {
|
|
12
|
+
const ig = ignore();
|
|
13
|
+
const gitignorePath = join(cwd, '.gitignore');
|
|
14
|
+
// Always ignore common directories
|
|
15
|
+
ig.add([
|
|
16
|
+
'node_modules',
|
|
17
|
+
'.git',
|
|
18
|
+
'dist',
|
|
19
|
+
'build',
|
|
20
|
+
'coverage',
|
|
21
|
+
'.next',
|
|
22
|
+
'.nuxt',
|
|
23
|
+
'out',
|
|
24
|
+
'.cache',
|
|
25
|
+
]);
|
|
26
|
+
// Load .gitignore if it exists
|
|
27
|
+
if (existsSync(gitignorePath)) {
|
|
28
|
+
try {
|
|
29
|
+
const gitignoreContent = readFileSync(gitignorePath, 'utf-8');
|
|
30
|
+
ig.add(gitignoreContent);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Silently fail if we can't read .gitignore
|
|
34
|
+
// The hardcoded ignores above will still apply
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return ig;
|
|
38
|
+
}
|
|
39
|
+
let fileListCache = null;
|
|
40
|
+
const CACHE_TTL = 5000; // 5 seconds
|
|
41
|
+
/**
|
|
42
|
+
* Get list of all files in the project (respecting gitignore)
|
|
43
|
+
*/
|
|
44
|
+
async function getAllFiles(cwd) {
|
|
45
|
+
// Check cache
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
if (fileListCache && now - fileListCache.timestamp < CACHE_TTL) {
|
|
48
|
+
return fileListCache.files;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const ig = loadGitignore(cwd);
|
|
52
|
+
// Use find to list all files, excluding common large directories
|
|
53
|
+
const { stdout } = await execAsync(`find . -type f -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/dist/*" -not -path "*/build/*" -not -path "*/coverage/*" -not -path "*/.next/*" -not -path "*/.nuxt/*" -not -path "*/out/*" -not -path "*/.cache/*"`, { cwd, maxBuffer: 1024 * 1024 * 10 });
|
|
54
|
+
const allFiles = stdout
|
|
55
|
+
.trim()
|
|
56
|
+
.split('\n')
|
|
57
|
+
.filter(Boolean)
|
|
58
|
+
.map(line => line.replace(/^\.\//, '')) // Remove leading "./"
|
|
59
|
+
.filter(file => !ig.ignores(file)); // Filter by gitignore
|
|
60
|
+
// Update cache
|
|
61
|
+
fileListCache = {
|
|
62
|
+
files: allFiles,
|
|
63
|
+
timestamp: now,
|
|
64
|
+
};
|
|
65
|
+
return allFiles;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
// If find fails, return empty array
|
|
69
|
+
console.error('Failed to list files:', error);
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Fuzzy match scoring algorithm for file paths
|
|
75
|
+
* Returns a score from 0 to 1000 (higher = better match)
|
|
76
|
+
* @deprecated Use fuzzyScoreFilePath from fuzzy-matching.ts instead
|
|
77
|
+
*/
|
|
78
|
+
export function fuzzyScore(filePath, query) {
|
|
79
|
+
return fuzzyScoreFilePath(filePath, query);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Extract the current @mention being typed at cursor position
|
|
83
|
+
* Returns the mention text and its position in the input
|
|
84
|
+
*/
|
|
85
|
+
export function getCurrentFileMention(input, cursorPosition) {
|
|
86
|
+
const pos = cursorPosition ?? input.length;
|
|
87
|
+
// Find the last @ before cursor
|
|
88
|
+
let startIndex = -1;
|
|
89
|
+
for (let i = pos - 1; i >= 0; i--) {
|
|
90
|
+
if (input[i] === '@') {
|
|
91
|
+
startIndex = i;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
// Stop if we hit whitespace (except for path separators)
|
|
95
|
+
if (input[i] === ' ' || input[i] === '\t' || input[i] === '\n') {
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (startIndex === -1) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
// Find the end of the mention (next whitespace or end of string)
|
|
103
|
+
let endIndex = pos;
|
|
104
|
+
for (let i = pos; i < input.length; i++) {
|
|
105
|
+
if (input[i] === ' ' ||
|
|
106
|
+
input[i] === '\t' ||
|
|
107
|
+
input[i] === '\n' ||
|
|
108
|
+
input[i] === '@') {
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
endIndex = i + 1;
|
|
112
|
+
}
|
|
113
|
+
// Extract mention text (without the @)
|
|
114
|
+
const fullText = input.substring(startIndex, endIndex);
|
|
115
|
+
const mention = fullText.substring(1); // Remove @ prefix
|
|
116
|
+
// Remove line range suffix if present (e.g., ":10-20")
|
|
117
|
+
const mentionWithoutRange = mention.replace(/:\d+(-\d+)?$/, '');
|
|
118
|
+
return {
|
|
119
|
+
mention: mentionWithoutRange,
|
|
120
|
+
startIndex,
|
|
121
|
+
endIndex,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get file completions for a partial path
|
|
126
|
+
*/
|
|
127
|
+
export async function getFileCompletions(partialPath, cwd, maxResults = 20) {
|
|
128
|
+
// Get all files
|
|
129
|
+
const allFiles = await getAllFiles(cwd);
|
|
130
|
+
// Score each file
|
|
131
|
+
const scoredFiles = allFiles
|
|
132
|
+
.map(file => ({
|
|
133
|
+
path: file,
|
|
134
|
+
displayPath: file.length > 50 ? '...' + file.slice(-47) : file,
|
|
135
|
+
score: fuzzyScoreFilePath(file, partialPath),
|
|
136
|
+
isDirectory: false, // We're only listing files, not directories
|
|
137
|
+
}))
|
|
138
|
+
.filter(f => f.score > 0) // Only include matches
|
|
139
|
+
.sort((a, b) => {
|
|
140
|
+
// Sort by score (descending)
|
|
141
|
+
if (b.score !== a.score) {
|
|
142
|
+
return b.score - a.score;
|
|
143
|
+
}
|
|
144
|
+
// If scores are equal, sort alphabetically
|
|
145
|
+
return a.path.localeCompare(b.path);
|
|
146
|
+
})
|
|
147
|
+
.slice(0, maxResults); // Limit results
|
|
148
|
+
return scoredFiles;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Clear the file list cache (useful for testing or when files change)
|
|
152
|
+
*/
|
|
153
|
+
export function clearFileListCache() {
|
|
154
|
+
fileListCache = null;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=file-autocomplete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-autocomplete.js","sourceRoot":"","sources":["../../source/utils/file-autocomplete.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-autocomplete.spec.d.ts","sourceRoot":"","sources":["../../source/utils/file-autocomplete.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { fuzzyScore, getCurrentFileMention, clearFileListCache, } from './file-autocomplete.js';
|
|
3
|
+
console.log(`\nfile-autocomplete.spec.ts`);
|
|
4
|
+
// Test fuzzyScore()
|
|
5
|
+
test('fuzzy score: exact match gets highest score', t => {
|
|
6
|
+
const score = fuzzyScore('app.tsx', 'app.tsx');
|
|
7
|
+
t.is(score, 1000);
|
|
8
|
+
});
|
|
9
|
+
test('fuzzy score: exact filename match', t => {
|
|
10
|
+
const score = fuzzyScore('src/components/app.tsx', 'app.tsx');
|
|
11
|
+
t.is(score, 900);
|
|
12
|
+
});
|
|
13
|
+
test('fuzzy score: path ends with query', t => {
|
|
14
|
+
const score = fuzzyScore('src/components/Button.tsx', 'Button.tsx');
|
|
15
|
+
// This matches exact filename, so it gets 900 not 850
|
|
16
|
+
t.is(score, 900);
|
|
17
|
+
});
|
|
18
|
+
test('fuzzy score: filename starts with query', t => {
|
|
19
|
+
const score = fuzzyScore('src/components/Button.tsx', 'butt');
|
|
20
|
+
t.is(score, 800);
|
|
21
|
+
});
|
|
22
|
+
test('fuzzy score: path starts with query', t => {
|
|
23
|
+
const score = fuzzyScore('src/components/Button.tsx', 'src/comp');
|
|
24
|
+
t.is(score, 750);
|
|
25
|
+
});
|
|
26
|
+
test('fuzzy score: filename contains query', t => {
|
|
27
|
+
const score = fuzzyScore('src/components/Button.tsx', 'ton');
|
|
28
|
+
t.is(score, 700);
|
|
29
|
+
});
|
|
30
|
+
test('fuzzy score: path contains query', t => {
|
|
31
|
+
const score = fuzzyScore('src/components/Button.tsx', 'compo');
|
|
32
|
+
// "compo" is a substring in path but doesn't start the path
|
|
33
|
+
t.is(score, 600);
|
|
34
|
+
});
|
|
35
|
+
test('fuzzy score: sequential character match', t => {
|
|
36
|
+
const score = fuzzyScore('src/components/Button.tsx', 'btn');
|
|
37
|
+
t.true(score > 0 && score < 600);
|
|
38
|
+
});
|
|
39
|
+
test('fuzzy score: no match returns 0', t => {
|
|
40
|
+
const score = fuzzyScore('app.tsx', 'xyz');
|
|
41
|
+
t.is(score, 0);
|
|
42
|
+
});
|
|
43
|
+
test('fuzzy score: empty query returns 0', t => {
|
|
44
|
+
const score = fuzzyScore('app.tsx', '');
|
|
45
|
+
t.is(score, 0);
|
|
46
|
+
});
|
|
47
|
+
test('fuzzy score: case insensitive', t => {
|
|
48
|
+
const score1 = fuzzyScore('App.tsx', 'app');
|
|
49
|
+
const score2 = fuzzyScore('app.tsx', 'APP');
|
|
50
|
+
t.true(score1 > 0);
|
|
51
|
+
t.true(score2 > 0);
|
|
52
|
+
});
|
|
53
|
+
test('fuzzy score: prefers shorter paths', t => {
|
|
54
|
+
const shortPath = fuzzyScore('app.tsx', 'app');
|
|
55
|
+
const longPath = fuzzyScore('src/components/nested/app.tsx', 'app');
|
|
56
|
+
// Both match filename "app.tsx" starting with "app", so they get same score
|
|
57
|
+
// The scoring doesn't currently prefer shorter paths
|
|
58
|
+
t.is(shortPath, longPath);
|
|
59
|
+
});
|
|
60
|
+
test('fuzzy score: consecutive matches get bonus', t => {
|
|
61
|
+
// "but" matches consecutively in "Button"
|
|
62
|
+
const consecutive = fuzzyScore('Button.tsx', 'but');
|
|
63
|
+
// "btn" requires skipping characters
|
|
64
|
+
const nonConsecutive = fuzzyScore('Button.tsx', 'btn');
|
|
65
|
+
t.true(consecutive > nonConsecutive);
|
|
66
|
+
});
|
|
67
|
+
// Test getCurrentFileMention()
|
|
68
|
+
test('extracts mention at end of string', t => {
|
|
69
|
+
const result = getCurrentFileMention('Fix @src/app');
|
|
70
|
+
t.truthy(result);
|
|
71
|
+
t.is(result.mention, 'src/app');
|
|
72
|
+
t.is(result.startIndex, 4);
|
|
73
|
+
t.is(result.endIndex, 12);
|
|
74
|
+
});
|
|
75
|
+
test('extracts mention in middle of string', t => {
|
|
76
|
+
// Cursor at position 15 is right after "x" in ".tsx"
|
|
77
|
+
const result = getCurrentFileMention('Check @app.tsx please', 14);
|
|
78
|
+
t.truthy(result);
|
|
79
|
+
t.is(result.mention, 'app.tsx');
|
|
80
|
+
t.is(result.startIndex, 6);
|
|
81
|
+
});
|
|
82
|
+
test('extracts mention with cursor in middle', t => {
|
|
83
|
+
const result = getCurrentFileMention('Fix @src/ap', 11);
|
|
84
|
+
t.truthy(result);
|
|
85
|
+
t.is(result.mention, 'src/ap');
|
|
86
|
+
});
|
|
87
|
+
test('returns null when no @ symbol', t => {
|
|
88
|
+
const result = getCurrentFileMention('Just regular text');
|
|
89
|
+
t.is(result, null);
|
|
90
|
+
});
|
|
91
|
+
test('returns null when @ is after cursor', t => {
|
|
92
|
+
const result = getCurrentFileMention('Text @file.txt', 3);
|
|
93
|
+
t.is(result, null);
|
|
94
|
+
});
|
|
95
|
+
test('returns null when @ is followed by space', t => {
|
|
96
|
+
const result = getCurrentFileMention('Fix @ file.txt');
|
|
97
|
+
t.is(result, null);
|
|
98
|
+
});
|
|
99
|
+
test('strips line range from mention', t => {
|
|
100
|
+
const result = getCurrentFileMention('Fix @app.tsx:10-20');
|
|
101
|
+
t.truthy(result);
|
|
102
|
+
t.is(result.mention, 'app.tsx');
|
|
103
|
+
});
|
|
104
|
+
test('strips single line number from mention', t => {
|
|
105
|
+
const result = getCurrentFileMention('Fix @app.tsx:10');
|
|
106
|
+
t.truthy(result);
|
|
107
|
+
t.is(result.mention, 'app.tsx');
|
|
108
|
+
});
|
|
109
|
+
test('handles multiple @ symbols', t => {
|
|
110
|
+
const result = getCurrentFileMention('Compare @a.ts and @b.ts', 24);
|
|
111
|
+
t.truthy(result);
|
|
112
|
+
t.is(result.mention, 'b.ts');
|
|
113
|
+
});
|
|
114
|
+
test('handles @ at start of string', t => {
|
|
115
|
+
const result = getCurrentFileMention('@app.tsx');
|
|
116
|
+
t.truthy(result);
|
|
117
|
+
t.is(result.mention, 'app.tsx');
|
|
118
|
+
t.is(result.startIndex, 0);
|
|
119
|
+
});
|
|
120
|
+
test('handles path with slashes', t => {
|
|
121
|
+
const result = getCurrentFileMention('@src/components/Button.tsx');
|
|
122
|
+
t.truthy(result);
|
|
123
|
+
t.is(result.mention, 'src/components/Button.tsx');
|
|
124
|
+
});
|
|
125
|
+
test('stops at whitespace', t => {
|
|
126
|
+
// When cursor is at end (after "here"), we look back and hit whitespace
|
|
127
|
+
// So we should use cursor position right after the file mention
|
|
128
|
+
const result = getCurrentFileMention('@app.tsx here', 8);
|
|
129
|
+
t.truthy(result);
|
|
130
|
+
t.is(result.mention, 'app.tsx');
|
|
131
|
+
t.is(result.endIndex, 8);
|
|
132
|
+
});
|
|
133
|
+
test('stops at next @ symbol', t => {
|
|
134
|
+
const result = getCurrentFileMention('@app.tsx@other', 8);
|
|
135
|
+
t.truthy(result);
|
|
136
|
+
t.is(result.mention, 'app.tsx');
|
|
137
|
+
});
|
|
138
|
+
// Clear cache between tests (if needed)
|
|
139
|
+
test.afterEach(() => {
|
|
140
|
+
clearFileListCache();
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=file-autocomplete.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-autocomplete.spec.js","sourceRoot":"","sources":["../../source/utils/file-autocomplete.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
interface FileContentResult {
|
|
2
|
+
success: boolean;
|
|
3
|
+
content?: string;
|
|
4
|
+
error?: string;
|
|
5
|
+
metadata: {
|
|
6
|
+
path: string;
|
|
7
|
+
absolutePath: string;
|
|
8
|
+
size: number;
|
|
9
|
+
lineCount: number;
|
|
10
|
+
lineRange?: {
|
|
11
|
+
start: number;
|
|
12
|
+
end?: number;
|
|
13
|
+
};
|
|
14
|
+
tokens: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Load file content with optional line range
|
|
19
|
+
* Silently handles errors - returns success: false instead of throwing
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadFileContent(filePath: string, lineRange?: {
|
|
22
|
+
start: number;
|
|
23
|
+
end?: number;
|
|
24
|
+
}): Promise<FileContentResult>;
|
|
25
|
+
/**
|
|
26
|
+
* Format file content with header for LLM context
|
|
27
|
+
* Used when assembling the prompt
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatFileForContext(result: FileContentResult): string;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=file-content-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-content-loader.d.ts","sourceRoot":"","sources":["../../source/utils/file-content-loader.ts"],"names":[],"mappings":"AAGA,UAAU,iBAAiB;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE;QACT,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,EAAE,MAAM,CAAC;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,GAAG,CAAC,EAAE,MAAM,CAAA;SAAC,CAAC;QAC1C,MAAM,EAAE,MAAM,CAAC;KACf,CAAC;CACF;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACpC,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAC,GACvC,OAAO,CAAC,iBAAiB,CAAC,CA2G5B;AAiBD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CA0BtE"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
3
|
+
/**
|
|
4
|
+
* Load file content with optional line range
|
|
5
|
+
* Silently handles errors - returns success: false instead of throwing
|
|
6
|
+
*/
|
|
7
|
+
export async function loadFileContent(filePath, lineRange) {
|
|
8
|
+
try {
|
|
9
|
+
const absPath = resolve(filePath);
|
|
10
|
+
// Check if file exists and get stats
|
|
11
|
+
const fileStats = await stat(absPath);
|
|
12
|
+
// Check if it's a file (not directory)
|
|
13
|
+
if (!fileStats.isFile()) {
|
|
14
|
+
return {
|
|
15
|
+
success: false,
|
|
16
|
+
error: 'Path is not a file',
|
|
17
|
+
metadata: {
|
|
18
|
+
path: filePath,
|
|
19
|
+
absolutePath: absPath,
|
|
20
|
+
size: 0,
|
|
21
|
+
lineCount: 0,
|
|
22
|
+
lineRange,
|
|
23
|
+
tokens: 0,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
// Read file content
|
|
28
|
+
let content;
|
|
29
|
+
try {
|
|
30
|
+
content = await readFile(absPath, 'utf-8');
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// File might be binary or unreadable
|
|
34
|
+
return {
|
|
35
|
+
success: false,
|
|
36
|
+
error: 'Failed to read file (might be binary)',
|
|
37
|
+
metadata: {
|
|
38
|
+
path: filePath,
|
|
39
|
+
absolutePath: absPath,
|
|
40
|
+
size: fileStats.size,
|
|
41
|
+
lineCount: 0,
|
|
42
|
+
lineRange,
|
|
43
|
+
tokens: 0,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// Split into lines
|
|
48
|
+
const allLines = content.split('\n');
|
|
49
|
+
const totalLines = allLines.length;
|
|
50
|
+
// Extract line range if specified
|
|
51
|
+
let selectedLines;
|
|
52
|
+
let actualLineRange;
|
|
53
|
+
if (lineRange) {
|
|
54
|
+
const start = Math.max(1, lineRange.start);
|
|
55
|
+
const end = lineRange.end ? Math.min(totalLines, lineRange.end) : start;
|
|
56
|
+
// Validate range
|
|
57
|
+
if (start > totalLines) {
|
|
58
|
+
// Invalid range, return empty
|
|
59
|
+
selectedLines = [];
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// Arrays are 0-indexed, but line numbers are 1-indexed
|
|
63
|
+
selectedLines = allLines.slice(start - 1, end);
|
|
64
|
+
actualLineRange = { start, end: lineRange.end ? end : undefined };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// No line range, use all lines
|
|
69
|
+
selectedLines = allLines;
|
|
70
|
+
}
|
|
71
|
+
// Format with line numbers
|
|
72
|
+
const formattedContent = formatFileContentWithLineNumbers(selectedLines, lineRange?.start || 1);
|
|
73
|
+
// Calculate metadata
|
|
74
|
+
const size = content.length;
|
|
75
|
+
const tokens = Math.ceil(formattedContent.length / 4); // Rough token estimate
|
|
76
|
+
return {
|
|
77
|
+
success: true,
|
|
78
|
+
content: formattedContent,
|
|
79
|
+
metadata: {
|
|
80
|
+
path: filePath,
|
|
81
|
+
absolutePath: absPath,
|
|
82
|
+
size,
|
|
83
|
+
lineCount: selectedLines.length,
|
|
84
|
+
lineRange: actualLineRange,
|
|
85
|
+
tokens,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
// File doesn't exist or other error
|
|
91
|
+
const absPath = resolve(filePath);
|
|
92
|
+
return {
|
|
93
|
+
success: false,
|
|
94
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
95
|
+
metadata: {
|
|
96
|
+
path: filePath,
|
|
97
|
+
absolutePath: absPath,
|
|
98
|
+
size: 0,
|
|
99
|
+
lineCount: 0,
|
|
100
|
+
lineRange,
|
|
101
|
+
tokens: 0,
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Format file lines with line numbers
|
|
108
|
+
*/
|
|
109
|
+
function formatFileContentWithLineNumbers(lines, startLineNumber) {
|
|
110
|
+
let result = '';
|
|
111
|
+
for (let i = 0; i < lines.length; i++) {
|
|
112
|
+
const lineNum = String(startLineNumber + i).padStart(4, ' ');
|
|
113
|
+
result += `${lineNum}: ${lines[i]}\n`;
|
|
114
|
+
}
|
|
115
|
+
return result.slice(0, -1); // Remove trailing newline
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Format file content with header for LLM context
|
|
119
|
+
* Used when assembling the prompt
|
|
120
|
+
*/
|
|
121
|
+
export function formatFileForContext(result) {
|
|
122
|
+
if (!result.success || !result.content) {
|
|
123
|
+
return `Error loading file: ${result.metadata.path}`;
|
|
124
|
+
}
|
|
125
|
+
const { path, lineCount, lineRange, tokens } = result.metadata;
|
|
126
|
+
let header;
|
|
127
|
+
if (lineRange) {
|
|
128
|
+
const rangeStr = lineRange.end
|
|
129
|
+
? `${lineRange.start}-${lineRange.end}`
|
|
130
|
+
: `${lineRange.start}`;
|
|
131
|
+
header = `=== File: ${path} (Lines ${rangeStr}) ===`;
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
header = `=== File: ${path} ===`;
|
|
135
|
+
}
|
|
136
|
+
const footer = '='.repeat(header.length);
|
|
137
|
+
const stats = lineRange
|
|
138
|
+
? `Lines: ${lineRange.start}${lineRange.end ? `-${lineRange.end}` : ''} (${lineCount} lines, ~${tokens} tokens)`
|
|
139
|
+
: `Lines: ${lineCount}, ~${tokens} tokens`;
|
|
140
|
+
return `${header}\n${stats}\n\n${result.content}\n${footer}`;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=file-content-loader.js.map
|