@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.
- package/README.md +57 -12
- package/agent/AgentDetailView.js +7 -7
- package/agent/AgentDetailView.js.map +1 -1
- package/agent/AgentPicker.js +3 -3
- package/agent/AgentPicker.js.map +1 -1
- package/api-key/ApiKeyCreatedAlert.js +1 -1
- package/api-key/ApiKeyCreatedAlert.js.map +1 -1
- package/api-key/ApiKeyListPanel.js +4 -4
- package/api-key/ApiKeyListPanel.js.map +1 -1
- package/api-key/CreateApiKeyForm.js +1 -1
- package/api-key/CreateApiKeyForm.js.map +1 -1
- package/attachment/AttachmentChipList.js +2 -2
- package/attachment/AttachmentChipList.js.map +1 -1
- package/color-mode.d.ts +48 -0
- package/color-mode.d.ts.map +1 -0
- package/color-mode.js +53 -0
- package/color-mode.js.map +1 -0
- package/composer/ComposerToolbar.d.ts +6 -2
- package/composer/ComposerToolbar.d.ts.map +1 -1
- package/composer/ComposerToolbar.js +5 -3
- package/composer/ComposerToolbar.js.map +1 -1
- package/composer/ConfigureMenu.js +3 -3
- package/composer/ConfigureMenu.js.map +1 -1
- package/composer/ContextChip.js +1 -1
- package/composer/ContextChip.js.map +1 -1
- package/composer/ContextPopover.js +1 -1
- package/composer/ContextPopover.js.map +1 -1
- package/composer/SessionComposer.d.ts +24 -3
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +5 -4
- package/composer/SessionComposer.js.map +1 -1
- package/environment/CreateEnvironmentForm.js +1 -1
- package/environment/CreateEnvironmentForm.js.map +1 -1
- package/environment/EnvVarForm.js +2 -2
- package/environment/EnvVarForm.js.map +1 -1
- package/environment/EnvironmentListPanel.js +2 -2
- package/environment/EnvironmentListPanel.js.map +1 -1
- package/environment/EnvironmentVariableEditor.js +6 -6
- package/environment/EnvironmentVariableEditor.js.map +1 -1
- package/error/ErrorMessage.js +1 -1
- package/error/ErrorMessage.js.map +1 -1
- package/execution/ApprovalCard.js +4 -4
- package/execution/ApprovalCard.js.map +1 -1
- package/execution/ArtifactCard.js +1 -1
- package/execution/ArtifactCard.js.map +1 -1
- package/execution/ArtifactPreviewModal.js +4 -4
- package/execution/ArtifactPreviewModal.js.map +1 -1
- package/execution/FollowUpInput.js +1 -1
- package/execution/FollowUpInput.js.map +1 -1
- package/execution/McpToolDetail.js +4 -4
- package/execution/McpToolDetail.js.map +1 -1
- package/execution/MessageEntry.js +1 -1
- package/execution/MessageEntry.js.map +1 -1
- package/execution/MessageThread.js +1 -1
- package/execution/MessageThread.js.map +1 -1
- package/execution/SessionVariablesInput.js +4 -4
- package/execution/SessionVariablesInput.js.map +1 -1
- package/execution/SubAgentSection.js +2 -2
- package/execution/SubAgentSection.js.map +1 -1
- package/execution/ToolCallDetail.js +2 -2
- package/execution/ToolCallDetail.js.map +1 -1
- package/execution/ToolCallGroup.js +1 -1
- package/execution/ToolCallGroup.js.map +1 -1
- package/execution/ToolCallItem.js +2 -2
- package/execution/ToolCallItem.js.map +1 -1
- package/execution/WriteBackCard.js +3 -3
- package/execution/WriteBackCard.js.map +1 -1
- package/execution/tool-rendering-primitives.js +3 -3
- package/execution/tool-rendering-primitives.js.map +1 -1
- package/github/GitHubRepoPicker.js +5 -5
- package/github/GitHubRepoPicker.js.map +1 -1
- package/iam-policy/GrantAccessForm.js +1 -1
- package/iam-policy/GrantAccessForm.js.map +1 -1
- package/iam-policy/OrgMembersPanel.js +5 -5
- package/iam-policy/OrgMembersPanel.js.map +1 -1
- package/identity-provider/CreateIdentityProviderForm.js +3 -3
- package/identity-provider/CreateIdentityProviderForm.js.map +1 -1
- package/identity-provider/IdentityProviderDetailPanel.js +5 -5
- package/identity-provider/IdentityProviderDetailPanel.js.map +1 -1
- package/identity-provider/IdentityProviderListPanel.js +3 -3
- package/identity-provider/IdentityProviderListPanel.js.map +1 -1
- package/identity-provider/IdentityProviderWizard.js +7 -7
- package/identity-provider/IdentityProviderWizard.js.map +1 -1
- package/identity-provider/ProviderPicker.js +2 -2
- package/identity-provider/ProviderPicker.js.map +1 -1
- package/index.d.ts +8 -4
- package/index.d.ts.map +1 -1
- package/index.js +7 -3
- package/index.js.map +1 -1
- package/internal/CloudFeatureNotice.js +1 -1
- package/internal/CloudFeatureNotice.js.map +1 -1
- package/internal/Tabs.js +1 -1
- package/internal/Tabs.js.map +1 -1
- package/internal/markdown-components.js +2 -2
- package/internal/markdown-components.js.map +1 -1
- package/invitation/InvitationCreatedAlert.js +1 -1
- package/invitation/InvitationCreatedAlert.js.map +1 -1
- package/invitation/InvitationManager.js +5 -5
- package/invitation/InvitationManager.js.map +1 -1
- package/invitation/InvitationRedemption.js +4 -4
- package/invitation/InvitationRedemption.js.map +1 -1
- package/library/ResourceCountCard.js +1 -1
- package/library/ResourceCountCard.js.map +1 -1
- package/library/ResourceListView.js +5 -5
- package/library/ResourceListView.js.map +1 -1
- package/mcp-server/McpServerConfigPanel.js +5 -5
- package/mcp-server/McpServerConfigPanel.js.map +1 -1
- package/mcp-server/McpServerConnectDialog.js +4 -4
- package/mcp-server/McpServerConnectDialog.js.map +1 -1
- package/mcp-server/McpServerDetailView.js +14 -14
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/mcp-server/McpServerPicker.js +4 -4
- package/mcp-server/McpServerPicker.js.map +1 -1
- package/mcp-server/McpToolSelector.js +3 -3
- package/mcp-server/McpToolSelector.js.map +1 -1
- package/mcp-server/OAuthAppForm.js +1 -1
- package/mcp-server/OAuthAppForm.js.map +1 -1
- package/models/ModelSelector.js +1 -1
- package/models/ModelSelector.js.map +1 -1
- package/oauth-app/CreateOAuthAppForm.js +1 -1
- package/oauth-app/CreateOAuthAppForm.js.map +1 -1
- package/oauth-app/OAuthAppDetailPanel.js +3 -3
- package/oauth-app/OAuthAppDetailPanel.js.map +1 -1
- package/oauth-app/OAuthAppListPanel.js +2 -2
- package/oauth-app/OAuthAppListPanel.js.map +1 -1
- package/organization/CreateOrganizationForm.js +1 -1
- package/organization/CreateOrganizationForm.js.map +1 -1
- package/organization/OrgProfilePanel.js +3 -3
- package/organization/OrgProfilePanel.js.map +1 -1
- package/package.json +4 -4
- package/platform-client/CreatePlatformClientForm.js +2 -2
- package/platform-client/CreatePlatformClientForm.js.map +1 -1
- package/platform-client/PlatformClientDetailPanel.js +4 -4
- package/platform-client/PlatformClientDetailPanel.js.map +1 -1
- package/platform-client/PlatformClientListPanel.js +3 -3
- package/platform-client/PlatformClientListPanel.js.map +1 -1
- package/platform-client/PlatformClientSecretAlert.js +2 -2
- package/platform-client/PlatformClientSecretAlert.js.map +1 -1
- package/provider.d.ts +39 -2
- package/provider.d.ts.map +1 -1
- package/provider.js +11 -3
- package/provider.js.map +1 -1
- package/runner/RunnerListPanel.d.ts +65 -0
- package/runner/RunnerListPanel.d.ts.map +1 -0
- package/runner/RunnerListPanel.js +237 -0
- package/runner/RunnerListPanel.js.map +1 -0
- package/runner/RunnerPicker.d.ts +54 -0
- package/runner/RunnerPicker.d.ts.map +1 -0
- package/runner/RunnerPicker.js +133 -0
- package/runner/RunnerPicker.js.map +1 -0
- package/runner/__tests__/useDeleteRunner.test.d.ts +2 -0
- package/runner/__tests__/useDeleteRunner.test.d.ts.map +1 -0
- package/runner/__tests__/useDeleteRunner.test.js +108 -0
- package/runner/__tests__/useDeleteRunner.test.js.map +1 -0
- package/runner/__tests__/useLaunchLocalRunner.test.d.ts +2 -0
- package/runner/__tests__/useLaunchLocalRunner.test.d.ts.map +1 -0
- package/runner/__tests__/useLaunchLocalRunner.test.js +143 -0
- package/runner/__tests__/useLaunchLocalRunner.test.js.map +1 -0
- package/runner/__tests__/useStopRunner.test.d.ts +2 -0
- package/runner/__tests__/useStopRunner.test.d.ts.map +1 -0
- package/runner/__tests__/useStopRunner.test.js +114 -0
- package/runner/__tests__/useStopRunner.test.js.map +1 -0
- package/runner/index.d.ts +14 -0
- package/runner/index.d.ts.map +1 -0
- package/runner/index.js +8 -0
- package/runner/index.js.map +1 -0
- package/runner/phase.d.ts +30 -0
- package/runner/phase.d.ts.map +1 -0
- package/runner/phase.js +58 -0
- package/runner/phase.js.map +1 -0
- package/runner/useDeleteRunner.d.ts +36 -0
- package/runner/useDeleteRunner.d.ts.map +1 -0
- package/runner/useDeleteRunner.js +42 -0
- package/runner/useDeleteRunner.js.map +1 -0
- package/runner/useLaunchLocalRunner.d.ts +84 -0
- package/runner/useLaunchLocalRunner.d.ts.map +1 -0
- package/runner/useLaunchLocalRunner.js +75 -0
- package/runner/useLaunchLocalRunner.js.map +1 -0
- package/runner/useRunnerList.d.ts +49 -0
- package/runner/useRunnerList.d.ts.map +1 -0
- package/runner/useRunnerList.js +70 -0
- package/runner/useRunnerList.js.map +1 -0
- package/runner/useStopRunner.d.ts +53 -0
- package/runner/useStopRunner.d.ts.map +1 -0
- package/runner/useStopRunner.js +50 -0
- package/runner/useStopRunner.js.map +1 -0
- package/session/draft.d.ts +53 -0
- package/session/draft.d.ts.map +1 -0
- package/session/draft.js +45 -0
- package/session/draft.js.map +1 -0
- package/session/index.d.ts +10 -0
- package/session/index.d.ts.map +1 -1
- package/session/index.js +5 -0
- package/session/index.js.map +1 -1
- package/session/useCreateSession.d.ts +8 -0
- package/session/useCreateSession.d.ts.map +1 -1
- package/session/useCreateSession.js +1 -0
- package/session/useCreateSession.js.map +1 -1
- package/session/useEditSessionPrep.d.ts +26 -0
- package/session/useEditSessionPrep.d.ts.map +1 -0
- package/session/useEditSessionPrep.js +83 -0
- package/session/useEditSessionPrep.js.map +1 -0
- package/session/useNewSessionFlow.d.ts +110 -0
- package/session/useNewSessionFlow.d.ts.map +1 -0
- package/session/useNewSessionFlow.js +184 -0
- package/session/useNewSessionFlow.js.map +1 -0
- package/session/usePersistedModel.d.ts +18 -0
- package/session/usePersistedModel.d.ts.map +1 -0
- package/session/usePersistedModel.js +31 -0
- package/session/usePersistedModel.js.map +1 -0
- package/session/useSessionPageFlow.d.ts +104 -0
- package/session/useSessionPageFlow.d.ts.map +1 -0
- package/session/useSessionPageFlow.js +172 -0
- package/session/useSessionPageFlow.js.map +1 -0
- package/skill/SkillDetailView.js +3 -3
- package/skill/SkillDetailView.js.map +1 -1
- package/skill/SkillPicker.js +3 -3
- package/skill/SkillPicker.js.map +1 -1
- package/src/agent/AgentDetailView.tsx +8 -8
- package/src/agent/AgentPicker.tsx +3 -3
- package/src/api-key/ApiKeyCreatedAlert.tsx +2 -2
- package/src/api-key/ApiKeyListPanel.tsx +6 -6
- package/src/api-key/CreateApiKeyForm.tsx +2 -2
- package/src/attachment/AttachmentChipList.tsx +3 -3
- package/src/color-mode.ts +75 -0
- package/src/composer/ComposerToolbar.tsx +29 -7
- package/src/composer/ConfigureMenu.tsx +6 -6
- package/src/composer/ContextChip.tsx +1 -1
- package/src/composer/ContextPopover.tsx +2 -2
- package/src/composer/SessionComposer.tsx +34 -5
- package/src/environment/CreateEnvironmentForm.tsx +3 -3
- package/src/environment/EnvVarForm.tsx +6 -6
- package/src/environment/EnvironmentListPanel.tsx +3 -3
- package/src/environment/EnvironmentVariableEditor.tsx +7 -7
- package/src/error/ErrorMessage.tsx +5 -5
- package/src/execution/ApprovalCard.tsx +5 -5
- package/src/execution/ArtifactCard.tsx +2 -2
- package/src/execution/ArtifactPreviewModal.tsx +4 -4
- package/src/execution/FollowUpInput.tsx +2 -2
- package/src/execution/McpToolDetail.tsx +4 -4
- package/src/execution/MessageEntry.tsx +1 -1
- package/src/execution/MessageThread.tsx +1 -1
- package/src/execution/SessionVariablesInput.tsx +7 -7
- package/src/execution/SubAgentSection.tsx +5 -5
- package/src/execution/ToolCallDetail.tsx +2 -2
- package/src/execution/ToolCallGroup.tsx +3 -3
- package/src/execution/ToolCallItem.tsx +4 -4
- package/src/execution/WriteBackCard.tsx +5 -5
- package/src/execution/tool-rendering-primitives.tsx +5 -5
- package/src/github/GitHubRepoPicker.tsx +5 -5
- package/src/iam-policy/GrantAccessForm.tsx +2 -2
- package/src/iam-policy/OrgMembersPanel.tsx +11 -11
- package/src/identity-provider/CreateIdentityProviderForm.tsx +4 -4
- package/src/identity-provider/IdentityProviderDetailPanel.tsx +7 -7
- package/src/identity-provider/IdentityProviderListPanel.tsx +7 -7
- package/src/identity-provider/IdentityProviderWizard.tsx +8 -8
- package/src/identity-provider/ProviderPicker.tsx +2 -2
- package/src/index.ts +46 -7
- package/src/internal/CloudFeatureNotice.tsx +1 -1
- package/src/internal/Tabs.tsx +1 -1
- package/src/internal/markdown-components.tsx +2 -2
- package/src/invitation/InvitationCreatedAlert.tsx +2 -2
- package/src/invitation/InvitationManager.tsx +9 -9
- package/src/invitation/InvitationRedemption.tsx +11 -11
- package/src/library/ResourceCountCard.tsx +1 -1
- package/src/library/ResourceListView.tsx +7 -7
- package/src/mcp-server/McpServerConfigPanel.tsx +7 -7
- package/src/mcp-server/McpServerConnectDialog.tsx +5 -5
- package/src/mcp-server/McpServerDetailView.tsx +19 -19
- package/src/mcp-server/McpServerPicker.tsx +6 -6
- package/src/mcp-server/McpToolSelector.tsx +4 -4
- package/src/mcp-server/OAuthAppForm.tsx +3 -3
- package/src/models/ModelSelector.tsx +1 -1
- package/src/oauth-app/CreateOAuthAppForm.tsx +3 -3
- package/src/oauth-app/OAuthAppDetailPanel.tsx +7 -7
- package/src/oauth-app/OAuthAppListPanel.tsx +3 -3
- package/src/organization/CreateOrganizationForm.tsx +3 -3
- package/src/organization/OrgProfilePanel.tsx +4 -5
- package/src/platform-client/CreatePlatformClientForm.tsx +6 -6
- package/src/platform-client/PlatformClientDetailPanel.tsx +19 -19
- package/src/platform-client/PlatformClientListPanel.tsx +7 -7
- package/src/platform-client/PlatformClientSecretAlert.tsx +2 -2
- package/src/provider.tsx +52 -2
- package/src/runner/RunnerListPanel.tsx +725 -0
- package/src/runner/RunnerPicker.tsx +319 -0
- package/src/runner/__tests__/useDeleteRunner.test.tsx +150 -0
- package/src/runner/__tests__/useLaunchLocalRunner.test.tsx +223 -0
- package/src/runner/__tests__/useStopRunner.test.tsx +154 -0
- package/src/runner/index.ts +34 -0
- package/src/runner/phase.ts +62 -0
- package/src/runner/useDeleteRunner.ts +67 -0
- package/src/runner/useLaunchLocalRunner.ts +139 -0
- package/src/runner/useRunnerList.ts +114 -0
- package/src/runner/useStopRunner.ts +92 -0
- package/src/session/draft.ts +82 -0
- package/src/session/index.ts +28 -0
- package/src/session/useCreateSession.ts +9 -0
- package/src/session/useEditSessionPrep.ts +111 -0
- package/src/session/useNewSessionFlow.ts +283 -0
- package/src/session/usePersistedModel.ts +41 -0
- package/src/session/useSessionPageFlow.ts +280 -0
- package/src/skill/SkillDetailView.tsx +5 -5
- package/src/skill/SkillPicker.tsx +3 -3
- package/src/styles.css +25 -1
- package/src/usage/OrgUsagePanel.tsx +4 -4
- package/src/workspace/WorkspaceEditor.tsx +78 -66
- package/src/workspace/index.ts +0 -8
- package/styles.css +1 -1
- package/usage/OrgUsagePanel.js +2 -2
- package/usage/OrgUsagePanel.js.map +1 -1
- package/workspace/WorkspaceEditor.d.ts +28 -3
- package/workspace/WorkspaceEditor.d.ts.map +1 -1
- package/workspace/WorkspaceEditor.js +24 -25
- package/workspace/WorkspaceEditor.js.map +1 -1
- package/workspace/index.d.ts +0 -4
- package/workspace/index.d.ts.map +1 -1
- package/workspace/index.js +0 -2
- package/workspace/index.js.map +1 -1
- package/src/workspace/FolderBrowser.tsx +0 -579
- package/src/workspace/useFolderListing.ts +0 -164
- package/workspace/FolderBrowser.d.ts +0 -37
- package/workspace/FolderBrowser.d.ts.map +0 -1
- package/workspace/FolderBrowser.js +0 -188
- package/workspace/FolderBrowser.js.map +0 -1
- package/workspace/useFolderListing.d.ts +0 -73
- package/workspace/useFolderListing.d.ts.map +0 -1
- package/workspace/useFolderListing.js +0 -110
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
427
|
+
<p className="text-xs text-muted-foreground-subtle">
|
|
428
428
|
This skill doesn't exist or you don'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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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
|
-
/**
|
|
26
|
-
|
|
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
|
-
|
|
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 [
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
245
|
-
<
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
|
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
|
|
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
|
|
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>
|
package/src/workspace/index.ts
CHANGED
|
@@ -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";
|