@open-mercato/ai-assistant 0.4.2-canary-c02407ff85

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 (193) hide show
  1. package/AGENTS.md +1090 -0
  2. package/README.md +607 -0
  3. package/build.mjs +92 -0
  4. package/dist/di.js +8 -0
  5. package/dist/di.js.map +7 -0
  6. package/dist/frontend/components/CommandPalette/CommandFooter.js +80 -0
  7. package/dist/frontend/components/CommandPalette/CommandFooter.js.map +7 -0
  8. package/dist/frontend/components/CommandPalette/CommandHeader.js +53 -0
  9. package/dist/frontend/components/CommandPalette/CommandHeader.js.map +7 -0
  10. package/dist/frontend/components/CommandPalette/CommandInput.js +29 -0
  11. package/dist/frontend/components/CommandPalette/CommandInput.js.map +7 -0
  12. package/dist/frontend/components/CommandPalette/CommandItem.js +92 -0
  13. package/dist/frontend/components/CommandPalette/CommandItem.js.map +7 -0
  14. package/dist/frontend/components/CommandPalette/CommandPalette.js +244 -0
  15. package/dist/frontend/components/CommandPalette/CommandPalette.js.map +7 -0
  16. package/dist/frontend/components/CommandPalette/CommandPaletteProvider.js +42 -0
  17. package/dist/frontend/components/CommandPalette/CommandPaletteProvider.js.map +7 -0
  18. package/dist/frontend/components/CommandPalette/CommandPaletteWrapper.js +18 -0
  19. package/dist/frontend/components/CommandPalette/CommandPaletteWrapper.js.map +7 -0
  20. package/dist/frontend/components/CommandPalette/DebugPanel.js +215 -0
  21. package/dist/frontend/components/CommandPalette/DebugPanel.js.map +7 -0
  22. package/dist/frontend/components/CommandPalette/MessageBubble.js +64 -0
  23. package/dist/frontend/components/CommandPalette/MessageBubble.js.map +7 -0
  24. package/dist/frontend/components/CommandPalette/ToolCallConfirmation.js +91 -0
  25. package/dist/frontend/components/CommandPalette/ToolCallConfirmation.js.map +7 -0
  26. package/dist/frontend/components/CommandPalette/ToolCallDisplay.js +47 -0
  27. package/dist/frontend/components/CommandPalette/ToolCallDisplay.js.map +7 -0
  28. package/dist/frontend/components/CommandPalette/ToolChatPage.js +74 -0
  29. package/dist/frontend/components/CommandPalette/ToolChatPage.js.map +7 -0
  30. package/dist/frontend/components/CommandPalette/index.js +28 -0
  31. package/dist/frontend/components/CommandPalette/index.js.map +7 -0
  32. package/dist/frontend/constants.js +41 -0
  33. package/dist/frontend/constants.js.map +7 -0
  34. package/dist/frontend/hooks/index.js +13 -0
  35. package/dist/frontend/hooks/index.js.map +7 -0
  36. package/dist/frontend/hooks/useCommandPalette.js +1094 -0
  37. package/dist/frontend/hooks/useCommandPalette.js.map +7 -0
  38. package/dist/frontend/hooks/useMcpTools.js +66 -0
  39. package/dist/frontend/hooks/useMcpTools.js.map +7 -0
  40. package/dist/frontend/hooks/usePageContext.js +48 -0
  41. package/dist/frontend/hooks/usePageContext.js.map +7 -0
  42. package/dist/frontend/hooks/useRecentActions.js +56 -0
  43. package/dist/frontend/hooks/useRecentActions.js.map +7 -0
  44. package/dist/frontend/hooks/useRecentTools.js +55 -0
  45. package/dist/frontend/hooks/useRecentTools.js.map +7 -0
  46. package/dist/frontend/index.js +35 -0
  47. package/dist/frontend/index.js.map +7 -0
  48. package/dist/frontend/types.js +1 -0
  49. package/dist/frontend/types.js.map +7 -0
  50. package/dist/frontend/utils/index.js +7 -0
  51. package/dist/frontend/utils/index.js.map +7 -0
  52. package/dist/frontend/utils/toolMatcher.js +95 -0
  53. package/dist/frontend/utils/toolMatcher.js.map +7 -0
  54. package/dist/index.js +57 -0
  55. package/dist/index.js.map +7 -0
  56. package/dist/modules/ai_assistant/acl.js +14 -0
  57. package/dist/modules/ai_assistant/acl.js.map +7 -0
  58. package/dist/modules/ai_assistant/api/chat/route.js +152 -0
  59. package/dist/modules/ai_assistant/api/chat/route.js.map +7 -0
  60. package/dist/modules/ai_assistant/api/health/route.js +27 -0
  61. package/dist/modules/ai_assistant/api/health/route.js.map +7 -0
  62. package/dist/modules/ai_assistant/api/route/route.js +123 -0
  63. package/dist/modules/ai_assistant/api/route/route.js.map +7 -0
  64. package/dist/modules/ai_assistant/api/settings/route.js +60 -0
  65. package/dist/modules/ai_assistant/api/settings/route.js.map +7 -0
  66. package/dist/modules/ai_assistant/api/tools/execute/route.js +58 -0
  67. package/dist/modules/ai_assistant/api/tools/execute/route.js.map +7 -0
  68. package/dist/modules/ai_assistant/api/tools/route.js +48 -0
  69. package/dist/modules/ai_assistant/api/tools/route.js.map +7 -0
  70. package/dist/modules/ai_assistant/backend/config/ai-assistant/page.js +10 -0
  71. package/dist/modules/ai_assistant/backend/config/ai-assistant/page.js.map +7 -0
  72. package/dist/modules/ai_assistant/backend/config/ai-assistant/page.meta.js +28 -0
  73. package/dist/modules/ai_assistant/backend/config/ai-assistant/page.meta.js.map +7 -0
  74. package/dist/modules/ai_assistant/cli.js +192 -0
  75. package/dist/modules/ai_assistant/cli.js.map +7 -0
  76. package/dist/modules/ai_assistant/di.js +11 -0
  77. package/dist/modules/ai_assistant/di.js.map +7 -0
  78. package/dist/modules/ai_assistant/frontend/components/AiAssistantSettingsPageClient.js +257 -0
  79. package/dist/modules/ai_assistant/frontend/components/AiAssistantSettingsPageClient.js.map +7 -0
  80. package/dist/modules/ai_assistant/index.js +13 -0
  81. package/dist/modules/ai_assistant/index.js.map +7 -0
  82. package/dist/modules/ai_assistant/lib/ai-sdk.js +13 -0
  83. package/dist/modules/ai_assistant/lib/ai-sdk.js.map +7 -0
  84. package/dist/modules/ai_assistant/lib/api-discovery-tools.js +249 -0
  85. package/dist/modules/ai_assistant/lib/api-discovery-tools.js.map +7 -0
  86. package/dist/modules/ai_assistant/lib/api-endpoint-index-config.js +177 -0
  87. package/dist/modules/ai_assistant/lib/api-endpoint-index-config.js.map +7 -0
  88. package/dist/modules/ai_assistant/lib/api-endpoint-index.js +210 -0
  89. package/dist/modules/ai_assistant/lib/api-endpoint-index.js.map +7 -0
  90. package/dist/modules/ai_assistant/lib/auth.js +87 -0
  91. package/dist/modules/ai_assistant/lib/auth.js.map +7 -0
  92. package/dist/modules/ai_assistant/lib/chat-config.js +117 -0
  93. package/dist/modules/ai_assistant/lib/chat-config.js.map +7 -0
  94. package/dist/modules/ai_assistant/lib/client-factory.js +60 -0
  95. package/dist/modules/ai_assistant/lib/client-factory.js.map +7 -0
  96. package/dist/modules/ai_assistant/lib/http-server.js +367 -0
  97. package/dist/modules/ai_assistant/lib/http-server.js.map +7 -0
  98. package/dist/modules/ai_assistant/lib/in-process-client.js +126 -0
  99. package/dist/modules/ai_assistant/lib/in-process-client.js.map +7 -0
  100. package/dist/modules/ai_assistant/lib/mcp-client.js +146 -0
  101. package/dist/modules/ai_assistant/lib/mcp-client.js.map +7 -0
  102. package/dist/modules/ai_assistant/lib/mcp-dev-server.js +283 -0
  103. package/dist/modules/ai_assistant/lib/mcp-dev-server.js.map +7 -0
  104. package/dist/modules/ai_assistant/lib/mcp-server-config.js +160 -0
  105. package/dist/modules/ai_assistant/lib/mcp-server-config.js.map +7 -0
  106. package/dist/modules/ai_assistant/lib/mcp-server.js +156 -0
  107. package/dist/modules/ai_assistant/lib/mcp-server.js.map +7 -0
  108. package/dist/modules/ai_assistant/lib/mcp-tool-adapter.js +44 -0
  109. package/dist/modules/ai_assistant/lib/mcp-tool-adapter.js.map +7 -0
  110. package/dist/modules/ai_assistant/lib/opencode-client.js +247 -0
  111. package/dist/modules/ai_assistant/lib/opencode-client.js.map +7 -0
  112. package/dist/modules/ai_assistant/lib/opencode-handlers.js +398 -0
  113. package/dist/modules/ai_assistant/lib/opencode-handlers.js.map +7 -0
  114. package/dist/modules/ai_assistant/lib/schema-utils.js +94 -0
  115. package/dist/modules/ai_assistant/lib/schema-utils.js.map +7 -0
  116. package/dist/modules/ai_assistant/lib/tool-executor.js +55 -0
  117. package/dist/modules/ai_assistant/lib/tool-executor.js.map +7 -0
  118. package/dist/modules/ai_assistant/lib/tool-index-config.js +125 -0
  119. package/dist/modules/ai_assistant/lib/tool-index-config.js.map +7 -0
  120. package/dist/modules/ai_assistant/lib/tool-loader.js +88 -0
  121. package/dist/modules/ai_assistant/lib/tool-loader.js.map +7 -0
  122. package/dist/modules/ai_assistant/lib/tool-registry.js +65 -0
  123. package/dist/modules/ai_assistant/lib/tool-registry.js.map +7 -0
  124. package/dist/modules/ai_assistant/lib/tool-search.js +192 -0
  125. package/dist/modules/ai_assistant/lib/tool-search.js.map +7 -0
  126. package/dist/modules/ai_assistant/lib/types.js +1 -0
  127. package/dist/modules/ai_assistant/lib/types.js.map +7 -0
  128. package/package.json +108 -0
  129. package/src/di.ts +11 -0
  130. package/src/frontend/components/CommandPalette/CommandFooter.tsx +113 -0
  131. package/src/frontend/components/CommandPalette/CommandHeader.tsx +76 -0
  132. package/src/frontend/components/CommandPalette/CommandInput.tsx +50 -0
  133. package/src/frontend/components/CommandPalette/CommandItem.tsx +111 -0
  134. package/src/frontend/components/CommandPalette/CommandPalette.tsx +276 -0
  135. package/src/frontend/components/CommandPalette/CommandPaletteProvider.tsx +60 -0
  136. package/src/frontend/components/CommandPalette/CommandPaletteWrapper.tsx +21 -0
  137. package/src/frontend/components/CommandPalette/DebugPanel.tsx +257 -0
  138. package/src/frontend/components/CommandPalette/MessageBubble.tsx +73 -0
  139. package/src/frontend/components/CommandPalette/ToolCallConfirmation.tsx +130 -0
  140. package/src/frontend/components/CommandPalette/ToolCallDisplay.tsx +57 -0
  141. package/src/frontend/components/CommandPalette/ToolChatPage.tsx +125 -0
  142. package/src/frontend/components/CommandPalette/index.ts +14 -0
  143. package/src/frontend/constants.ts +35 -0
  144. package/src/frontend/hooks/index.ts +5 -0
  145. package/src/frontend/hooks/useCommandPalette.ts +1389 -0
  146. package/src/frontend/hooks/useMcpTools.ts +73 -0
  147. package/src/frontend/hooks/usePageContext.ts +61 -0
  148. package/src/frontend/hooks/useRecentActions.ts +64 -0
  149. package/src/frontend/hooks/useRecentTools.ts +69 -0
  150. package/src/frontend/index.ts +39 -0
  151. package/src/frontend/types.ts +260 -0
  152. package/src/frontend/utils/index.ts +1 -0
  153. package/src/frontend/utils/toolMatcher.ts +127 -0
  154. package/src/index.ts +92 -0
  155. package/src/modules/ai_assistant/acl.ts +10 -0
  156. package/src/modules/ai_assistant/api/chat/route.ts +213 -0
  157. package/src/modules/ai_assistant/api/health/route.ts +30 -0
  158. package/src/modules/ai_assistant/api/route/route.ts +149 -0
  159. package/src/modules/ai_assistant/api/settings/route.ts +73 -0
  160. package/src/modules/ai_assistant/api/tools/execute/route.ts +71 -0
  161. package/src/modules/ai_assistant/api/tools/route.ts +57 -0
  162. package/src/modules/ai_assistant/backend/config/ai-assistant/page.meta.ts +26 -0
  163. package/src/modules/ai_assistant/backend/config/ai-assistant/page.tsx +12 -0
  164. package/src/modules/ai_assistant/cli.ts +233 -0
  165. package/src/modules/ai_assistant/di.ts +9 -0
  166. package/src/modules/ai_assistant/frontend/components/AiAssistantSettingsPageClient.tsx +418 -0
  167. package/src/modules/ai_assistant/index.ts +11 -0
  168. package/src/modules/ai_assistant/lib/ai-sdk.ts +5 -0
  169. package/src/modules/ai_assistant/lib/api-discovery-tools.ts +334 -0
  170. package/src/modules/ai_assistant/lib/api-endpoint-index-config.ts +243 -0
  171. package/src/modules/ai_assistant/lib/api-endpoint-index.ts +381 -0
  172. package/src/modules/ai_assistant/lib/auth.ts +185 -0
  173. package/src/modules/ai_assistant/lib/chat-config.ts +152 -0
  174. package/src/modules/ai_assistant/lib/client-factory.ts +130 -0
  175. package/src/modules/ai_assistant/lib/http-server.ts +498 -0
  176. package/src/modules/ai_assistant/lib/in-process-client.ts +205 -0
  177. package/src/modules/ai_assistant/lib/mcp-client.ts +221 -0
  178. package/src/modules/ai_assistant/lib/mcp-dev-server.ts +373 -0
  179. package/src/modules/ai_assistant/lib/mcp-server-config.ts +287 -0
  180. package/src/modules/ai_assistant/lib/mcp-server.ts +214 -0
  181. package/src/modules/ai_assistant/lib/mcp-tool-adapter.ts +76 -0
  182. package/src/modules/ai_assistant/lib/opencode-client.ts +426 -0
  183. package/src/modules/ai_assistant/lib/opencode-handlers.ts +676 -0
  184. package/src/modules/ai_assistant/lib/schema-utils.ts +142 -0
  185. package/src/modules/ai_assistant/lib/tool-executor.ts +71 -0
  186. package/src/modules/ai_assistant/lib/tool-index-config.ts +178 -0
  187. package/src/modules/ai_assistant/lib/tool-loader.ts +149 -0
  188. package/src/modules/ai_assistant/lib/tool-registry.ts +114 -0
  189. package/src/modules/ai_assistant/lib/tool-search.ts +308 -0
  190. package/src/modules/ai_assistant/lib/types.ts +147 -0
  191. package/test-schema.ts +37 -0
  192. package/tsconfig.json +10 -0
  193. package/watch.mjs +6 -0
