@stigmer/react 0.0.92 → 0.0.94

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 (328) hide show
  1. package/README.md +57 -12
  2. package/agent/AgentDetailView.js +7 -7
  3. package/agent/AgentDetailView.js.map +1 -1
  4. package/agent/AgentPicker.js +3 -3
  5. package/agent/AgentPicker.js.map +1 -1
  6. package/api-key/ApiKeyCreatedAlert.js +1 -1
  7. package/api-key/ApiKeyCreatedAlert.js.map +1 -1
  8. package/api-key/ApiKeyListPanel.js +4 -4
  9. package/api-key/ApiKeyListPanel.js.map +1 -1
  10. package/api-key/CreateApiKeyForm.js +1 -1
  11. package/api-key/CreateApiKeyForm.js.map +1 -1
  12. package/attachment/AttachmentChipList.js +2 -2
  13. package/attachment/AttachmentChipList.js.map +1 -1
  14. package/color-mode.d.ts +48 -0
  15. package/color-mode.d.ts.map +1 -0
  16. package/color-mode.js +53 -0
  17. package/color-mode.js.map +1 -0
  18. package/composer/ComposerToolbar.d.ts +6 -2
  19. package/composer/ComposerToolbar.d.ts.map +1 -1
  20. package/composer/ComposerToolbar.js +5 -3
  21. package/composer/ComposerToolbar.js.map +1 -1
  22. package/composer/ConfigureMenu.js +3 -3
  23. package/composer/ConfigureMenu.js.map +1 -1
  24. package/composer/ContextChip.js +1 -1
  25. package/composer/ContextChip.js.map +1 -1
  26. package/composer/ContextPopover.js +1 -1
  27. package/composer/ContextPopover.js.map +1 -1
  28. package/composer/SessionComposer.d.ts +24 -3
  29. package/composer/SessionComposer.d.ts.map +1 -1
  30. package/composer/SessionComposer.js +5 -4
  31. package/composer/SessionComposer.js.map +1 -1
  32. package/environment/CreateEnvironmentForm.js +1 -1
  33. package/environment/CreateEnvironmentForm.js.map +1 -1
  34. package/environment/EnvVarForm.js +2 -2
  35. package/environment/EnvVarForm.js.map +1 -1
  36. package/environment/EnvironmentListPanel.js +2 -2
  37. package/environment/EnvironmentListPanel.js.map +1 -1
  38. package/environment/EnvironmentVariableEditor.js +6 -6
  39. package/environment/EnvironmentVariableEditor.js.map +1 -1
  40. package/error/ErrorMessage.js +1 -1
  41. package/error/ErrorMessage.js.map +1 -1
  42. package/execution/ApprovalCard.js +4 -4
  43. package/execution/ApprovalCard.js.map +1 -1
  44. package/execution/ArtifactCard.js +1 -1
  45. package/execution/ArtifactCard.js.map +1 -1
  46. package/execution/ArtifactPreviewModal.js +4 -4
  47. package/execution/ArtifactPreviewModal.js.map +1 -1
  48. package/execution/FollowUpInput.js +1 -1
  49. package/execution/FollowUpInput.js.map +1 -1
  50. package/execution/McpToolDetail.js +4 -4
  51. package/execution/McpToolDetail.js.map +1 -1
  52. package/execution/MessageEntry.js +1 -1
  53. package/execution/MessageEntry.js.map +1 -1
  54. package/execution/MessageThread.js +1 -1
  55. package/execution/MessageThread.js.map +1 -1
  56. package/execution/SessionVariablesInput.js +4 -4
  57. package/execution/SessionVariablesInput.js.map +1 -1
  58. package/execution/SubAgentSection.js +2 -2
  59. package/execution/SubAgentSection.js.map +1 -1
  60. package/execution/ToolCallDetail.js +2 -2
  61. package/execution/ToolCallDetail.js.map +1 -1
  62. package/execution/ToolCallGroup.js +1 -1
  63. package/execution/ToolCallGroup.js.map +1 -1
  64. package/execution/ToolCallItem.js +2 -2
  65. package/execution/ToolCallItem.js.map +1 -1
  66. package/execution/WriteBackCard.js +3 -3
  67. package/execution/WriteBackCard.js.map +1 -1
  68. package/execution/tool-rendering-primitives.js +3 -3
  69. package/execution/tool-rendering-primitives.js.map +1 -1
  70. package/github/GitHubRepoPicker.js +5 -5
  71. package/github/GitHubRepoPicker.js.map +1 -1
  72. package/iam-policy/GrantAccessForm.js +1 -1
  73. package/iam-policy/GrantAccessForm.js.map +1 -1
  74. package/iam-policy/OrgMembersPanel.js +5 -5
  75. package/iam-policy/OrgMembersPanel.js.map +1 -1
  76. package/identity-provider/CreateIdentityProviderForm.js +3 -3
  77. package/identity-provider/CreateIdentityProviderForm.js.map +1 -1
  78. package/identity-provider/IdentityProviderDetailPanel.js +5 -5
  79. package/identity-provider/IdentityProviderDetailPanel.js.map +1 -1
  80. package/identity-provider/IdentityProviderListPanel.js +3 -3
  81. package/identity-provider/IdentityProviderListPanel.js.map +1 -1
  82. package/identity-provider/IdentityProviderWizard.js +7 -7
  83. package/identity-provider/IdentityProviderWizard.js.map +1 -1
  84. package/identity-provider/ProviderPicker.js +2 -2
  85. package/identity-provider/ProviderPicker.js.map +1 -1
  86. package/index.d.ts +8 -4
  87. package/index.d.ts.map +1 -1
  88. package/index.js +7 -3
  89. package/index.js.map +1 -1
  90. package/internal/CloudFeatureNotice.js +1 -1
  91. package/internal/CloudFeatureNotice.js.map +1 -1
  92. package/internal/Tabs.js +1 -1
  93. package/internal/Tabs.js.map +1 -1
  94. package/internal/markdown-components.js +2 -2
  95. package/internal/markdown-components.js.map +1 -1
  96. package/invitation/InvitationCreatedAlert.js +1 -1
  97. package/invitation/InvitationCreatedAlert.js.map +1 -1
  98. package/invitation/InvitationManager.js +5 -5
  99. package/invitation/InvitationManager.js.map +1 -1
  100. package/invitation/InvitationRedemption.js +4 -4
  101. package/invitation/InvitationRedemption.js.map +1 -1
  102. package/library/ResourceCountCard.js +1 -1
  103. package/library/ResourceCountCard.js.map +1 -1
  104. package/library/ResourceListView.js +5 -5
  105. package/library/ResourceListView.js.map +1 -1
  106. package/mcp-server/McpServerConfigPanel.js +5 -5
  107. package/mcp-server/McpServerConfigPanel.js.map +1 -1
  108. package/mcp-server/McpServerConnectDialog.js +4 -4
  109. package/mcp-server/McpServerConnectDialog.js.map +1 -1
  110. package/mcp-server/McpServerDetailView.js +14 -14
  111. package/mcp-server/McpServerDetailView.js.map +1 -1
  112. package/mcp-server/McpServerPicker.js +4 -4
  113. package/mcp-server/McpServerPicker.js.map +1 -1
  114. package/mcp-server/McpToolSelector.js +3 -3
  115. package/mcp-server/McpToolSelector.js.map +1 -1
  116. package/mcp-server/OAuthAppForm.js +1 -1
  117. package/mcp-server/OAuthAppForm.js.map +1 -1
  118. package/models/ModelSelector.js +1 -1
  119. package/models/ModelSelector.js.map +1 -1
  120. package/oauth-app/CreateOAuthAppForm.js +1 -1
  121. package/oauth-app/CreateOAuthAppForm.js.map +1 -1
  122. package/oauth-app/OAuthAppDetailPanel.js +3 -3
  123. package/oauth-app/OAuthAppDetailPanel.js.map +1 -1
  124. package/oauth-app/OAuthAppListPanel.js +2 -2
  125. package/oauth-app/OAuthAppListPanel.js.map +1 -1
  126. package/organization/CreateOrganizationForm.js +1 -1
  127. package/organization/CreateOrganizationForm.js.map +1 -1
  128. package/organization/OrgProfilePanel.js +3 -3
  129. package/organization/OrgProfilePanel.js.map +1 -1
  130. package/package.json +4 -4
  131. package/platform-client/CreatePlatformClientForm.js +2 -2
  132. package/platform-client/CreatePlatformClientForm.js.map +1 -1
  133. package/platform-client/PlatformClientDetailPanel.js +4 -4
  134. package/platform-client/PlatformClientDetailPanel.js.map +1 -1
  135. package/platform-client/PlatformClientListPanel.js +3 -3
  136. package/platform-client/PlatformClientListPanel.js.map +1 -1
  137. package/platform-client/PlatformClientSecretAlert.js +2 -2
  138. package/platform-client/PlatformClientSecretAlert.js.map +1 -1
  139. package/provider.d.ts +39 -2
  140. package/provider.d.ts.map +1 -1
  141. package/provider.js +11 -3
  142. package/provider.js.map +1 -1
  143. package/runner/RunnerListPanel.d.ts +65 -0
  144. package/runner/RunnerListPanel.d.ts.map +1 -0
  145. package/runner/RunnerListPanel.js +237 -0
  146. package/runner/RunnerListPanel.js.map +1 -0
  147. package/runner/RunnerPicker.d.ts +54 -0
  148. package/runner/RunnerPicker.d.ts.map +1 -0
  149. package/runner/RunnerPicker.js +133 -0
  150. package/runner/RunnerPicker.js.map +1 -0
  151. package/runner/__tests__/useDeleteRunner.test.d.ts +2 -0
  152. package/runner/__tests__/useDeleteRunner.test.d.ts.map +1 -0
  153. package/runner/__tests__/useDeleteRunner.test.js +108 -0
  154. package/runner/__tests__/useDeleteRunner.test.js.map +1 -0
  155. package/runner/__tests__/useLaunchLocalRunner.test.d.ts +2 -0
  156. package/runner/__tests__/useLaunchLocalRunner.test.d.ts.map +1 -0
  157. package/runner/__tests__/useLaunchLocalRunner.test.js +143 -0
  158. package/runner/__tests__/useLaunchLocalRunner.test.js.map +1 -0
  159. package/runner/__tests__/useStopRunner.test.d.ts +2 -0
  160. package/runner/__tests__/useStopRunner.test.d.ts.map +1 -0
  161. package/runner/__tests__/useStopRunner.test.js +114 -0
  162. package/runner/__tests__/useStopRunner.test.js.map +1 -0
  163. package/runner/index.d.ts +14 -0
  164. package/runner/index.d.ts.map +1 -0
  165. package/runner/index.js +8 -0
  166. package/runner/index.js.map +1 -0
  167. package/runner/phase.d.ts +30 -0
  168. package/runner/phase.d.ts.map +1 -0
  169. package/runner/phase.js +58 -0
  170. package/runner/phase.js.map +1 -0
  171. package/runner/useDeleteRunner.d.ts +36 -0
  172. package/runner/useDeleteRunner.d.ts.map +1 -0
  173. package/runner/useDeleteRunner.js +42 -0
  174. package/runner/useDeleteRunner.js.map +1 -0
  175. package/runner/useLaunchLocalRunner.d.ts +84 -0
  176. package/runner/useLaunchLocalRunner.d.ts.map +1 -0
  177. package/runner/useLaunchLocalRunner.js +75 -0
  178. package/runner/useLaunchLocalRunner.js.map +1 -0
  179. package/runner/useRunnerList.d.ts +49 -0
  180. package/runner/useRunnerList.d.ts.map +1 -0
  181. package/runner/useRunnerList.js +70 -0
  182. package/runner/useRunnerList.js.map +1 -0
  183. package/runner/useStopRunner.d.ts +53 -0
  184. package/runner/useStopRunner.d.ts.map +1 -0
  185. package/runner/useStopRunner.js +50 -0
  186. package/runner/useStopRunner.js.map +1 -0
  187. package/session/draft.d.ts +53 -0
  188. package/session/draft.d.ts.map +1 -0
  189. package/session/draft.js +45 -0
  190. package/session/draft.js.map +1 -0
  191. package/session/index.d.ts +10 -0
  192. package/session/index.d.ts.map +1 -1
  193. package/session/index.js +5 -0
  194. package/session/index.js.map +1 -1
  195. package/session/useCreateSession.d.ts +8 -0
  196. package/session/useCreateSession.d.ts.map +1 -1
  197. package/session/useCreateSession.js +1 -0
  198. package/session/useCreateSession.js.map +1 -1
  199. package/session/useEditSessionPrep.d.ts +26 -0
  200. package/session/useEditSessionPrep.d.ts.map +1 -0
  201. package/session/useEditSessionPrep.js +83 -0
  202. package/session/useEditSessionPrep.js.map +1 -0
  203. package/session/useNewSessionFlow.d.ts +110 -0
  204. package/session/useNewSessionFlow.d.ts.map +1 -0
  205. package/session/useNewSessionFlow.js +184 -0
  206. package/session/useNewSessionFlow.js.map +1 -0
  207. package/session/usePersistedModel.d.ts +18 -0
  208. package/session/usePersistedModel.d.ts.map +1 -0
  209. package/session/usePersistedModel.js +31 -0
  210. package/session/usePersistedModel.js.map +1 -0
  211. package/session/useSessionPageFlow.d.ts +104 -0
  212. package/session/useSessionPageFlow.d.ts.map +1 -0
  213. package/session/useSessionPageFlow.js +172 -0
  214. package/session/useSessionPageFlow.js.map +1 -0
  215. package/skill/SkillDetailView.js +3 -3
  216. package/skill/SkillDetailView.js.map +1 -1
  217. package/skill/SkillPicker.js +3 -3
  218. package/skill/SkillPicker.js.map +1 -1
  219. package/src/agent/AgentDetailView.tsx +8 -8
  220. package/src/agent/AgentPicker.tsx +3 -3
  221. package/src/api-key/ApiKeyCreatedAlert.tsx +2 -2
  222. package/src/api-key/ApiKeyListPanel.tsx +6 -6
  223. package/src/api-key/CreateApiKeyForm.tsx +2 -2
  224. package/src/attachment/AttachmentChipList.tsx +3 -3
  225. package/src/color-mode.ts +75 -0
  226. package/src/composer/ComposerToolbar.tsx +29 -7
  227. package/src/composer/ConfigureMenu.tsx +6 -6
  228. package/src/composer/ContextChip.tsx +1 -1
  229. package/src/composer/ContextPopover.tsx +2 -2
  230. package/src/composer/SessionComposer.tsx +34 -5
  231. package/src/environment/CreateEnvironmentForm.tsx +3 -3
  232. package/src/environment/EnvVarForm.tsx +6 -6
  233. package/src/environment/EnvironmentListPanel.tsx +3 -3
  234. package/src/environment/EnvironmentVariableEditor.tsx +7 -7
  235. package/src/error/ErrorMessage.tsx +5 -5
  236. package/src/execution/ApprovalCard.tsx +5 -5
  237. package/src/execution/ArtifactCard.tsx +2 -2
  238. package/src/execution/ArtifactPreviewModal.tsx +4 -4
  239. package/src/execution/FollowUpInput.tsx +2 -2
  240. package/src/execution/McpToolDetail.tsx +4 -4
  241. package/src/execution/MessageEntry.tsx +1 -1
  242. package/src/execution/MessageThread.tsx +1 -1
  243. package/src/execution/SessionVariablesInput.tsx +7 -7
  244. package/src/execution/SubAgentSection.tsx +5 -5
  245. package/src/execution/ToolCallDetail.tsx +2 -2
  246. package/src/execution/ToolCallGroup.tsx +3 -3
  247. package/src/execution/ToolCallItem.tsx +4 -4
  248. package/src/execution/WriteBackCard.tsx +5 -5
  249. package/src/execution/tool-rendering-primitives.tsx +5 -5
  250. package/src/github/GitHubRepoPicker.tsx +5 -5
  251. package/src/iam-policy/GrantAccessForm.tsx +2 -2
  252. package/src/iam-policy/OrgMembersPanel.tsx +11 -11
  253. package/src/identity-provider/CreateIdentityProviderForm.tsx +4 -4
  254. package/src/identity-provider/IdentityProviderDetailPanel.tsx +7 -7
  255. package/src/identity-provider/IdentityProviderListPanel.tsx +7 -7
  256. package/src/identity-provider/IdentityProviderWizard.tsx +8 -8
  257. package/src/identity-provider/ProviderPicker.tsx +2 -2
  258. package/src/index.ts +46 -7
  259. package/src/internal/CloudFeatureNotice.tsx +1 -1
  260. package/src/internal/Tabs.tsx +1 -1
  261. package/src/internal/markdown-components.tsx +2 -2
  262. package/src/invitation/InvitationCreatedAlert.tsx +2 -2
  263. package/src/invitation/InvitationManager.tsx +9 -9
  264. package/src/invitation/InvitationRedemption.tsx +11 -11
  265. package/src/library/ResourceCountCard.tsx +1 -1
  266. package/src/library/ResourceListView.tsx +7 -7
  267. package/src/mcp-server/McpServerConfigPanel.tsx +7 -7
  268. package/src/mcp-server/McpServerConnectDialog.tsx +5 -5
  269. package/src/mcp-server/McpServerDetailView.tsx +19 -19
  270. package/src/mcp-server/McpServerPicker.tsx +6 -6
  271. package/src/mcp-server/McpToolSelector.tsx +4 -4
  272. package/src/mcp-server/OAuthAppForm.tsx +3 -3
  273. package/src/models/ModelSelector.tsx +1 -1
  274. package/src/oauth-app/CreateOAuthAppForm.tsx +3 -3
  275. package/src/oauth-app/OAuthAppDetailPanel.tsx +7 -7
  276. package/src/oauth-app/OAuthAppListPanel.tsx +3 -3
  277. package/src/organization/CreateOrganizationForm.tsx +3 -3
  278. package/src/organization/OrgProfilePanel.tsx +4 -5
  279. package/src/platform-client/CreatePlatformClientForm.tsx +6 -6
  280. package/src/platform-client/PlatformClientDetailPanel.tsx +19 -19
  281. package/src/platform-client/PlatformClientListPanel.tsx +7 -7
  282. package/src/platform-client/PlatformClientSecretAlert.tsx +2 -2
  283. package/src/provider.tsx +52 -2
  284. package/src/runner/RunnerListPanel.tsx +725 -0
  285. package/src/runner/RunnerPicker.tsx +319 -0
  286. package/src/runner/__tests__/useDeleteRunner.test.tsx +150 -0
  287. package/src/runner/__tests__/useLaunchLocalRunner.test.tsx +223 -0
  288. package/src/runner/__tests__/useStopRunner.test.tsx +154 -0
  289. package/src/runner/index.ts +34 -0
  290. package/src/runner/phase.ts +62 -0
  291. package/src/runner/useDeleteRunner.ts +67 -0
  292. package/src/runner/useLaunchLocalRunner.ts +139 -0
  293. package/src/runner/useRunnerList.ts +114 -0
  294. package/src/runner/useStopRunner.ts +92 -0
  295. package/src/session/draft.ts +82 -0
  296. package/src/session/index.ts +28 -0
  297. package/src/session/useCreateSession.ts +9 -0
  298. package/src/session/useEditSessionPrep.ts +111 -0
  299. package/src/session/useNewSessionFlow.ts +283 -0
  300. package/src/session/usePersistedModel.ts +41 -0
  301. package/src/session/useSessionPageFlow.ts +280 -0
  302. package/src/skill/SkillDetailView.tsx +5 -5
  303. package/src/skill/SkillPicker.tsx +3 -3
  304. package/src/styles.css +25 -1
  305. package/src/usage/OrgUsagePanel.tsx +4 -4
  306. package/src/workspace/WorkspaceEditor.tsx +78 -66
  307. package/src/workspace/index.ts +0 -8
  308. package/styles.css +1 -1
  309. package/usage/OrgUsagePanel.js +2 -2
  310. package/usage/OrgUsagePanel.js.map +1 -1
  311. package/workspace/WorkspaceEditor.d.ts +28 -3
  312. package/workspace/WorkspaceEditor.d.ts.map +1 -1
  313. package/workspace/WorkspaceEditor.js +24 -25
  314. package/workspace/WorkspaceEditor.js.map +1 -1
  315. package/workspace/index.d.ts +0 -4
  316. package/workspace/index.d.ts.map +1 -1
  317. package/workspace/index.js +0 -2
  318. package/workspace/index.js.map +1 -1
  319. package/src/workspace/FolderBrowser.tsx +0 -579
  320. package/src/workspace/useFolderListing.ts +0 -164
  321. package/workspace/FolderBrowser.d.ts +0 -37
  322. package/workspace/FolderBrowser.d.ts.map +0 -1
  323. package/workspace/FolderBrowser.js +0 -188
  324. package/workspace/FolderBrowser.js.map +0 -1
  325. package/workspace/useFolderListing.d.ts +0 -73
  326. package/workspace/useFolderListing.d.ts.map +0 -1
  327. package/workspace/useFolderListing.js +0 -110
  328. package/workspace/useFolderListing.js.map +0 -1
