@zds-ai/cli 0.1.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/LICENSE +21 -0
- package/README.md +497 -0
- package/dist/agent/grok-agent.d.ts +250 -0
- package/dist/agent/grok-agent.js +2480 -0
- package/dist/agent/grok-agent.js.map +1 -0
- package/dist/agent/index.d.ts +14 -0
- package/dist/agent/index.js +136 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/commands/mcp.d.ts +2 -0
- package/dist/commands/mcp.js +239 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/grok/client.d.ts +55 -0
- package/dist/grok/client.js +276 -0
- package/dist/grok/client.js.map +1 -0
- package/dist/grok/tools.d.ts +8 -0
- package/dist/grok/tools.js +878 -0
- package/dist/grok/tools.js.map +1 -0
- package/dist/hooks/use-enhanced-input.d.ts +38 -0
- package/dist/hooks/use-enhanced-input.js +228 -0
- package/dist/hooks/use-enhanced-input.js.map +1 -0
- package/dist/hooks/use-input-handler.d.ts +36 -0
- package/dist/hooks/use-input-handler.js +1099 -0
- package/dist/hooks/use-input-handler.js.map +1 -0
- package/dist/hooks/use-input-history.d.ts +9 -0
- package/dist/hooks/use-input-history.js +61 -0
- package/dist/hooks/use-input-history.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +869 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/client.d.ts +41 -0
- package/dist/mcp/client.js +224 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/config.d.ts +13 -0
- package/dist/mcp/config.js +56 -0
- package/dist/mcp/config.js.map +1 -0
- package/dist/mcp/transports.d.ts +53 -0
- package/dist/mcp/transports.js +256 -0
- package/dist/mcp/transports.js.map +1 -0
- package/dist/tools/character-tool.d.ts +27 -0
- package/dist/tools/character-tool.js +194 -0
- package/dist/tools/character-tool.js.map +1 -0
- package/dist/tools/clear-cache-tool.d.ts +14 -0
- package/dist/tools/clear-cache-tool.js +82 -0
- package/dist/tools/clear-cache-tool.js.map +1 -0
- package/dist/tools/confirmation-tool.d.ts +16 -0
- package/dist/tools/confirmation-tool.js +72 -0
- package/dist/tools/confirmation-tool.js.map +1 -0
- package/dist/tools/env-tool.d.ts +17 -0
- package/dist/tools/env-tool.js +89 -0
- package/dist/tools/env-tool.js.map +1 -0
- package/dist/tools/file-conversion-tool.d.ts +16 -0
- package/dist/tools/file-conversion-tool.js +181 -0
- package/dist/tools/file-conversion-tool.js.map +1 -0
- package/dist/tools/image-tool.d.ts +22 -0
- package/dist/tools/image-tool.js +268 -0
- package/dist/tools/image-tool.js.map +1 -0
- package/dist/tools/index.d.ts +14 -0
- package/dist/tools/index.js +15 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/internet-tool.d.ts +11 -0
- package/dist/tools/internet-tool.js +108 -0
- package/dist/tools/internet-tool.js.map +1 -0
- package/dist/tools/introspect-tool.d.ts +11 -0
- package/dist/tools/introspect-tool.js +243 -0
- package/dist/tools/introspect-tool.js.map +1 -0
- package/dist/tools/morph-editor.d.ts +38 -0
- package/dist/tools/morph-editor.js +318 -0
- package/dist/tools/morph-editor.js.map +1 -0
- package/dist/tools/restart-tool.d.ts +7 -0
- package/dist/tools/restart-tool.js +24 -0
- package/dist/tools/restart-tool.js.map +1 -0
- package/dist/tools/search.d.ts +71 -0
- package/dist/tools/search.js +340 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/task-tool.d.ts +19 -0
- package/dist/tools/task-tool.js +115 -0
- package/dist/tools/task-tool.js.map +1 -0
- package/dist/tools/text-editor.d.ts +35 -0
- package/dist/tools/text-editor.js +669 -0
- package/dist/tools/text-editor.js.map +1 -0
- package/dist/tools/tool-discovery.d.ts +20 -0
- package/dist/tools/tool-discovery.js +45 -0
- package/dist/tools/tool-discovery.js.map +1 -0
- package/dist/tools/zsh.d.ts +13 -0
- package/dist/tools/zsh.js +168 -0
- package/dist/tools/zsh.js.map +1 -0
- package/dist/types/index.d.ts +31 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/app.d.ts +7 -0
- package/dist/ui/app.js +99 -0
- package/dist/ui/app.js.map +1 -0
- package/dist/ui/components/active-task-status.d.ts +7 -0
- package/dist/ui/components/active-task-status.js +37 -0
- package/dist/ui/components/active-task-status.js.map +1 -0
- package/dist/ui/components/api-key-input.d.ts +7 -0
- package/dist/ui/components/api-key-input.js +80 -0
- package/dist/ui/components/api-key-input.js.map +1 -0
- package/dist/ui/components/backend-status.d.ts +7 -0
- package/dist/ui/components/backend-status.js +85 -0
- package/dist/ui/components/backend-status.js.map +1 -0
- package/dist/ui/components/chat-history.d.ts +8 -0
- package/dist/ui/components/chat-history.js +187 -0
- package/dist/ui/components/chat-history.js.map +1 -0
- package/dist/ui/components/chat-input.d.ts +9 -0
- package/dist/ui/components/chat-input.js +63 -0
- package/dist/ui/components/chat-input.js.map +1 -0
- package/dist/ui/components/chat-interface.d.ts +9 -0
- package/dist/ui/components/chat-interface.js +389 -0
- package/dist/ui/components/chat-interface.js.map +1 -0
- package/dist/ui/components/command-suggestions.d.ts +17 -0
- package/dist/ui/components/command-suggestions.js +22 -0
- package/dist/ui/components/command-suggestions.js.map +1 -0
- package/dist/ui/components/confirmation-dialog.d.ts +11 -0
- package/dist/ui/components/confirmation-dialog.js +105 -0
- package/dist/ui/components/confirmation-dialog.js.map +1 -0
- package/dist/ui/components/context-status.d.ts +7 -0
- package/dist/ui/components/context-status.js +36 -0
- package/dist/ui/components/context-status.js.map +1 -0
- package/dist/ui/components/diff-renderer.d.ts +13 -0
- package/dist/ui/components/diff-renderer.js +206 -0
- package/dist/ui/components/diff-renderer.js.map +1 -0
- package/dist/ui/components/loading-spinner.d.ts +8 -0
- package/dist/ui/components/loading-spinner.js +64 -0
- package/dist/ui/components/loading-spinner.js.map +1 -0
- package/dist/ui/components/mcp-status.d.ts +5 -0
- package/dist/ui/components/mcp-status.js +57 -0
- package/dist/ui/components/mcp-status.js.map +1 -0
- package/dist/ui/components/model-selection.d.ts +12 -0
- package/dist/ui/components/model-selection.js +17 -0
- package/dist/ui/components/model-selection.js.map +1 -0
- package/dist/ui/components/mood-status.d.ts +7 -0
- package/dist/ui/components/mood-status.js +34 -0
- package/dist/ui/components/mood-status.js.map +1 -0
- package/dist/ui/components/persona-status.d.ts +7 -0
- package/dist/ui/components/persona-status.js +34 -0
- package/dist/ui/components/persona-status.js.map +1 -0
- package/dist/ui/shared/max-sized-box.d.ts +8 -0
- package/dist/ui/shared/max-sized-box.js +6 -0
- package/dist/ui/shared/max-sized-box.js.map +1 -0
- package/dist/ui/utils/code-colorizer.d.ts +2 -0
- package/dist/ui/utils/code-colorizer.js +7 -0
- package/dist/ui/utils/code-colorizer.js.map +1 -0
- package/dist/ui/utils/colors.d.ts +14 -0
- package/dist/ui/utils/colors.js +15 -0
- package/dist/ui/utils/colors.js.map +1 -0
- package/dist/ui/utils/markdown-renderer.d.ts +4 -0
- package/dist/ui/utils/markdown-renderer.js +40 -0
- package/dist/ui/utils/markdown-renderer.js.map +1 -0
- package/dist/utils/auth-helper.d.ts +63 -0
- package/dist/utils/auth-helper.js +129 -0
- package/dist/utils/auth-helper.js.map +1 -0
- package/dist/utils/chat-history-manager-sqlite.d.ts +92 -0
- package/dist/utils/chat-history-manager-sqlite.js +334 -0
- package/dist/utils/chat-history-manager-sqlite.js.map +1 -0
- package/dist/utils/chat-history-manager.d.ts +87 -0
- package/dist/utils/chat-history-manager.js +273 -0
- package/dist/utils/chat-history-manager.js.map +1 -0
- package/dist/utils/chat-history-manager.json-backup.d.ts +69 -0
- package/dist/utils/chat-history-manager.json-backup.js +215 -0
- package/dist/utils/chat-history-manager.json-backup.js.map +1 -0
- package/dist/utils/confirmation-service.d.ts +46 -0
- package/dist/utils/confirmation-service.js +165 -0
- package/dist/utils/confirmation-service.js.map +1 -0
- package/dist/utils/custom-instructions.d.ts +1 -0
- package/dist/utils/custom-instructions.js +30 -0
- package/dist/utils/custom-instructions.js.map +1 -0
- package/dist/utils/database-connection.d.ts +27 -0
- package/dist/utils/database-connection.js +81 -0
- package/dist/utils/database-connection.js.map +1 -0
- package/dist/utils/database-schema.d.ts +17 -0
- package/dist/utils/database-schema.js +93 -0
- package/dist/utils/database-schema.js.map +1 -0
- package/dist/utils/error-logger.d.ts +13 -0
- package/dist/utils/error-logger.js +56 -0
- package/dist/utils/error-logger.js.map +1 -0
- package/dist/utils/hook-executor.d.ts +59 -0
- package/dist/utils/hook-executor.js +351 -0
- package/dist/utils/hook-executor.js.map +1 -0
- package/dist/utils/model-config.d.ts +28 -0
- package/dist/utils/model-config.js +42 -0
- package/dist/utils/model-config.js.map +1 -0
- package/dist/utils/path-utils.d.ts +4 -0
- package/dist/utils/path-utils.js +12 -0
- package/dist/utils/path-utils.js.map +1 -0
- package/dist/utils/settings-manager.d.ts +169 -0
- package/dist/utils/settings-manager.js +403 -0
- package/dist/utils/settings-manager.js.map +1 -0
- package/dist/utils/settings.d.ts +1 -0
- package/dist/utils/settings.js +4 -0
- package/dist/utils/settings.js.map +1 -0
- package/dist/utils/slash-commands.d.ts +25 -0
- package/dist/utils/slash-commands.js +454 -0
- package/dist/utils/slash-commands.js.map +1 -0
- package/dist/utils/startup-hook.d.ts +13 -0
- package/dist/utils/startup-hook.js +44 -0
- package/dist/utils/startup-hook.js.map +1 -0
- package/dist/utils/text-utils.d.ts +80 -0
- package/dist/utils/text-utils.js +182 -0
- package/dist/utils/text-utils.js.map +1 -0
- package/dist/utils/token-counter.d.ts +33 -0
- package/dist/utils/token-counter.js +78 -0
- package/dist/utils/token-counter.js.map +1 -0
- package/package.json +102 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Text } from 'ink';
|
|
3
|
+
import { marked } from 'marked';
|
|
4
|
+
import TerminalRenderer from 'marked-terminal';
|
|
5
|
+
export function MarkdownRenderer({ content }) {
|
|
6
|
+
try {
|
|
7
|
+
// List of common abbreviations that should NOT get two spaces after them
|
|
8
|
+
const abbreviations = ['Mr', 'Mrs', 'Ms', 'Dr', 'St', 'Jr', 'Sr', 'Prof', 'Rev'];
|
|
9
|
+
// Pre-process: Convert one or two spaces after hard stops to nbsp + space (to prevent reflow collapse)
|
|
10
|
+
// Pattern: word(2+ chars) + optional quotes/markdown + hard stop + optional quotes/markdown + 1-2 spaces + optional quotes/markdown + capital
|
|
11
|
+
// Supports: " ' " " ' ' " " (quotes) and * ** (markdown emphasis)
|
|
12
|
+
// Note: nbsp comes FIRST so it stays with the hard stop, not at start of new line
|
|
13
|
+
let processed = content.replace(/\b(\w{2,})(["'""''""\u201C\u201D*]*?)([.!?])(["'""''""\u201C\u201D*]*?) {1,2}(["'""''""\u201C\u201D*]*?)([A-Z])/g, (match, word, markupBefore, punct, markupAfter, markupBeforeCap, cap) => {
|
|
14
|
+
// Don't convert if word is an abbreviation
|
|
15
|
+
if (abbreviations.includes(word))
|
|
16
|
+
return match;
|
|
17
|
+
// Convert to: non-breaking space + regular space (preserving all markup)
|
|
18
|
+
return `${word}${markupBefore}${punct}${markupAfter}\u00A0 ${markupBeforeCap}${cap}`;
|
|
19
|
+
});
|
|
20
|
+
// Create a new renderer with width reduced by 3 columns for each render
|
|
21
|
+
// to account for bullet points and spacing that would cause wrapping
|
|
22
|
+
const terminalWidth = (process.stdout.columns || 80) - 3;
|
|
23
|
+
const renderer = new TerminalRenderer({
|
|
24
|
+
width: terminalWidth,
|
|
25
|
+
reflowText: true
|
|
26
|
+
});
|
|
27
|
+
marked.setOptions({ renderer });
|
|
28
|
+
// Use marked.parse for synchronous parsing
|
|
29
|
+
const result = marked.parse(processed);
|
|
30
|
+
// Handle both sync and async results
|
|
31
|
+
const rendered = typeof result === 'string' ? result : content;
|
|
32
|
+
return React.createElement(Text, null, rendered);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
// Fallback to plain text if markdown parsing fails
|
|
36
|
+
console.error('Markdown rendering error:', error);
|
|
37
|
+
return React.createElement(Text, null, content);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=markdown-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-renderer.js","sourceRoot":"","sources":["../../../src/ui/utils/markdown-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,gBAAgB,MAAM,iBAAiB,CAAC;AAE/C,MAAM,UAAU,gBAAgB,CAAC,EAAE,OAAO,EAAuB;IAC/D,IAAI,CAAC;QACH,yEAAyE;QACzE,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QAEjF,uGAAuG;QACvG,8IAA8I;QAC9I,kEAAkE;QAClE,kFAAkF;QAClF,IAAI,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,kHAAkH,EAChJ,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,EAAE,EAAE;YACtE,2CAA2C;YAC3C,IAAI,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,OAAO,KAAK,CAAC;YAC/C,yEAAyE;YACzE,OAAO,GAAG,IAAI,GAAG,YAAY,GAAG,KAAK,GAAG,WAAW,UAAU,eAAe,GAAG,GAAG,EAAE,CAAC;QACvF,CAAC,CACF,CAAC;QAEF,wEAAwE;QACxE,qEAAqE;QACrE,MAAM,aAAa,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;QAEzD,MAAM,QAAQ,GAAG,IAAK,gBAAwB,CAAC;YAC7C,KAAK,EAAE,aAAa;YACpB,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;QAEH,MAAM,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEhC,2CAA2C;QAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACvC,qCAAqC;QACrC,MAAM,QAAQ,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QAC/D,OAAO,oBAAC,IAAI,QAAE,QAAQ,CAAQ,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,mDAAmD;QACnD,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;QAClD,OAAO,oBAAC,IAAI,QAAE,OAAO,CAAQ,CAAC;IAChC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication helper utilities
|
|
3
|
+
* Handles API key retrieval from multiple sources with proper fallback logic
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Get API key with proper fallback logic:
|
|
7
|
+
* 1. Environment variable (GROK_API_KEY)
|
|
8
|
+
* 2. User settings file (~/.grok/user-settings.json)
|
|
9
|
+
* 3. Command-line argument (passed explicitly)
|
|
10
|
+
*
|
|
11
|
+
* @param explicitApiKey - API key passed via command-line argument (highest priority)
|
|
12
|
+
* @returns API key or undefined if not found
|
|
13
|
+
*/
|
|
14
|
+
export declare function getApiKey(explicitApiKey?: string): string | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Get base URL with proper fallback logic:
|
|
17
|
+
* 1. Explicit base URL from command-line argument
|
|
18
|
+
* 2. Environment variable (GROK_BASE_URL)
|
|
19
|
+
* 3. User settings file (~/.grok/user-settings.json)
|
|
20
|
+
* 4. Default value
|
|
21
|
+
*
|
|
22
|
+
* @param explicitBaseURL - Base URL passed via command-line argument (highest priority)
|
|
23
|
+
* @param defaultBaseURL - Default base URL to use if none found (default: https://api.x.ai/v1)
|
|
24
|
+
* @returns Base URL
|
|
25
|
+
*/
|
|
26
|
+
export declare function getBaseURL(explicitBaseURL?: string, defaultBaseURL?: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Get model with proper fallback logic:
|
|
29
|
+
* 1. Explicit model from command-line argument
|
|
30
|
+
* 2. Environment variable (GROK_MODEL)
|
|
31
|
+
* 3. Project-specific model setting
|
|
32
|
+
* 4. User's default model
|
|
33
|
+
* 5. Default value
|
|
34
|
+
*
|
|
35
|
+
* @param explicitModel - Model passed via command-line argument (highest priority)
|
|
36
|
+
* @param defaultModel - Default model to use if none found (default: grok-code-fast-1)
|
|
37
|
+
* @returns Model name
|
|
38
|
+
*/
|
|
39
|
+
export declare function getModel(explicitModel?: string, defaultModel?: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Validate that required authentication is present
|
|
42
|
+
* Throws an error with helpful message if API key is missing
|
|
43
|
+
*
|
|
44
|
+
* @param apiKey - API key to validate
|
|
45
|
+
* @throws Error if API key is undefined or empty
|
|
46
|
+
*/
|
|
47
|
+
export declare function validateApiKey(apiKey: string | undefined): asserts apiKey is string;
|
|
48
|
+
/**
|
|
49
|
+
* Get all authentication configuration with proper fallbacks
|
|
50
|
+
* Convenience function that combines all auth-related getters
|
|
51
|
+
*
|
|
52
|
+
* @param options - Optional explicit values from command-line arguments
|
|
53
|
+
* @returns Complete authentication configuration
|
|
54
|
+
*/
|
|
55
|
+
export declare function getAuthConfig(options?: {
|
|
56
|
+
apiKey?: string;
|
|
57
|
+
baseURL?: string;
|
|
58
|
+
model?: string;
|
|
59
|
+
}): {
|
|
60
|
+
apiKey: string | undefined;
|
|
61
|
+
baseURL: string;
|
|
62
|
+
model: string;
|
|
63
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication helper utilities
|
|
3
|
+
* Handles API key retrieval from multiple sources with proper fallback logic
|
|
4
|
+
*/
|
|
5
|
+
import { getSettingsManager } from "./settings-manager.js";
|
|
6
|
+
/**
|
|
7
|
+
* Get API key with proper fallback logic:
|
|
8
|
+
* 1. Environment variable (GROK_API_KEY)
|
|
9
|
+
* 2. User settings file (~/.grok/user-settings.json)
|
|
10
|
+
* 3. Command-line argument (passed explicitly)
|
|
11
|
+
*
|
|
12
|
+
* @param explicitApiKey - API key passed via command-line argument (highest priority)
|
|
13
|
+
* @returns API key or undefined if not found
|
|
14
|
+
*/
|
|
15
|
+
export function getApiKey(explicitApiKey) {
|
|
16
|
+
// Priority 1: Explicit API key from command-line argument
|
|
17
|
+
if (explicitApiKey) {
|
|
18
|
+
return explicitApiKey;
|
|
19
|
+
}
|
|
20
|
+
// Priority 2: Environment variable
|
|
21
|
+
const envApiKey = process.env.GROK_API_KEY;
|
|
22
|
+
if (envApiKey) {
|
|
23
|
+
return envApiKey;
|
|
24
|
+
}
|
|
25
|
+
// Priority 3: User settings file
|
|
26
|
+
try {
|
|
27
|
+
const manager = getSettingsManager();
|
|
28
|
+
return manager.getUserSetting("apiKey");
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
// Silently ignore errors loading from settings
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get base URL with proper fallback logic:
|
|
37
|
+
* 1. Explicit base URL from command-line argument
|
|
38
|
+
* 2. Environment variable (GROK_BASE_URL)
|
|
39
|
+
* 3. User settings file (~/.grok/user-settings.json)
|
|
40
|
+
* 4. Default value
|
|
41
|
+
*
|
|
42
|
+
* @param explicitBaseURL - Base URL passed via command-line argument (highest priority)
|
|
43
|
+
* @param defaultBaseURL - Default base URL to use if none found (default: https://api.x.ai/v1)
|
|
44
|
+
* @returns Base URL
|
|
45
|
+
*/
|
|
46
|
+
export function getBaseURL(explicitBaseURL, defaultBaseURL = "https://api.x.ai/v1") {
|
|
47
|
+
// Priority 1: Explicit base URL from command-line argument
|
|
48
|
+
if (explicitBaseURL) {
|
|
49
|
+
return explicitBaseURL;
|
|
50
|
+
}
|
|
51
|
+
// Priority 2: Environment variable
|
|
52
|
+
const envBaseURL = process.env.GROK_BASE_URL;
|
|
53
|
+
if (envBaseURL) {
|
|
54
|
+
return envBaseURL;
|
|
55
|
+
}
|
|
56
|
+
// Priority 3: User settings file
|
|
57
|
+
try {
|
|
58
|
+
const manager = getSettingsManager();
|
|
59
|
+
const userBaseURL = manager.getUserSetting("baseURL");
|
|
60
|
+
if (userBaseURL) {
|
|
61
|
+
return userBaseURL;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
// Silently ignore errors loading from settings
|
|
66
|
+
}
|
|
67
|
+
// Priority 4: Default value
|
|
68
|
+
return defaultBaseURL;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get model with proper fallback logic:
|
|
72
|
+
* 1. Explicit model from command-line argument
|
|
73
|
+
* 2. Environment variable (GROK_MODEL)
|
|
74
|
+
* 3. Project-specific model setting
|
|
75
|
+
* 4. User's default model
|
|
76
|
+
* 5. Default value
|
|
77
|
+
*
|
|
78
|
+
* @param explicitModel - Model passed via command-line argument (highest priority)
|
|
79
|
+
* @param defaultModel - Default model to use if none found (default: grok-code-fast-1)
|
|
80
|
+
* @returns Model name
|
|
81
|
+
*/
|
|
82
|
+
export function getModel(explicitModel, defaultModel = "grok-code-fast-1") {
|
|
83
|
+
// Priority 1: Explicit model from command-line argument
|
|
84
|
+
if (explicitModel) {
|
|
85
|
+
return explicitModel;
|
|
86
|
+
}
|
|
87
|
+
// Priority 2: Environment variable
|
|
88
|
+
const envModel = process.env.GROK_MODEL;
|
|
89
|
+
if (envModel) {
|
|
90
|
+
return envModel;
|
|
91
|
+
}
|
|
92
|
+
// Priority 3-4: Project-specific or user's default model
|
|
93
|
+
try {
|
|
94
|
+
const manager = getSettingsManager();
|
|
95
|
+
return manager.getCurrentModel();
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
// Silently ignore errors loading from settings
|
|
99
|
+
}
|
|
100
|
+
// Priority 5: Default value
|
|
101
|
+
return defaultModel;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Validate that required authentication is present
|
|
105
|
+
* Throws an error with helpful message if API key is missing
|
|
106
|
+
*
|
|
107
|
+
* @param apiKey - API key to validate
|
|
108
|
+
* @throws Error if API key is undefined or empty
|
|
109
|
+
*/
|
|
110
|
+
export function validateApiKey(apiKey) {
|
|
111
|
+
if (!apiKey || apiKey.trim() === "") {
|
|
112
|
+
throw new Error("API key required. Set GROK_API_KEY environment variable, use --api-key flag, or save to ~/.grok/user-settings.json");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get all authentication configuration with proper fallbacks
|
|
117
|
+
* Convenience function that combines all auth-related getters
|
|
118
|
+
*
|
|
119
|
+
* @param options - Optional explicit values from command-line arguments
|
|
120
|
+
* @returns Complete authentication configuration
|
|
121
|
+
*/
|
|
122
|
+
export function getAuthConfig(options = {}) {
|
|
123
|
+
return {
|
|
124
|
+
apiKey: getApiKey(options.apiKey),
|
|
125
|
+
baseURL: getBaseURL(options.baseURL),
|
|
126
|
+
model: getModel(options.model),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=auth-helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-helper.js","sourceRoot":"","sources":["../../src/utils/auth-helper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,cAAuB;IAC/C,0DAA0D;IAC1D,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,mCAAmC;IACnC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC3C,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,iCAAiC;IACjC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;QACrC,OAAO,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,+CAA+C;QAC/C,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU,CACxB,eAAwB,EACxB,iBAAyB,qBAAqB;IAE9C,2DAA2D;IAC3D,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,mCAAmC;IACnC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAC7C,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,iCAAiC;IACjC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;QACrC,MAAM,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QACtD,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,WAAW,CAAC;QACrB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,+CAA+C;IACjD,CAAC;IAED,4BAA4B;IAC5B,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,QAAQ,CACtB,aAAsB,EACtB,eAAuB,kBAAkB;IAEzC,wDAAwD;IACxD,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,mCAAmC;IACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACxC,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,yDAAyD;IACzD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;QACrC,OAAO,OAAO,CAAC,eAAe,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,+CAA+C;IACjD,CAAC;IAED,4BAA4B;IAC5B,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,MAA0B;IACvD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CACb,oHAAoH,CACrH,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,UAI1B,EAAE;IAKJ,OAAO;QACL,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;QACjC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC;QACpC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;KAC/B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { ChatEntry } from "../agent/grok-agent.js";
|
|
2
|
+
export interface SessionState {
|
|
3
|
+
session: string;
|
|
4
|
+
persona: string;
|
|
5
|
+
personaColor: string;
|
|
6
|
+
mood: string;
|
|
7
|
+
moodColor: string;
|
|
8
|
+
activeTask: string;
|
|
9
|
+
activeTaskAction: string;
|
|
10
|
+
activeTaskColor: string;
|
|
11
|
+
cwd: string;
|
|
12
|
+
contextCurrent: number;
|
|
13
|
+
contextMax: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* SQLite-based chat history manager with support for concurrent access
|
|
17
|
+
*/
|
|
18
|
+
export declare class ChatHistoryManager {
|
|
19
|
+
private static instance;
|
|
20
|
+
private static customHistoryPath;
|
|
21
|
+
private dbPath;
|
|
22
|
+
private db;
|
|
23
|
+
private constructor();
|
|
24
|
+
/**
|
|
25
|
+
* Set a custom database path (must be called before getInstance)
|
|
26
|
+
*/
|
|
27
|
+
static setCustomHistoryPath(filePath: string): void;
|
|
28
|
+
static getInstance(): ChatHistoryManager;
|
|
29
|
+
/**
|
|
30
|
+
* Get the database file path
|
|
31
|
+
*/
|
|
32
|
+
getContextFilePath(): string;
|
|
33
|
+
private ensureHistoryDirExists;
|
|
34
|
+
/**
|
|
35
|
+
* Migrate from JSON files to SQLite if JSON files exist and DB is empty
|
|
36
|
+
*/
|
|
37
|
+
private migrateFromJSONIfNeeded;
|
|
38
|
+
/**
|
|
39
|
+
* Load chat history from database
|
|
40
|
+
*/
|
|
41
|
+
loadHistory(): ChatEntry[];
|
|
42
|
+
/**
|
|
43
|
+
* Add a single message to the database (atomic operation)
|
|
44
|
+
*/
|
|
45
|
+
addMessage(entry: ChatEntry): void;
|
|
46
|
+
/**
|
|
47
|
+
* Save chat history to database (replaces entire history)
|
|
48
|
+
* This maintains backward compatibility but is less efficient than addMessage
|
|
49
|
+
*/
|
|
50
|
+
saveHistory(history: ChatEntry[]): void;
|
|
51
|
+
/**
|
|
52
|
+
* Save raw messages log (for backward compatibility)
|
|
53
|
+
* In SQLite version, this is stored alongside the messages
|
|
54
|
+
*/
|
|
55
|
+
saveMessages(messages: any[]): void;
|
|
56
|
+
/**
|
|
57
|
+
* Create a backup of the database
|
|
58
|
+
*/
|
|
59
|
+
backupHistory(): string | null;
|
|
60
|
+
/**
|
|
61
|
+
* Clear all data from database with automatic backup
|
|
62
|
+
*/
|
|
63
|
+
clearHistory(): void;
|
|
64
|
+
/**
|
|
65
|
+
* Save session state to database
|
|
66
|
+
*/
|
|
67
|
+
saveSessionState(state: SessionState): void;
|
|
68
|
+
/**
|
|
69
|
+
* Load session state from database
|
|
70
|
+
*/
|
|
71
|
+
loadSessionState(): SessionState | null;
|
|
72
|
+
/**
|
|
73
|
+
* Get the debug log file path
|
|
74
|
+
*/
|
|
75
|
+
getDebugLogPath(): string;
|
|
76
|
+
/**
|
|
77
|
+
* Static method to get debug log path
|
|
78
|
+
*/
|
|
79
|
+
static getDebugLogPath(): string;
|
|
80
|
+
/**
|
|
81
|
+
* Get messages in a specific range (for pagination)
|
|
82
|
+
*/
|
|
83
|
+
getMessagesRange(offset: number, limit: number): ChatEntry[];
|
|
84
|
+
/**
|
|
85
|
+
* Get the total number of messages
|
|
86
|
+
*/
|
|
87
|
+
getMessageCount(): number;
|
|
88
|
+
/**
|
|
89
|
+
* Export current database to JSON format (for debugging/backup)
|
|
90
|
+
*/
|
|
91
|
+
exportToJSON(): string;
|
|
92
|
+
}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import * as os from "os";
|
|
4
|
+
import { DatabaseConnection } from "./database-connection.js";
|
|
5
|
+
const HISTORY_DIR = path.join(os.homedir(), ".grok");
|
|
6
|
+
const DB_FILE_NAME = "chat-history.db";
|
|
7
|
+
/**
|
|
8
|
+
* SQLite-based chat history manager with support for concurrent access
|
|
9
|
+
*/
|
|
10
|
+
export class ChatHistoryManager {
|
|
11
|
+
static instance;
|
|
12
|
+
static customHistoryPath = null;
|
|
13
|
+
dbPath;
|
|
14
|
+
db;
|
|
15
|
+
constructor() {
|
|
16
|
+
this.dbPath = ChatHistoryManager.customHistoryPath || path.join(HISTORY_DIR, DB_FILE_NAME);
|
|
17
|
+
this.ensureHistoryDirExists();
|
|
18
|
+
this.db = DatabaseConnection.getConnection(this.dbPath);
|
|
19
|
+
// Attempt migration from JSON if this is first run
|
|
20
|
+
this.migrateFromJSONIfNeeded();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Set a custom database path (must be called before getInstance)
|
|
24
|
+
*/
|
|
25
|
+
static setCustomHistoryPath(filePath) {
|
|
26
|
+
// Convert .json path to .db path
|
|
27
|
+
ChatHistoryManager.customHistoryPath = filePath.replace(/\.json$/, ".db");
|
|
28
|
+
}
|
|
29
|
+
static getInstance() {
|
|
30
|
+
if (!ChatHistoryManager.instance) {
|
|
31
|
+
ChatHistoryManager.instance = new ChatHistoryManager();
|
|
32
|
+
}
|
|
33
|
+
return ChatHistoryManager.instance;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get the database file path
|
|
37
|
+
*/
|
|
38
|
+
getContextFilePath() {
|
|
39
|
+
return this.dbPath;
|
|
40
|
+
}
|
|
41
|
+
ensureHistoryDirExists() {
|
|
42
|
+
const dir = path.dirname(this.dbPath);
|
|
43
|
+
if (!fs.existsSync(dir)) {
|
|
44
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Migrate from JSON files to SQLite if JSON files exist and DB is empty
|
|
49
|
+
*/
|
|
50
|
+
migrateFromJSONIfNeeded() {
|
|
51
|
+
try {
|
|
52
|
+
// Check if database is empty
|
|
53
|
+
const count = this.db.prepare("SELECT COUNT(*) as count FROM messages").get();
|
|
54
|
+
if (count.count > 0) {
|
|
55
|
+
// Database already has data, skip migration
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Check for old JSON files
|
|
59
|
+
const jsonPath = this.dbPath.replace(".db", ".json");
|
|
60
|
+
const messagesJsonPath = jsonPath.replace(".json", ".messages.json");
|
|
61
|
+
const stateJsonPath = jsonPath.replace(".json", ".state.json");
|
|
62
|
+
if (!fs.existsSync(jsonPath) && !fs.existsSync(messagesJsonPath)) {
|
|
63
|
+
// No JSON files to migrate
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
console.log("Migrating from JSON to SQLite...");
|
|
67
|
+
// Migrate chat history
|
|
68
|
+
if (fs.existsSync(jsonPath)) {
|
|
69
|
+
const data = fs.readFileSync(jsonPath, "utf-8");
|
|
70
|
+
const entries = JSON.parse(data);
|
|
71
|
+
for (const entry of entries) {
|
|
72
|
+
this.addMessage({
|
|
73
|
+
type: entry.type,
|
|
74
|
+
content: entry.content,
|
|
75
|
+
timestamp: new Date(entry.timestamp),
|
|
76
|
+
tool_calls: entry.tool_calls,
|
|
77
|
+
toolCall: entry.toolCall,
|
|
78
|
+
toolResult: entry.toolResult,
|
|
79
|
+
isStreaming: entry.isStreaming,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// Rename JSON file to .migrated
|
|
83
|
+
fs.renameSync(jsonPath, `${jsonPath}.migrated`);
|
|
84
|
+
}
|
|
85
|
+
// Migrate messages log if exists
|
|
86
|
+
if (fs.existsSync(messagesJsonPath)) {
|
|
87
|
+
fs.renameSync(messagesJsonPath, `${messagesJsonPath}.migrated`);
|
|
88
|
+
}
|
|
89
|
+
// Migrate session state
|
|
90
|
+
if (fs.existsSync(stateJsonPath)) {
|
|
91
|
+
const stateData = fs.readFileSync(stateJsonPath, "utf-8");
|
|
92
|
+
const state = JSON.parse(stateData);
|
|
93
|
+
this.saveSessionState(state);
|
|
94
|
+
fs.renameSync(stateJsonPath, `${stateJsonPath}.migrated`);
|
|
95
|
+
}
|
|
96
|
+
console.log("Migration complete!");
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.warn("Failed to migrate from JSON:", error);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Load chat history from database
|
|
104
|
+
*/
|
|
105
|
+
loadHistory() {
|
|
106
|
+
try {
|
|
107
|
+
const stmt = this.db.prepare(`
|
|
108
|
+
SELECT type, content, tool_calls, tool_call, tool_result, is_streaming, timestamp
|
|
109
|
+
FROM messages
|
|
110
|
+
ORDER BY id ASC
|
|
111
|
+
`);
|
|
112
|
+
const rows = stmt.all();
|
|
113
|
+
return rows.map(row => ({
|
|
114
|
+
type: row.type,
|
|
115
|
+
content: row.content || undefined,
|
|
116
|
+
timestamp: new Date(row.timestamp),
|
|
117
|
+
tool_calls: row.tool_calls ? JSON.parse(row.tool_calls) : undefined,
|
|
118
|
+
toolCall: row.tool_call ? JSON.parse(row.tool_call) : undefined,
|
|
119
|
+
toolResult: row.tool_result ? JSON.parse(row.tool_result) : undefined,
|
|
120
|
+
isStreaming: row.is_streaming === 1,
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
console.warn("Failed to load chat history:", error);
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Add a single message to the database (atomic operation)
|
|
130
|
+
*/
|
|
131
|
+
addMessage(entry) {
|
|
132
|
+
try {
|
|
133
|
+
const stmt = this.db.prepare(`
|
|
134
|
+
INSERT INTO messages (message_id, type, content, tool_calls, tool_call, tool_result, is_streaming, timestamp)
|
|
135
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
136
|
+
`);
|
|
137
|
+
const messageId = `${entry.type}-${entry.timestamp.getTime()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
138
|
+
stmt.run(messageId, entry.type, entry.content || null, entry.tool_calls ? JSON.stringify(entry.tool_calls) : null, entry.toolCall ? JSON.stringify(entry.toolCall) : null, entry.toolResult ? JSON.stringify(entry.toolResult) : null, entry.isStreaming ? 1 : 0, entry.timestamp.getTime());
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
console.warn("Failed to add message:", error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Save chat history to database (replaces entire history)
|
|
146
|
+
* This maintains backward compatibility but is less efficient than addMessage
|
|
147
|
+
*/
|
|
148
|
+
saveHistory(history) {
|
|
149
|
+
try {
|
|
150
|
+
// Use transaction for atomicity
|
|
151
|
+
DatabaseConnection.transaction(this.db, () => {
|
|
152
|
+
// Clear existing messages
|
|
153
|
+
this.db.prepare("DELETE FROM messages").run();
|
|
154
|
+
// Insert all messages
|
|
155
|
+
const stmt = this.db.prepare(`
|
|
156
|
+
INSERT INTO messages (message_id, type, content, tool_calls, tool_call, tool_result, is_streaming, timestamp)
|
|
157
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
158
|
+
`);
|
|
159
|
+
for (const entry of history) {
|
|
160
|
+
const messageId = `${entry.type}-${entry.timestamp.getTime()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
161
|
+
stmt.run(messageId, entry.type, entry.content || null, entry.tool_calls ? JSON.stringify(entry.tool_calls) : null, entry.toolCall ? JSON.stringify(entry.toolCall) : null, entry.toolResult ? JSON.stringify(entry.toolResult) : null, entry.isStreaming ? 1 : 0, entry.timestamp.getTime());
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
console.warn("Failed to save chat history:", error);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Save raw messages log (for backward compatibility)
|
|
171
|
+
* In SQLite version, this is stored alongside the messages
|
|
172
|
+
*/
|
|
173
|
+
saveMessages(messages) {
|
|
174
|
+
// Messages are already saved in the main messages table
|
|
175
|
+
// This method is kept for backward compatibility but doesn't need to do anything
|
|
176
|
+
// The messages are retrievable via loadHistory()
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Create a backup of the database
|
|
180
|
+
*/
|
|
181
|
+
backupHistory() {
|
|
182
|
+
try {
|
|
183
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
184
|
+
const backupPath = this.dbPath.replace(".db", `.backup-${timestamp}.db`);
|
|
185
|
+
DatabaseConnection.backup(this.dbPath, backupPath);
|
|
186
|
+
// Also backup debug log if it exists
|
|
187
|
+
const debugLogPath = this.dbPath.replace(".db", ".debug.log");
|
|
188
|
+
if (fs.existsSync(debugLogPath)) {
|
|
189
|
+
const debugBackupPath = debugLogPath.replace(".log", `.backup-${timestamp}.log`);
|
|
190
|
+
fs.copyFileSync(debugLogPath, debugBackupPath);
|
|
191
|
+
}
|
|
192
|
+
return backupPath;
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
console.warn("Failed to backup database:", error);
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Clear all data from database with automatic backup
|
|
201
|
+
*/
|
|
202
|
+
clearHistory() {
|
|
203
|
+
try {
|
|
204
|
+
// Create backup first
|
|
205
|
+
this.backupHistory();
|
|
206
|
+
// Clear all tables
|
|
207
|
+
DatabaseConnection.transaction(this.db, () => {
|
|
208
|
+
this.db.prepare("DELETE FROM messages").run();
|
|
209
|
+
this.db.prepare("DELETE FROM session_state").run();
|
|
210
|
+
this.db.prepare("DELETE FROM session_metadata").run();
|
|
211
|
+
});
|
|
212
|
+
// Clear debug log
|
|
213
|
+
const debugLogPath = this.dbPath.replace(".db", ".debug.log");
|
|
214
|
+
if (fs.existsSync(debugLogPath)) {
|
|
215
|
+
fs.unlinkSync(debugLogPath);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
console.warn("Failed to clear history:", error);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Save session state to database
|
|
224
|
+
*/
|
|
225
|
+
saveSessionState(state) {
|
|
226
|
+
try {
|
|
227
|
+
const stmt = this.db.prepare(`
|
|
228
|
+
INSERT OR REPLACE INTO session_state (key, value, updated_at)
|
|
229
|
+
VALUES (?, ?, ?)
|
|
230
|
+
`);
|
|
231
|
+
const now = Date.now();
|
|
232
|
+
for (const [key, value] of Object.entries(state)) {
|
|
233
|
+
stmt.run(key, JSON.stringify(value), now);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
console.warn("Failed to save session state:", error);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Load session state from database
|
|
242
|
+
*/
|
|
243
|
+
loadSessionState() {
|
|
244
|
+
try {
|
|
245
|
+
const stmt = this.db.prepare("SELECT key, value FROM session_state");
|
|
246
|
+
const rows = stmt.all();
|
|
247
|
+
if (rows.length === 0) {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
const state = {};
|
|
251
|
+
for (const row of rows) {
|
|
252
|
+
state[row.key] = JSON.parse(row.value);
|
|
253
|
+
}
|
|
254
|
+
return state;
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
console.warn("Failed to load session state:", error);
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Get the debug log file path
|
|
263
|
+
*/
|
|
264
|
+
getDebugLogPath() {
|
|
265
|
+
return this.dbPath.replace(".db", ".debug.log");
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Static method to get debug log path
|
|
269
|
+
*/
|
|
270
|
+
static getDebugLogPath() {
|
|
271
|
+
const instance = ChatHistoryManager.getInstance();
|
|
272
|
+
return instance.getDebugLogPath();
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Get messages in a specific range (for pagination)
|
|
276
|
+
*/
|
|
277
|
+
getMessagesRange(offset, limit) {
|
|
278
|
+
try {
|
|
279
|
+
const stmt = this.db.prepare(`
|
|
280
|
+
SELECT type, content, tool_calls, tool_call, tool_result, is_streaming, timestamp
|
|
281
|
+
FROM messages
|
|
282
|
+
ORDER BY id ASC
|
|
283
|
+
LIMIT ? OFFSET ?
|
|
284
|
+
`);
|
|
285
|
+
const rows = stmt.all(limit, offset);
|
|
286
|
+
return rows.map(row => ({
|
|
287
|
+
type: row.type,
|
|
288
|
+
content: row.content || undefined,
|
|
289
|
+
timestamp: new Date(row.timestamp),
|
|
290
|
+
tool_calls: row.tool_calls ? JSON.parse(row.tool_calls) : undefined,
|
|
291
|
+
toolCall: row.tool_call ? JSON.parse(row.tool_call) : undefined,
|
|
292
|
+
toolResult: row.tool_result ? JSON.parse(row.tool_result) : undefined,
|
|
293
|
+
isStreaming: row.is_streaming === 1,
|
|
294
|
+
}));
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
console.warn("Failed to get messages range:", error);
|
|
298
|
+
return [];
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Get the total number of messages
|
|
303
|
+
*/
|
|
304
|
+
getMessageCount() {
|
|
305
|
+
try {
|
|
306
|
+
const result = this.db.prepare("SELECT COUNT(*) as count FROM messages").get();
|
|
307
|
+
return result.count;
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
console.warn("Failed to get message count:", error);
|
|
311
|
+
return 0;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Export current database to JSON format (for debugging/backup)
|
|
316
|
+
*/
|
|
317
|
+
exportToJSON() {
|
|
318
|
+
try {
|
|
319
|
+
const history = this.loadHistory();
|
|
320
|
+
const serialized = history.map(entry => ({
|
|
321
|
+
...entry,
|
|
322
|
+
timestamp: entry.timestamp.toISOString(),
|
|
323
|
+
}));
|
|
324
|
+
const exportPath = this.dbPath.replace(".db", ".export.json");
|
|
325
|
+
fs.writeFileSync(exportPath, JSON.stringify(serialized, null, 2));
|
|
326
|
+
return exportPath;
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
console.warn("Failed to export to JSON:", error);
|
|
330
|
+
throw error;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=chat-history-manager-sqlite.js.map
|