@@ -0,0 +1,130 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Wrench, AlertTriangle, Loader2, Check, X } from 'lucide-react'
5
+ import { cn } from '@open-mercato/shared/lib/utils'
6
+ import { Button } from '@open-mercato/ui/primitives/button'
7
+ import type { PendingToolCall } from '../../types'
8
+
9
+ interface ToolCallConfirmationProps {
10
+ toolCall: PendingToolCall
11
+ onApprove: () => void
12
+ onReject: () => void
13
+ }
14
+
15
+ const DESTRUCTIVE_PATTERNS = [/^delete/i, /^remove/i, /\.delete$/i, /\.remove$/i]
16
+
17
+ function isDestructive(toolName: string): boolean {
18
+ return DESTRUCTIVE_PATTERNS.some((p) => p.test(toolName))
19
+ }
20
+
21
+ export function ToolCallConfirmation({
22
+ toolCall,
23
+ onApprove,
24
+ onReject,
25
+ }: ToolCallConfirmationProps) {
26
+ const destructive = isDestructive(toolCall.toolName)
27
+
28
+ // Show different UI based on status
29
+ if (toolCall.status === 'executing') {
30
+ return (
31
+ <div className="bg-muted/50 rounded-lg p-3 border animate-pulse">
32
+ <div className="flex items-center gap-2">
33
+ <Loader2 className="h-4 w-4 animate-spin text-primary" />
34
+ <span className="text-sm">Executing {toolCall.toolName}...</span>
35
+ </div>
36
+ </div>
37
+ )
38
+ }
39
+
40
+ if (toolCall.status === 'completed') {
41
+ return (
42
+ <div className="bg-emerald-50 dark:bg-emerald-900/20 rounded-lg p-3 border border-emerald-200 dark:border-emerald-800">
43
+ <div className="flex items-center gap-2">
44
+ <Check className="h-4 w-4 text-emerald-600 dark:text-emerald-400" />
45
+ <span className="text-sm text-emerald-800 dark:text-emerald-200">
46
+ {toolCall.toolName} completed successfully
47
+ </span>
48
+ </div>
49
+ </div>
50
+ )
51
+ }
52
+
53
+ if (toolCall.status === 'error') {
54
+ return (
55
+ <div className="bg-destructive/10 rounded-lg p-3 border border-destructive/20">
56
+ <div className="flex items-center gap-2">
57
+ <X className="h-4 w-4 text-destructive" />
58
+ <span className="text-sm text-destructive">
59
+ {toolCall.toolName} failed: {toolCall.error || 'Unknown error'}
60
+ </span>
61
+ </div>
62
+ </div>
63
+ )
64
+ }
65
+
66
+ if (toolCall.status === 'rejected') {
67
+ return (
68
+ <div className="bg-muted/30 rounded-lg p-3 border opacity-60">
69
+ <div className="flex items-center gap-2">
70
+ <X className="h-4 w-4 text-muted-foreground" />
71
+ <span className="text-sm text-muted-foreground line-through">
72
+ {toolCall.toolName} cancelled
73
+ </span>
74
+ </div>
75
+ </div>
76
+ )
77
+ }
78
+
79
+ // Pending state - show confirmation UI
80
+ return (
81
+ <div
82
+ className={cn(
83
+ 'rounded-lg p-3 border',
84
+ destructive
85
+ ? 'bg-destructive/5 border-destructive/20'
86
+ : 'bg-muted/50 border-border'
87
+ )}
88
+ >
89
+ <div className="flex items-center gap-2 mb-2">
90
+ {destructive ? (
91
+ <AlertTriangle className="h-4 w-4 text-destructive" />
92
+ ) : (
93
+ <Wrench className="h-4 w-4 text-primary" />
94
+ )}
95
+ <span className="font-medium text-sm">
96
+ {destructive ? 'Destructive action requested' : 'AI wants to execute:'}
97
+ </span>
98
+ </div>
99
+
100
+ <div className="font-mono text-xs bg-background rounded p-2 mb-3 overflow-auto max-h-32">
101
+ <div className={cn('font-medium', destructive ? 'text-destructive' : 'text-primary')}>
102
+ {toolCall.toolName}
103
+ </div>
104
+ {toolCall.args && Object.keys(toolCall.args).length > 0 && (
105
+ <pre className="text-muted-foreground mt-1 whitespace-pre-wrap break-all">
106
+ {JSON.stringify(toolCall.args, null, 2)}
107
+ </pre>
108
+ )}
109
+ </div>
110
+
111
+ {destructive && (
112
+ <p className="text-xs text-destructive mb-3">This action may not be reversible.</p>
113
+ )}
114
+
115
+ <div className="flex gap-2">
116
+ <Button size="sm" variant="outline" onClick={onReject} className="flex-1">
117
+ Cancel
118
+ </Button>
119
+ <Button
120
+ size="sm"
121
+ variant={destructive ? 'destructive' : 'default'}
122
+ onClick={onApprove}
123
+ className="flex-1"
124
+ >
125
+ {destructive ? 'Delete' : 'Execute'}
126
+ </Button>
127
+ </div>
128
+ </div>
129
+ )
130
+ }
@@ -0,0 +1,57 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Wrench, Check, X, Loader2 } from 'lucide-react'
5
+ import { cn } from '@open-mercato/shared/lib/utils'
6
+ import type { ToolCall } from '../../types'
7
+ import { humanizeToolName } from '../../utils/toolMatcher'
8
+
9
+ interface ToolCallDisplayProps {
10
+ toolCall: ToolCall
11
+ }
12
+
13
+ export function ToolCallDisplay({ toolCall }: ToolCallDisplayProps) {
14
+ const displayName = humanizeToolName(toolCall.toolName)
15
+
16
+ return (
17
+ <div className="flex items-start gap-3 py-2 px-3 bg-muted/50 rounded-lg my-2">
18
+ <div
19
+ className={cn(
20
+ 'flex items-center justify-center w-6 h-6 rounded shrink-0',
21
+ toolCall.status === 'completed' && 'bg-green-100 text-green-600',
22
+ toolCall.status === 'error' && 'bg-red-100 text-red-600',
23
+ toolCall.status === 'running' && 'bg-blue-100 text-blue-600',
24
+ toolCall.status === 'pending' && 'bg-gray-100 text-gray-600'
25
+ )}
26
+ >
27
+ {toolCall.status === 'running' && <Loader2 className="h-3 w-3 animate-spin" />}
28
+ {toolCall.status === 'completed' && <Check className="h-3 w-3" />}
29
+ {toolCall.status === 'error' && <X className="h-3 w-3" />}
30
+ {toolCall.status === 'pending' && <Wrench className="h-3 w-3" />}
31
+ </div>
32
+
33
+ <div className="flex-1 min-w-0 text-xs">
34
+ <div className="font-medium text-foreground">{displayName}</div>
35
+
36
+ {Object.keys(toolCall.args).length > 0 && (
37
+ <div className="text-muted-foreground mt-1">
38
+ <code className="bg-muted px-1 rounded">
39
+ {JSON.stringify(toolCall.args, null, 0).slice(0, 100)}
40
+ {JSON.stringify(toolCall.args).length > 100 && '...'}
41
+ </code>
42
+ </div>
43
+ )}
44
+
45
+ {toolCall.status === 'completed' && toolCall.result !== undefined && (
46
+ <div className="text-green-600 mt-1">
47
+ Result: {typeof toolCall.result === 'object' ? 'Success' : String(toolCall.result)}
48
+ </div>
49
+ )}
50
+
51
+ {toolCall.status === 'error' && toolCall.error && (
52
+ <div className="text-red-600 mt-1">Error: {toolCall.error}</div>
53
+ )}
54
+ </div>
55
+ </div>
56
+ )
57
+ }
@@ -0,0 +1,125 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { useRef, useEffect } from 'react'
5
+ import { Loader2 } from 'lucide-react'
6
+ import Markdown from 'react-markdown'
7
+ import remarkGfm from 'remark-gfm'
8
+ import { Button } from '@open-mercato/ui/primitives/button'
9
+ import type { ToolInfo, ChatMessage, PendingToolCall, OpenCodeQuestion } from '../../types'
10
+ import { MessageBubble } from './MessageBubble'
11
+ import { ToolCallConfirmation } from './ToolCallConfirmation'
12
+
13
+ interface ToolChatPageProps {
14
+ tool: ToolInfo | null // Can be null for general chat
15
+ messages: ChatMessage[]
16
+ pendingToolCalls: PendingToolCall[]
17
+ isStreaming: boolean
18
+ isThinking?: boolean
19
+ onApproveToolCall: (toolCallId: string) => Promise<void>
20
+ onRejectToolCall: (toolCallId: string) => void
21
+ pendingQuestion?: OpenCodeQuestion | null
22
+ onAnswerQuestion?: (answer: number) => Promise<void>
23
+ }
24
+
25
+ export function ToolChatPage({
26
+ tool,
27
+ messages,
28
+ pendingToolCalls,
29
+ isStreaming,
30
+ isThinking = false,
31
+ onApproveToolCall,
32
+ onRejectToolCall,
33
+ pendingQuestion,
34
+ onAnswerQuestion,
35
+ }: ToolChatPageProps) {
36
+ const bottomRef = useRef<HTMLDivElement>(null)
37
+
38
+ // Auto-scroll to bottom on new messages (debounced)
39
+ useEffect(() => {
40
+ const timeoutId = setTimeout(() => {
41
+ bottomRef.current?.scrollIntoView({ behavior: 'smooth', block: 'end' })
42
+ }, 100)
43
+
44
+ return () => clearTimeout(timeoutId)
45
+ }, [messages, pendingToolCalls, isStreaming, isThinking, pendingQuestion])
46
+
47
+ return (
48
+ <div className="p-3 space-y-3">
49
+ {/* Tool description header - only shown if tool is selected */}
50
+ {tool && (
51
+ <div className="-mx-3 -mt-3 mb-3 px-3 py-2 border-b bg-muted/20">
52
+ <p className="text-xs text-muted-foreground line-clamp-2">{tool.description}</p>
53
+ </div>
54
+ )}
55
+
56
+ {/* Chat messages */}
57
+ <div className="space-y-3">
58
+ {messages.map((message) => (
59
+ <MessageBubble key={message.id} message={message} />
60
+ ))}
61
+
62
+ {/* Only show tool calls that require user action (pending dangerous tools or errors) */}
63
+ {pendingToolCalls
64
+ .filter((tc) => tc.status === 'pending' || tc.status === 'error')
65
+ .map((toolCall) => (
66
+ <ToolCallConfirmation
67
+ key={toolCall.id}
68
+ toolCall={toolCall}
69
+ onApprove={() => onApproveToolCall(toolCall.id)}
70
+ onReject={() => onRejectToolCall(toolCall.id)}
71
+ />
72
+ ))}
73
+
74
+ {/* OpenCode confirmation question */}
75
+ {pendingQuestion && pendingQuestion.questions[0] && (
76
+ <div className="p-4 bg-amber-500/10 border border-amber-500/30 rounded-lg space-y-3">
77
+ <div className="flex items-center gap-2 text-amber-600 dark:text-amber-400 text-sm font-medium">
78
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
79
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
80
+ </svg>
81
+ <span>{pendingQuestion.questions[0].header || 'Confirmation Required'}</span>
82
+ </div>
83
+ <div className="text-sm prose prose-sm dark:prose-invert max-w-none [&>*:first-child]:mt-0 [&>*:last-child]:mb-0 [&_p]:my-1 [&_strong]:font-semibold">
84
+ <Markdown remarkPlugins={[remarkGfm]}>
85
+ {pendingQuestion.questions[0].question}
86
+ </Markdown>
87
+ </div>
88
+ <div className="flex gap-2 flex-wrap">
89
+ {pendingQuestion.questions[0].options.map((option, index) => (
90
+ <Button
91
+ key={index}
92
+ variant={index === 0 ? 'default' : 'outline'}
93
+ size="sm"
94
+ onClick={() => onAnswerQuestion?.(index)}
95
+ disabled={isStreaming}
96
+ >
97
+ {option.label}
98
+ </Button>
99
+ ))}
100
+ </div>
101
+ </div>
102
+ )}
103
+
104
+ {/* Thinking indicator - OpenCode is processing */}
105
+ {isThinking && !pendingQuestion && (
106
+ <div className="flex items-center gap-2 py-3 px-3 bg-muted/50 rounded-lg text-muted-foreground text-sm">
107
+ <Loader2 className="h-4 w-4 animate-spin" />
108
+ <span>Agent is working...</span>
109
+ </div>
110
+ )}
111
+
112
+ {/* Streaming indicator - fallback for non-thinking streaming */}
113
+ {isStreaming && !isThinking && !pendingQuestion && messages[messages.length - 1]?.role !== 'assistant' && (
114
+ <div className="flex items-center gap-2 py-2 text-muted-foreground text-sm">
115
+ <Loader2 className="h-4 w-4 animate-spin" />
116
+ <span>AI is responding...</span>
117
+ </div>
118
+ )}
119
+
120
+ {/* Scroll anchor */}
121
+ <div ref={bottomRef} />
122
+ </div>
123
+ </div>
124
+ )
125
+ }
@@ -0,0 +1,14 @@
1
+ export { CommandPalette } from './CommandPalette'
2
+ export { CommandPaletteProvider, useCommandPaletteContext } from './CommandPaletteProvider'
3
+ export { CommandPaletteWrapper } from './CommandPaletteWrapper'
4
+ export { CommandInput } from './CommandInput'
5
+ export { CommandItem } from './CommandItem'
6
+ export { MessageBubble } from './MessageBubble'
7
+ export { ToolCallDisplay } from './ToolCallDisplay'
8
+
9
+ // Raycast-style components
10
+ export { CommandHeader } from './CommandHeader'
11
+ export { CommandFooter } from './CommandFooter'
12
+ export { ToolChatPage } from './ToolChatPage'
13
+ export { ToolCallConfirmation } from './ToolCallConfirmation'
14
+ export { DebugPanel } from './DebugPanel'
@@ -0,0 +1,35 @@
1
+ export const COMMAND_PALETTE_SHORTCUT = {
2
+ key: 'k',
3
+ meta: true, // Cmd on Mac, Ctrl on Windows/Linux
4
+ } as const
5
+
6
+ export const RECENT_ACTIONS_KEY = 'om:command-palette:recent-actions'
7
+ export const MAX_RECENT_ACTIONS = 10
8
+
9
+ export const NATURAL_LANGUAGE_PATTERNS = [
10
+ /^(what|how|why|when|where|who|can you|please|help|show me|find|search|list|create|update|delete)/i,
11
+ /\?$/,
12
+ /^(i want|i need|i'd like)/i,
13
+ ] as const
14
+
15
+ export const MODULE_ICONS: Record<string, string> = {
16
+ customers: 'users',
17
+ catalog: 'package',
18
+ sales: 'shopping-cart',
19
+ search: 'search',
20
+ auth: 'lock',
21
+ dictionaries: 'book',
22
+ directory: 'folder',
23
+ currencies: 'dollar-sign',
24
+ feature_toggles: 'toggle-left',
25
+ } as const
26
+
27
+ export const ACTION_ICONS: Record<string, string> = {
28
+ create: 'plus',
29
+ update: 'edit',
30
+ delete: 'trash',
31
+ search: 'search',
32
+ query: 'search',
33
+ get: 'eye',
34
+ list: 'list',
35
+ } as const
@@ -0,0 +1,5 @@
1
+ export { useCommandPalette } from './useCommandPalette'
2
+ export { useMcpTools } from './useMcpTools'
3
+ export { usePageContext } from './usePageContext'
4
+ export { useRecentActions } from './useRecentActions'
5
+ export { useRecentTools } from './useRecentTools'