@@ -0,0 +1,280 @@
1
+ "use client";
2
+
3
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
+ import type { McpServerUsageInput, ResourceRef } from "@stigmer/sdk";
5
+ import type { AgentResolution } from "../agent";
6
+ import { useDefaultAgent } from "../agent";
7
+ import { useStigmer } from "../hooks";
8
+ import { useWorkspaceEntries, type UseWorkspaceEntriesReturn } from "../workspace";
9
+ import { useSessionVariables, type UseSessionVariablesReturn } from "../execution/useSessionVariables";
10
+ import type { SessionComposerSubmitContext } from "../composer";
11
+ import { useSessionConversation, type UseSessionConversationReturn } from "./useSessionConversation";
12
+ import { useAgentRefFromSession } from "./useAgentRefFromSession";
13
+ import { usePersistedModel, type UsePersistedModelReturn } from "./usePersistedModel";
14
+
15
+ /**
16
+ * Well-known Daytona sandbox workspace root. Used as the SDK safety-net
17
+ * normalization target for cloud sessions (git-repo workspace entries).
18
+ */
19
+ const DAYTONA_WORKSPACE_ROOT = "/home/daytona/workspace";
20
+
21
+ /** Options for {@link useSessionPageFlow}. */
22
+ export interface UseSessionPageFlowOptions {
23
+ /** Session ID to load and manage. */
24
+ readonly sessionId: string;
25
+ /** Organization slug. */
26
+ readonly org: string;
27
+ }
28
+
29
+ /** Return value of {@link useSessionPageFlow}. */
30
+ export interface UseSessionPageFlowReturn {
31
+ /** Full conversation state from `useSessionConversation`. */
32
+ readonly conv: UseSessionConversationReturn;
33
+
34
+ /** Persisted model selection: `[modelId, setModelId]`. */
35
+ readonly model: UsePersistedModelReturn;
36
+
37
+ /** Currently selected agent reference (derived from session, or overridden by user). */
38
+ readonly agentRef: ResourceRef | null;
39
+ /** Update the agent reference for future follow-ups. */
40
+ readonly setAgentRef: (ref: ResourceRef | null) => void;
41
+ /** Current agent resolution state. */
42
+ readonly resolution: AgentResolution | null;
43
+ /** Update the agent resolution. */
44
+ readonly setResolution: (r: AgentResolution | null) => void;
45
+
46
+ /** Active MCP server configurations for follow-ups. */
47
+ readonly mcpServerUsages: McpServerUsageInput[];
48
+ /** Update MCP server configurations. */
49
+ readonly setMcpServerUsages: (usages: McpServerUsageInput[]) => void;
50
+
51
+ /** Active skill references for follow-ups. */
52
+ readonly skillRefs: ResourceRef[];
53
+ /** Update skill references. */
54
+ readonly setSkillRefs: (refs: ResourceRef[]) => void;
55
+
56
+ /** Workspace entries manager (synced from session on load). */
57
+ readonly workspace: UseWorkspaceEntriesReturn;
58
+ /** Session variables (per-execution secrets) manager. */
59
+ readonly sessionVariables: UseSessionVariablesReturn;
60
+
61
+ /**
62
+ * Submit a follow-up message. Handles agent override resolution
63
+ * (if the user changed the agent mid-session) and delegates to
64
+ * `conv.sendFollowUp` with all managed state.
65
+ */
66
+ readonly handleSubmit: (
67
+ message: string,
68
+ model?: string,
69
+ context?: SessionComposerSubmitContext,
70
+ ) => Promise<void>;
71
+
72
+ /**
73
+ * The most relevant execution for sidebar display — the active
74
+ * streaming execution, or the last completed one.
75
+ */
76
+ readonly displayExecution: UseSessionConversationReturn["activeStreamExecution"];
77
+
78
+ /**
79
+ * All executions for widget display (completed + active stream).
80
+ */
81
+ readonly allExecutions: UseSessionConversationReturn["completedExecutions"];
82
+
83
+ /**
84
+ * Sandbox workspace root for file path normalization, or `undefined`
85
+ * when the session has no git-repo workspace entries.
86
+ */
87
+ readonly sandboxWorkspaceRoot: string | undefined;
88
+ }
89
+
90
+ /**
91
+ * Orchestrates the session page experience.
92
+ *
93
+ * Composes `useSessionConversation` with agent resolution, workspace
94
+ * synchronization, model persistence, and follow-up submission logic.
95
+ * Returns everything a session page needs to render its UI without
96
+ * duplicating domain orchestration.
97
+ *
98
+ * Framework-agnostic — works identically in Next.js, Vite, Tauri, or
99
+ * any React environment. The consumer provides layout, error states,
100
+ * and loading skeletons.
101
+ *
102
+ * @example
103
+ * ```tsx
104
+ * const flow = useSessionPageFlow({ sessionId: "ses_abc", org: "acme" });
105
+ *
106
+ * if (flow.conv.isLoading) return <Spinner />;
107
+ * if (flow.conv.loadError) return <ErrorView error={flow.conv.loadError} />;
108
+ *
109
+ * return (
110
+ * <>
111
+ * <MessageThread
112
+ * executions={flow.conv.completedExecutions}
113
+ * activeStreamExecution={flow.conv.activeStreamExecution}
114
+ * sandboxWorkspaceRoot={flow.sandboxWorkspaceRoot}
115
+ * />
116
+ * <SessionComposer
117
+ * onSubmit={flow.handleSubmit}
118
+ * isSubmitting={flow.conv.isSending}
119
+ * disabled={!flow.conv.canSendFollowUp}
120
+ * workspace={flow.workspace}
121
+ * agentRef={flow.agentRef}
122
+ * onAgentRefChange={flow.setAgentRef}
123
+ * onAgentResolutionChange={flow.setResolution}
124
+ * defaultModelId={flow.model[0]}
125
+ * onModelChange={flow.model[1]}
126
+ * />
127
+ * </>
128
+ * );
129
+ * ```
130
+ */
131
+ export function useSessionPageFlow(
132
+ options: UseSessionPageFlowOptions,
133
+ ): UseSessionPageFlowReturn {
134
+ const { sessionId, org } = options;
135
+
136
+ const stigmer = useStigmer();
137
+ const conv = useSessionConversation(sessionId, org);
138
+ const model = usePersistedModel();
139
+ const [modelId] = model;
140
+
141
+ const workspace = useWorkspaceEntries();
142
+ const sessionVariables = useSessionVariables();
143
+ const [mcpServerUsages, setMcpServerUsages] = useState<McpServerUsageInput[]>([]);
144
+ const [skillRefs, setSkillRefs] = useState<ResourceRef[]>([]);
145
+ const initialSyncDone = useRef(false);
146
+
147
+ // -------------------------------------------------------------------------
148
+ // Agent — derive from session, allow mid-session changes
149
+ // -------------------------------------------------------------------------
150
+
151
+ const sessionInstanceId = conv.session?.spec?.agentInstanceId ?? null;
152
+ const { agentRef: derivedAgentRef } = useAgentRefFromSession(sessionInstanceId);
153
+ const { agent: defaultAgent, isLoading: isDefaultAgentLoading } = useDefaultAgent(org);
154
+
155
+ const [agentRef, setAgentRef] = useState<ResourceRef | null>(null);
156
+ const [resolution, setResolution] = useState<AgentResolution | null>(null);
157
+ const [agentInitDone, setAgentInitDone] = useState(false);
158
+
159
+ if (!agentInitDone && derivedAgentRef && sessionInstanceId && !isDefaultAgentLoading) {
160
+ setAgentInitDone(true);
161
+
162
+ const isDefault =
163
+ defaultAgent &&
164
+ derivedAgentRef.org === defaultAgent.metadata?.org &&
165
+ derivedAgentRef.slug === defaultAgent.metadata?.slug;
166
+
167
+ if (!isDefault) {
168
+ setAgentRef(derivedAgentRef);
169
+ setResolution({ mode: "saved", instanceId: sessionInstanceId });
170
+ }
171
+ }
172
+
173
+ // -------------------------------------------------------------------------
174
+ // Workspace — sync entries from session on first load
175
+ // -------------------------------------------------------------------------
176
+
177
+ useEffect(() => {
178
+ if (!conv.session || initialSyncDone.current) return;
179
+ initialSyncDone.current = true;
180
+
181
+ const protoEntries = conv.session.spec?.workspaceEntries ?? [];
182
+ for (const entry of protoEntries) {
183
+ if (entry.source?.source.case === "gitRepo") {
184
+ const { url, branch } = entry.source.source.value;
185
+ workspace.addGitRepo(url, branch || undefined);
186
+ } else if (entry.source?.source.case === "localPath") {
187
+ workspace.addLocalPath(entry.source.source.value.path);
188
+ }
189
+ }
190
+ }, [conv.session, workspace]);
191
+
192
+ // -------------------------------------------------------------------------
193
+ // Follow-up submission with agent override
194
+ // -------------------------------------------------------------------------
195
+
196
+ const handleSubmit = useCallback(
197
+ async (
198
+ message: string,
199
+ selectedModel?: string,
200
+ context?: SessionComposerSubmitContext,
201
+ ) => {
202
+ let agentInstanceIdOverride: string | undefined;
203
+
204
+ if (resolution) {
205
+ if (
206
+ resolution.mode === "saved" &&
207
+ resolution.instanceId !== sessionInstanceId
208
+ ) {
209
+ agentInstanceIdOverride = resolution.instanceId;
210
+ } else if (resolution.mode === "direct" && agentRef) {
211
+ const agent = await stigmer.agent.getByReference(agentRef);
212
+ const defaultId = agent.status?.defaultInstanceId;
213
+ if (defaultId && defaultId !== sessionInstanceId) {
214
+ agentInstanceIdOverride = defaultId;
215
+ }
216
+ }
217
+ }
218
+
219
+ conv.sendFollowUp(message, {
220
+ agentInstanceId: agentInstanceIdOverride,
221
+ modelName: selectedModel ?? modelId,
222
+ workspaceEntries: workspace.hasEntries
223
+ ? workspace.toInput()
224
+ : undefined,
225
+ mcpServerUsages: mcpServerUsages.length > 0 ? mcpServerUsages : undefined,
226
+ skillRefs: skillRefs.length > 0 ? skillRefs : undefined,
227
+ runtimeEnv: context?.runtimeEnv,
228
+ attachments: context?.attachments,
229
+ });
230
+
231
+ sessionVariables.clear();
232
+ },
233
+ [conv, modelId, workspace, mcpServerUsages, skillRefs, sessionVariables, resolution, agentRef, sessionInstanceId, stigmer],
234
+ );
235
+
236
+ // -------------------------------------------------------------------------
237
+ // Derived display state
238
+ // -------------------------------------------------------------------------
239
+
240
+ const displayExecution = useMemo(() => {
241
+ if (conv.activeStreamExecution) return conv.activeStreamExecution;
242
+ const completed = conv.completedExecutions;
243
+ return completed.length > 0 ? completed[completed.length - 1] : null;
244
+ }, [conv.activeStreamExecution, conv.completedExecutions]);
245
+
246
+ const allExecutions = useMemo(
247
+ () => [
248
+ ...conv.completedExecutions,
249
+ ...(conv.activeStreamExecution ? [conv.activeStreamExecution] : []),
250
+ ],
251
+ [conv.completedExecutions, conv.activeStreamExecution],
252
+ );
253
+
254
+ const sandboxWorkspaceRoot = useMemo(() => {
255
+ const entries = conv.workspaceEntries;
256
+ const hasGitRepo = entries.some(
257
+ (e) => e.source?.source.case === "gitRepo",
258
+ );
259
+ return hasGitRepo ? DAYTONA_WORKSPACE_ROOT : undefined;
260
+ }, [conv.workspaceEntries]);
261
+
262
+ return {
263
+ conv,
264
+ model,
265
+ agentRef,
266
+ setAgentRef,
267
+ resolution,
268
+ setResolution,
269
+ mcpServerUsages,
270
+ setMcpServerUsages,
271
+ skillRefs,
272
+ setSkillRefs,
273
+ workspace,
274
+ sessionVariables,
275
+ handleSubmit,
276
+ displayExecution,
277
+ allExecutions,
278
+ sandboxWorkspaceRoot,
279
+ };
280
+ }
@@ -304,7 +304,7 @@ function GitProvenanceDisplay({
304
304
  {repoUrl ? (
305
305
  <a
306
306
  href={repoUrl}
307
- className="text-primary underline underline-offset-2 hover:text-primary/80"
307
+ className="text-primary underline underline-offset-2 hover:text-primary-muted"
308
308
  target="_blank"
309
309
  rel="noopener noreferrer"
310
310
  >
@@ -396,14 +396,14 @@ function LoadingSkeleton({ className }: { readonly className?: string }) {
396
396
  <div className="space-y-2">
397
397
  <div className="h-3 w-28 animate-pulse rounded bg-muted" />
398
398
  <div
399
- className="animate-pulse rounded-lg border border-border bg-muted/30"
399
+ className="animate-pulse rounded-lg border border-border bg-muted-faint"
400
400
  style={{ height: "240px" }}
401
401
  />
402
402
  </div>
403
403
  <div className="space-y-2">
404
404
  <div className="h-3 w-20 animate-pulse rounded bg-muted" />
405
405
  <div
406
- className="animate-pulse rounded-lg border border-border bg-muted/30"
406
+ className="animate-pulse rounded-lg border border-border bg-muted-faint"
407
407
  style={{ height: "64px" }}
408
408
  />
409
409
  </div>
@@ -420,11 +420,11 @@ function NotFoundState({ className }: { readonly className?: string }) {
420
420
  className,
421
421
  )}
422
422
  >
423
- <SkillIcon className="size-10 text-muted-foreground/40" />
423
+ <SkillIcon className="size-10 text-muted-foreground-faint" />
424
424
  <p className="text-sm font-medium text-muted-foreground">
425
425
  Skill not found
426
426
  </p>
427
- <p className="text-xs text-muted-foreground/60">
427
+ <p className="text-xs text-muted-foreground-subtle">
428
428
  This skill doesn&apos;t exist or you don&apos;t have access to it.
429
429
  </p>
430
430
  </div>
@@ -173,7 +173,7 @@ export function SkillPicker({
173
173
  return (
174
174
  <div
175
175
  key={key}
176
- className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1 text-xs"
176
+ className="flex items-center gap-2 rounded-md bg-muted-faint px-2 py-1 text-xs"
177
177
  >
178
178
  <SkillIcon />
179
179
  <span className="min-w-0 flex-1 truncate text-foreground">
@@ -254,7 +254,7 @@ export function SkillPicker({
254
254
  "disabled:pointer-events-none disabled:opacity-50",
255
255
  idx === focusIndex
256
256
  ? "bg-accent text-foreground"
257
- : "text-foreground hover:bg-accent/50",
257
+ : "text-foreground hover:bg-accent-hover",
258
258
  )}
259
259
  role="option"
260
260
  aria-selected={idx === focusIndex}
@@ -313,7 +313,7 @@ function LoadingSkeleton() {
313
313
  style={{ width: `${w}%` }}
314
314
  />
315
315
  <div
316
- className="h-2 rounded bg-muted/60 animate-pulse"
316
+ className="h-2 rounded bg-muted-subtle animate-pulse"
317
317
  style={{ width: `${Math.min(w + 15, 90)}%` }}
318
318
  />
319
319
  </div>
package/src/styles.css CHANGED
@@ -6,7 +6,7 @@
6
6
  @import "tailwindcss/utilities.css" layer(stgm);
7
7
  @import "@stigmer/theme/tokens.css" layer(stgm);
8
8
 
9
- @custom-variant dark (&:is(.dark *));
9
+ @custom-variant dark (&:is([data-stgm-color-mode="dark"] *));
10
10
 
11
11
  @theme inline {
12
12
  --radius-sm: calc(var(--stgm-radius) - 4px);
@@ -45,6 +45,30 @@
45
45
  --color-chart-5: var(--stgm-chart-5);
46
46
  --font-sans: var(--stgm-font-sans);
47
47
  --font-mono: var(--stgm-font-mono);
48
+ --color-primary-hover: var(--stgm-primary-hover);
49
+ --color-primary-subtle: var(--stgm-primary-subtle);
50
+ --color-primary-muted: var(--stgm-primary-muted);
51
+ --color-destructive-subtle: var(--stgm-destructive-subtle);
52
+ --color-destructive-hover: var(--stgm-destructive-hover);
53
+ --color-destructive-muted: var(--stgm-destructive-muted);
54
+ --color-accent-hover: var(--stgm-accent-hover);
55
+ --color-foreground-hover: var(--stgm-foreground-hover);
56
+ --color-muted-subtle: var(--stgm-muted-subtle);
57
+ --color-muted-faint: var(--stgm-muted-faint);
58
+ --color-muted-foreground-subtle: var(--stgm-muted-foreground-subtle);
59
+ --color-muted-foreground-faint: var(--stgm-muted-foreground-faint);
60
+ --color-border-muted: var(--stgm-border-muted);
61
+ --color-backdrop: var(--stgm-backdrop);
62
+ --color-sidebar: var(--stgm-sidebar);
63
+ --color-sidebar-foreground: var(--stgm-sidebar-foreground);
64
+ --color-sidebar-primary: var(--stgm-sidebar-primary);
65
+ --color-sidebar-primary-foreground: var(--stgm-sidebar-primary-foreground);
66
+ --color-sidebar-muted: var(--stgm-sidebar-muted);
67
+ --color-sidebar-muted-foreground: var(--stgm-sidebar-muted-foreground);
68
+ --color-sidebar-accent: var(--stgm-sidebar-accent);
69
+ --color-sidebar-accent-foreground: var(--stgm-sidebar-accent-foreground);
70
+ --color-sidebar-border: var(--stgm-sidebar-border);
71
+ --color-sidebar-ring: var(--stgm-sidebar-ring);
48
72
  --shadow-sm: var(--stgm-shadow-sm);
49
73
  --shadow-md: var(--stgm-shadow-md);
50
74
  --shadow-lg: var(--stgm-shadow-lg);
@@ -61,7 +61,7 @@ export function OrgUsagePanel({ orgId, className }: OrgUsagePanelProps) {
61
61
  {DATE_RANGE_PRESETS.map((p) => (
62
62
  <div
63
63
  key={p}
64
- className="h-7 w-16 animate-pulse rounded-md bg-muted/40"
64
+ className="h-7 w-16 animate-pulse rounded-md bg-muted-subtle"
65
65
  />
66
66
  ))}
67
67
  </div>
@@ -69,11 +69,11 @@ export function OrgUsagePanel({ orgId, className }: OrgUsagePanelProps) {
69
69
  {Array.from({ length: 3 }, (_, i) => (
70
70
  <div
71
71
  key={i}
72
- className="h-[72px] animate-pulse rounded-lg bg-muted/40"
72
+ className="h-[72px] animate-pulse rounded-lg bg-muted-subtle"
73
73
  />
74
74
  ))}
75
75
  </div>
76
- <div className="h-40 animate-pulse rounded-lg bg-muted/40" />
76
+ <div className="h-40 animate-pulse rounded-lg bg-muted-subtle" />
77
77
  </div>
78
78
  );
79
79
  }
@@ -333,7 +333,7 @@ function ModelBreakdownList({
333
333
  return (
334
334
  <div
335
335
  key={`${m.model}\0${m.provider}`}
336
- className="border-b border-border/50 px-3.5 py-2 last:border-b-0"
336
+ className="border-b border-border-muted px-3.5 py-2 last:border-b-0"
337
337
  >
338
338
  <div
339
339
  role="row"
@@ -1,10 +1,9 @@
1
1
  "use client";
2
2
 
3
- import { useState, useCallback, useEffect, type KeyboardEvent } from "react";
3
+ import { useState, useCallback, type KeyboardEvent } from "react";
4
4
  import type { UseWorkspaceEntriesReturn } from "./useWorkspaceEntries";
5
5
  import type { UseGitHubConnectionReturn } from "../github/useGitHubConnection";
6
6
  import { GitHubRepoPicker } from "../github/GitHubRepoPicker";
7
- import { FolderBrowser } from "./FolderBrowser";
8
7
  import { useScrollShadows } from "../internal/useScrollShadows";
9
8
  import { ScrollFade } from "../internal/ScrollFade";
10
9
 
@@ -22,14 +21,37 @@ export interface WorkspaceEditorProps {
22
21
  readonly enableGitHub?: boolean;
23
22
  /** Show the Local Folder source button. Default: false (set by Console based on deployment mode). */
24
23
  readonly enableLocal?: boolean;
25
- /** Use the visual folder browser instead of a text input for local paths. Requires the /api/fs/list endpoint. Default: false. */
26
- readonly enableFolderBrowser?: boolean;
24
+ /**
25
+ * Native folder picker callback for desktop environments.
26
+ *
27
+ * When provided and `enableLocal` is `true`, clicking the "Local Folder"
28
+ * button invokes this callback instead of showing the manual path input.
29
+ * Should resolve to an absolute folder path, or `null` if the user
30
+ * cancelled the dialog.
31
+ *
32
+ * When not provided, falls back to the inline text input for manual
33
+ * path entry (backward compatible with web environments).
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * // Tauri desktop integration
38
+ * const browseFolder = useCallback(async () => {
39
+ * const { open } = await import("@tauri-apps/plugin-dialog");
40
+ * return open({ directory: true }) as Promise<string | null>;
41
+ * }, []);
42
+ *
43
+ * <WorkspaceEditor
44
+ * workspace={workspace}
45
+ * enableLocal
46
+ * onBrowseLocalFolder={browseFolder}
47
+ * />
48
+ * ```
49
+ */
50
+ readonly onBrowseLocalFolder?: () => Promise<string | null>;
27
51
  }
28
52
 
29
53
  type ActivePanel = "none" | "github" | "local";
30
54
 
31
- const STORAGE_KEY_LAST_FOLDER = "stigmer:folder:last-path";
32
-
33
55
  const TYPE_LABELS: Record<string, string> = {
34
56
  git: "GitHub",
35
57
  local: "Local",
@@ -72,7 +94,7 @@ export function WorkspaceEditor({
72
94
  gitHubConnection,
73
95
  enableGitHub = true,
74
96
  enableLocal = false,
75
- enableFolderBrowser = false,
97
+ onBrowseLocalFolder,
76
98
  }: WorkspaceEditorProps) {
77
99
  const [activePanel, setActivePanel] = useState<ActivePanel>(
78
100
  enableGitHub ? "github" : "none",
@@ -81,18 +103,7 @@ export function WorkspaceEditor({
81
103
  const [manualBranch, setManualBranch] = useState("");
82
104
  const entryList = useScrollShadows();
83
105
  const [localPath, setLocalPath] = useState("");
84
- const [lastFolderPath, setLastFolderPath] = useState<string | undefined>(
85
- () => {
86
- if (typeof window === "undefined") return undefined;
87
- return localStorage.getItem(STORAGE_KEY_LAST_FOLDER) ?? undefined;
88
- },
89
- );
90
-
91
- useEffect(() => {
92
- if (lastFolderPath) {
93
- localStorage.setItem(STORAGE_KEY_LAST_FOLDER, lastFolderPath);
94
- }
95
- }, [lastFolderPath]);
106
+ const [isBrowsing, setIsBrowsing] = useState(false);
96
107
 
97
108
  const handleGitHubSelect = useCallback(
98
109
  (repoUrl: string, branch: string) => {
@@ -119,6 +130,19 @@ export function WorkspaceEditor({
119
130
  }
120
131
  }, [localPath, workspace]);
121
132
 
133
+ const handleBrowseLocalFolder = useCallback(async () => {
134
+ if (!onBrowseLocalFolder || isBrowsing) return;
135
+ setIsBrowsing(true);
136
+ try {
137
+ const path = await onBrowseLocalFolder();
138
+ if (path) {
139
+ workspace.addLocalPath(path);
140
+ }
141
+ } finally {
142
+ setIsBrowsing(false);
143
+ }
144
+ }, [onBrowseLocalFolder, isBrowsing, workspace]);
145
+
122
146
  const handleKeyDown = useCallback(
123
147
  (handler: () => void) => (e: KeyboardEvent<HTMLInputElement>) => {
124
148
  if (e.key === "Enter") {
@@ -147,7 +171,7 @@ export function WorkspaceEditor({
147
171
  {workspace.entries.map((entry) => (
148
172
  <div
149
173
  key={entry.id}
150
- className="flex items-center gap-2 rounded-md border border-border bg-muted/30 px-2.5 py-1.5 text-xs"
174
+ className="flex items-center gap-2 rounded-md border border-border bg-muted-faint px-2.5 py-1.5 text-xs"
151
175
  >
152
176
  <span className="shrink-0 rounded bg-muted px-1.5 py-0.5 text-[0.65rem] text-muted-foreground">
153
177
  {TYPE_LABELS[entry.type] ?? entry.type}
@@ -189,7 +213,7 @@ export function WorkspaceEditor({
189
213
  "flex items-center gap-1.5 rounded-md px-2 py-1.5 text-xs transition-colors disabled:pointer-events-none disabled:opacity-50",
190
214
  activePanel === "github"
191
215
  ? "bg-accent text-foreground"
192
- : "text-muted-foreground hover:text-foreground hover:bg-accent/50",
216
+ : "text-muted-foreground hover:text-foreground hover:bg-accent-hover",
193
217
  ].join(" ")}
194
218
  >
195
219
  <GitHubIcon />
@@ -200,17 +224,17 @@ export function WorkspaceEditor({
200
224
  {enableLocal && (
201
225
  <button
202
226
  type="button"
203
- onClick={() => togglePanel("local")}
204
- disabled={disabled}
227
+ onClick={onBrowseLocalFolder ? handleBrowseLocalFolder : () => togglePanel("local")}
228
+ disabled={disabled || isBrowsing}
205
229
  className={[
206
230
  "flex items-center gap-1.5 rounded-md px-2 py-1.5 text-xs transition-colors disabled:pointer-events-none disabled:opacity-50",
207
231
  activePanel === "local"
208
232
  ? "bg-accent text-foreground"
209
- : "text-muted-foreground hover:text-foreground hover:bg-accent/50",
233
+ : "text-muted-foreground hover:text-foreground hover:bg-accent-hover",
210
234
  ].join(" ")}
211
235
  >
212
236
  <FolderIcon />
213
- <span>Local Folder</span>
237
+ <span>{isBrowsing ? "Opening\u2026" : "Local Folder"}</span>
214
238
  </button>
215
239
  )}
216
240
  </div>
@@ -241,46 +265,34 @@ export function WorkspaceEditor({
241
265
  {/* Local folder panel */}
242
266
  {activePanel === "local" && (
243
267
  <div className="rounded-md border border-border bg-card p-3">
244
- {enableFolderBrowser ? (
245
- <FolderBrowser
246
- initialPath={lastFolderPath}
247
- onSelect={(path) => {
248
- setLastFolderPath(path);
249
- workspace.addLocalPath(path);
250
- setActivePanel("none");
251
- }}
252
- onCancel={() => setActivePanel("none")}
268
+ <div className="space-y-2">
269
+ <input
270
+ type="text"
271
+ placeholder="/path/to/project"
272
+ value={localPath}
273
+ onChange={(e) => setLocalPath(e.target.value)}
274
+ onKeyDown={handleKeyDown(handleLocalAdd)}
275
+ className="w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-xs text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
276
+ autoFocus
253
277
  />
254
- ) : (
255
- <div className="space-y-2">
256
- <input
257
- type="text"
258
- placeholder="/path/to/project"
259
- value={localPath}
260
- onChange={(e) => setLocalPath(e.target.value)}
261
- onKeyDown={handleKeyDown(handleLocalAdd)}
262
- className="w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-xs text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
263
- autoFocus
264
- />
265
- <div className="flex justify-end gap-2">
266
- <button
267
- type="button"
268
- onClick={() => setActivePanel("none")}
269
- className="rounded-md px-2.5 py-1 text-xs text-muted-foreground hover:text-foreground transition-colors"
270
- >
271
- Cancel
272
- </button>
273
- <button
274
- type="button"
275
- onClick={handleLocalAdd}
276
- disabled={!localPath.trim()}
277
- className="rounded-md bg-primary px-2.5 py-1 text-xs text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-40"
278
- >
279
- Add
280
- </button>
281
- </div>
278
+ <div className="flex justify-end gap-2">
279
+ <button
280
+ type="button"
281
+ onClick={() => setActivePanel("none")}
282
+ className="rounded-md px-2.5 py-1 text-xs text-muted-foreground hover:text-foreground transition-colors"
283
+ >
284
+ Cancel
285
+ </button>
286
+ <button
287
+ type="button"
288
+ onClick={handleLocalAdd}
289
+ disabled={!localPath.trim()}
290
+ className="rounded-md bg-primary px-2.5 py-1 text-xs text-primary-foreground hover:bg-primary-hover transition-colors disabled:opacity-40"
291
+ >
292
+ Add
293
+ </button>
282
294
  </div>
283
- )}
295
+ </div>
284
296
  </div>
285
297
  )}
286
298
  </div>
@@ -355,7 +367,7 @@ function GitHubPanel({
355
367
  <button
356
368
  type="button"
357
369
  onClick={() => connection.connect(redirectUri)}
358
- className="inline-flex items-center gap-2 rounded-md bg-foreground px-3 py-1.5 text-xs text-background hover:bg-foreground/90 transition-colors"
370
+ className="inline-flex items-center gap-2 rounded-md bg-foreground px-3 py-1.5 text-xs text-background hover:bg-foreground-hover transition-colors"
359
371
  >
360
372
  <GitHubIcon />
361
373
  <span>Continue with redirect</span>
@@ -366,7 +378,7 @@ function GitHubPanel({
366
378
  <button
367
379
  type="button"
368
380
  onClick={() => connection.connect(redirectUri, { popup: true })}
369
- className="inline-flex items-center gap-2 rounded-md bg-foreground px-3 py-1.5 text-xs text-background hover:bg-foreground/90 transition-colors"
381
+ className="inline-flex items-center gap-2 rounded-md bg-foreground px-3 py-1.5 text-xs text-background hover:bg-foreground-hover transition-colors"
370
382
  >
371
383
  <GitHubIcon />
372
384
  <span>Connect GitHub</span>
@@ -467,7 +479,7 @@ function ManualGitPanel({
467
479
  type="button"
468
480
  onClick={onAdd}
469
481
  disabled={!url.trim()}
470
- className="rounded-md bg-primary px-2.5 py-1 text-xs text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-40"
482
+ className="rounded-md bg-primary px-2.5 py-1 text-xs text-primary-foreground hover:bg-primary-hover transition-colors disabled:opacity-40"
471
483
  >
472
484
  Add
473
485
  </button>
@@ -5,13 +5,5 @@ export type {
5
5
  } from "./useWorkspaceEntries";
6
6
  export { WorkspaceEditor } from "./WorkspaceEditor";
7
7
  export type { WorkspaceEditorProps } from "./WorkspaceEditor";
8
- export { useFolderListing } from "./useFolderListing";
9
- export type {
10
- FolderEntry,
11
- FolderListing,
12
- UseFolderListingReturn,
13
- } from "./useFolderListing";
14
- export { FolderBrowser } from "./FolderBrowser";
15
- export type { FolderBrowserProps } from "./FolderBrowser";
16
8
  export { WorkspaceSummary } from "./WorkspaceSummary";
17
9
  export type { WorkspaceSummaryProps } from "./WorkspaceSummary";