@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.
Files changed (204) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +497 -0
  3. package/dist/agent/grok-agent.d.ts +250 -0
  4. package/dist/agent/grok-agent.js +2480 -0
  5. package/dist/agent/grok-agent.js.map +1 -0
  6. package/dist/agent/index.d.ts +14 -0
  7. package/dist/agent/index.js +136 -0
  8. package/dist/agent/index.js.map +1 -0
  9. package/dist/commands/mcp.d.ts +2 -0
  10. package/dist/commands/mcp.js +239 -0
  11. package/dist/commands/mcp.js.map +1 -0
  12. package/dist/grok/client.d.ts +55 -0
  13. package/dist/grok/client.js +276 -0
  14. package/dist/grok/client.js.map +1 -0
  15. package/dist/grok/tools.d.ts +8 -0
  16. package/dist/grok/tools.js +878 -0
  17. package/dist/grok/tools.js.map +1 -0
  18. package/dist/hooks/use-enhanced-input.d.ts +38 -0
  19. package/dist/hooks/use-enhanced-input.js +228 -0
  20. package/dist/hooks/use-enhanced-input.js.map +1 -0
  21. package/dist/hooks/use-input-handler.d.ts +36 -0
  22. package/dist/hooks/use-input-handler.js +1099 -0
  23. package/dist/hooks/use-input-handler.js.map +1 -0
  24. package/dist/hooks/use-input-history.d.ts +9 -0
  25. package/dist/hooks/use-input-history.js +61 -0
  26. package/dist/hooks/use-input-history.js.map +1 -0
  27. package/dist/index.d.ts +2 -0
  28. package/dist/index.js +869 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/mcp/client.d.ts +41 -0
  31. package/dist/mcp/client.js +224 -0
  32. package/dist/mcp/client.js.map +1 -0
  33. package/dist/mcp/config.d.ts +13 -0
  34. package/dist/mcp/config.js +56 -0
  35. package/dist/mcp/config.js.map +1 -0
  36. package/dist/mcp/transports.d.ts +53 -0
  37. package/dist/mcp/transports.js +256 -0
  38. package/dist/mcp/transports.js.map +1 -0
  39. package/dist/tools/character-tool.d.ts +27 -0
  40. package/dist/tools/character-tool.js +194 -0
  41. package/dist/tools/character-tool.js.map +1 -0
  42. package/dist/tools/clear-cache-tool.d.ts +14 -0
  43. package/dist/tools/clear-cache-tool.js +82 -0
  44. package/dist/tools/clear-cache-tool.js.map +1 -0
  45. package/dist/tools/confirmation-tool.d.ts +16 -0
  46. package/dist/tools/confirmation-tool.js +72 -0
  47. package/dist/tools/confirmation-tool.js.map +1 -0
  48. package/dist/tools/env-tool.d.ts +17 -0
  49. package/dist/tools/env-tool.js +89 -0
  50. package/dist/tools/env-tool.js.map +1 -0
  51. package/dist/tools/file-conversion-tool.d.ts +16 -0
  52. package/dist/tools/file-conversion-tool.js +181 -0
  53. package/dist/tools/file-conversion-tool.js.map +1 -0
  54. package/dist/tools/image-tool.d.ts +22 -0
  55. package/dist/tools/image-tool.js +268 -0
  56. package/dist/tools/image-tool.js.map +1 -0
  57. package/dist/tools/index.d.ts +14 -0
  58. package/dist/tools/index.js +15 -0
  59. package/dist/tools/index.js.map +1 -0
  60. package/dist/tools/internet-tool.d.ts +11 -0
  61. package/dist/tools/internet-tool.js +108 -0
  62. package/dist/tools/internet-tool.js.map +1 -0
  63. package/dist/tools/introspect-tool.d.ts +11 -0
  64. package/dist/tools/introspect-tool.js +243 -0
  65. package/dist/tools/introspect-tool.js.map +1 -0
  66. package/dist/tools/morph-editor.d.ts +38 -0
  67. package/dist/tools/morph-editor.js +318 -0
  68. package/dist/tools/morph-editor.js.map +1 -0
  69. package/dist/tools/restart-tool.d.ts +7 -0
  70. package/dist/tools/restart-tool.js +24 -0
  71. package/dist/tools/restart-tool.js.map +1 -0
  72. package/dist/tools/search.d.ts +71 -0
  73. package/dist/tools/search.js +340 -0
  74. package/dist/tools/search.js.map +1 -0
  75. package/dist/tools/task-tool.d.ts +19 -0
  76. package/dist/tools/task-tool.js +115 -0
  77. package/dist/tools/task-tool.js.map +1 -0
  78. package/dist/tools/text-editor.d.ts +35 -0
  79. package/dist/tools/text-editor.js +669 -0
  80. package/dist/tools/text-editor.js.map +1 -0
  81. package/dist/tools/tool-discovery.d.ts +20 -0
  82. package/dist/tools/tool-discovery.js +45 -0
  83. package/dist/tools/tool-discovery.js.map +1 -0
  84. package/dist/tools/zsh.d.ts +13 -0
  85. package/dist/tools/zsh.js +168 -0
  86. package/dist/tools/zsh.js.map +1 -0
  87. package/dist/types/index.d.ts +31 -0
  88. package/dist/types/index.js +2 -0
  89. package/dist/types/index.js.map +1 -0
  90. package/dist/ui/app.d.ts +7 -0
  91. package/dist/ui/app.js +99 -0
  92. package/dist/ui/app.js.map +1 -0
  93. package/dist/ui/components/active-task-status.d.ts +7 -0
  94. package/dist/ui/components/active-task-status.js +37 -0
  95. package/dist/ui/components/active-task-status.js.map +1 -0
  96. package/dist/ui/components/api-key-input.d.ts +7 -0
  97. package/dist/ui/components/api-key-input.js +80 -0
  98. package/dist/ui/components/api-key-input.js.map +1 -0
  99. package/dist/ui/components/backend-status.d.ts +7 -0
  100. package/dist/ui/components/backend-status.js +85 -0
  101. package/dist/ui/components/backend-status.js.map +1 -0
  102. package/dist/ui/components/chat-history.d.ts +8 -0
  103. package/dist/ui/components/chat-history.js +187 -0
  104. package/dist/ui/components/chat-history.js.map +1 -0
  105. package/dist/ui/components/chat-input.d.ts +9 -0
  106. package/dist/ui/components/chat-input.js +63 -0
  107. package/dist/ui/components/chat-input.js.map +1 -0
  108. package/dist/ui/components/chat-interface.d.ts +9 -0
  109. package/dist/ui/components/chat-interface.js +389 -0
  110. package/dist/ui/components/chat-interface.js.map +1 -0
  111. package/dist/ui/components/command-suggestions.d.ts +17 -0
  112. package/dist/ui/components/command-suggestions.js +22 -0
  113. package/dist/ui/components/command-suggestions.js.map +1 -0
  114. package/dist/ui/components/confirmation-dialog.d.ts +11 -0
  115. package/dist/ui/components/confirmation-dialog.js +105 -0
  116. package/dist/ui/components/confirmation-dialog.js.map +1 -0
  117. package/dist/ui/components/context-status.d.ts +7 -0
  118. package/dist/ui/components/context-status.js +36 -0
  119. package/dist/ui/components/context-status.js.map +1 -0
  120. package/dist/ui/components/diff-renderer.d.ts +13 -0
  121. package/dist/ui/components/diff-renderer.js +206 -0
  122. package/dist/ui/components/diff-renderer.js.map +1 -0
  123. package/dist/ui/components/loading-spinner.d.ts +8 -0
  124. package/dist/ui/components/loading-spinner.js +64 -0
  125. package/dist/ui/components/loading-spinner.js.map +1 -0
  126. package/dist/ui/components/mcp-status.d.ts +5 -0
  127. package/dist/ui/components/mcp-status.js +57 -0
  128. package/dist/ui/components/mcp-status.js.map +1 -0
  129. package/dist/ui/components/model-selection.d.ts +12 -0
  130. package/dist/ui/components/model-selection.js +17 -0
  131. package/dist/ui/components/model-selection.js.map +1 -0
  132. package/dist/ui/components/mood-status.d.ts +7 -0
  133. package/dist/ui/components/mood-status.js +34 -0
  134. package/dist/ui/components/mood-status.js.map +1 -0
  135. package/dist/ui/components/persona-status.d.ts +7 -0
  136. package/dist/ui/components/persona-status.js +34 -0
  137. package/dist/ui/components/persona-status.js.map +1 -0
  138. package/dist/ui/shared/max-sized-box.d.ts +8 -0
  139. package/dist/ui/shared/max-sized-box.js +6 -0
  140. package/dist/ui/shared/max-sized-box.js.map +1 -0
  141. package/dist/ui/utils/code-colorizer.d.ts +2 -0
  142. package/dist/ui/utils/code-colorizer.js +7 -0
  143. package/dist/ui/utils/code-colorizer.js.map +1 -0
  144. package/dist/ui/utils/colors.d.ts +14 -0
  145. package/dist/ui/utils/colors.js +15 -0
  146. package/dist/ui/utils/colors.js.map +1 -0
  147. package/dist/ui/utils/markdown-renderer.d.ts +4 -0
  148. package/dist/ui/utils/markdown-renderer.js +40 -0
  149. package/dist/ui/utils/markdown-renderer.js.map +1 -0
  150. package/dist/utils/auth-helper.d.ts +63 -0
  151. package/dist/utils/auth-helper.js +129 -0
  152. package/dist/utils/auth-helper.js.map +1 -0
  153. package/dist/utils/chat-history-manager-sqlite.d.ts +92 -0
  154. package/dist/utils/chat-history-manager-sqlite.js +334 -0
  155. package/dist/utils/chat-history-manager-sqlite.js.map +1 -0
  156. package/dist/utils/chat-history-manager.d.ts +87 -0
  157. package/dist/utils/chat-history-manager.js +273 -0
  158. package/dist/utils/chat-history-manager.js.map +1 -0
  159. package/dist/utils/chat-history-manager.json-backup.d.ts +69 -0
  160. package/dist/utils/chat-history-manager.json-backup.js +215 -0
  161. package/dist/utils/chat-history-manager.json-backup.js.map +1 -0
  162. package/dist/utils/confirmation-service.d.ts +46 -0
  163. package/dist/utils/confirmation-service.js +165 -0
  164. package/dist/utils/confirmation-service.js.map +1 -0
  165. package/dist/utils/custom-instructions.d.ts +1 -0
  166. package/dist/utils/custom-instructions.js +30 -0
  167. package/dist/utils/custom-instructions.js.map +1 -0
  168. package/dist/utils/database-connection.d.ts +27 -0
  169. package/dist/utils/database-connection.js +81 -0
  170. package/dist/utils/database-connection.js.map +1 -0
  171. package/dist/utils/database-schema.d.ts +17 -0
  172. package/dist/utils/database-schema.js +93 -0
  173. package/dist/utils/database-schema.js.map +1 -0
  174. package/dist/utils/error-logger.d.ts +13 -0
  175. package/dist/utils/error-logger.js +56 -0
  176. package/dist/utils/error-logger.js.map +1 -0
  177. package/dist/utils/hook-executor.d.ts +59 -0
  178. package/dist/utils/hook-executor.js +351 -0
  179. package/dist/utils/hook-executor.js.map +1 -0
  180. package/dist/utils/model-config.d.ts +28 -0
  181. package/dist/utils/model-config.js +42 -0
  182. package/dist/utils/model-config.js.map +1 -0
  183. package/dist/utils/path-utils.d.ts +4 -0
  184. package/dist/utils/path-utils.js +12 -0
  185. package/dist/utils/path-utils.js.map +1 -0
  186. package/dist/utils/settings-manager.d.ts +169 -0
  187. package/dist/utils/settings-manager.js +403 -0
  188. package/dist/utils/settings-manager.js.map +1 -0
  189. package/dist/utils/settings.d.ts +1 -0
  190. package/dist/utils/settings.js +4 -0
  191. package/dist/utils/settings.js.map +1 -0
  192. package/dist/utils/slash-commands.d.ts +25 -0
  193. package/dist/utils/slash-commands.js +454 -0
  194. package/dist/utils/slash-commands.js.map +1 -0
  195. package/dist/utils/startup-hook.d.ts +13 -0
  196. package/dist/utils/startup-hook.js +44 -0
  197. package/dist/utils/startup-hook.js.map +1 -0
  198. package/dist/utils/text-utils.d.ts +80 -0
  199. package/dist/utils/text-utils.js +182 -0
  200. package/dist/utils/text-utils.js.map +1 -0
  201. package/dist/utils/token-counter.d.ts +33 -0
  202. package/dist/utils/token-counter.js +78 -0
  203. package/dist/utils/token-counter.js.map +1 -0
  204. 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