@nextclaw/ui 0.14.1-beta.1 → 0.14.2
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/CHANGELOG.md +61 -0
- package/dist/assets/{api-dQ6uQSZG.js → api-a14tR_z1.js} +7 -7
- package/dist/assets/channels-list-page-CFGkm4DT.js +8 -0
- package/dist/assets/chat-page-CEdavJXc.js +105 -0
- package/dist/assets/{config-split-page-CeFfbaqc.js → config-split-page-B5b9B0uE.js} +1 -1
- package/dist/assets/{confirm-dialog-C95Y4QPC.js → confirm-dialog-ClH_Ec7n.js} +1 -1
- package/dist/assets/{desktop-update-config-CcK6jiEb.js → desktop-update-config-DPNDnVpk.js} +1 -1
- package/dist/assets/{dist-DTGzeil6.js → dist-BtCS2Ucq.js} +1 -1
- package/dist/assets/{dist-fGogBmPA.js → dist-CLGGLm8b.js} +1 -1
- package/dist/assets/doc-browser-5nMWYKBD.js +1 -0
- package/dist/assets/doc-browser-BJRLhztv.js +1 -0
- package/dist/assets/doc-browser-context-D4JwMMxK.js +1 -0
- package/dist/assets/{ellipsis-D2F4KMiU.js → ellipsis-CtJXjIol.js} +1 -1
- package/dist/assets/{external-link-CcgtBK26.js → external-link-CdJiG13p.js} +1 -1
- package/dist/assets/index-BDN1zzMQ.js +105 -0
- package/dist/assets/index-g3uSZXoc.css +1 -0
- package/dist/assets/mcp-marketplace-page-BU0kIjhR.js +40 -0
- package/dist/assets/mcp-marketplace-page-sMNFSq_T.js +1 -0
- package/dist/assets/middleware-CkFT3R4v.js +1 -0
- package/dist/assets/model-config-page-D6hYXROd.js +1 -0
- package/dist/assets/plus-DPjb0piO.js +1 -0
- package/dist/assets/provider-scoped-model-input-DAX2HgmR.js +1 -0
- package/dist/assets/providers-config-page-BzAeaACA.js +1 -0
- package/dist/assets/{react-CTqdhFMk.js → react-C6cZgP44.js} +1 -1
- package/dist/assets/remote-B0G80uPr.js +1 -0
- package/dist/assets/rotate-cw-DnEB1Rju.js +1 -0
- package/dist/assets/runtime-config-page-C5xKaV3i.js +1 -0
- package/dist/assets/{save-C9fKWfVB.js → save-DKA0x4zk.js} +1 -1
- package/dist/assets/{search-D5FQ5q0X.js → search-BNlcoj5c.js} +1 -1
- package/dist/assets/{search-config-page-AMEJJNIS.js → search-config-page-Cq9uJ-N8.js} +1 -1
- package/dist/assets/{secrets-config-page-CcgJnvBO.js → secrets-config-page-CxSbZLBo.js} +2 -2
- package/dist/assets/{select-Cu5n0E-3.js → select-CvTlDZTQ.js} +1 -1
- package/dist/assets/{tag-chip-C5aOtjxu.js → tag-chip-8ffF2y2C.js} +1 -1
- package/dist/assets/use-config-DmT0o1gv.js +1 -0
- package/dist/assets/x-BiSSpgqB.js +1 -0
- package/dist/index.html +15 -14
- package/package.json +9 -9
- package/src/app/components/app-presenter-provider.tsx +11 -2
- package/src/app/components/layout/__tests__/app-layout.test.tsx +11 -2
- package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +110 -79
- package/src/app/components/layout/app-layout.tsx +18 -4
- package/src/app/components/layout/sidebar-items.tsx +194 -71
- package/src/app/components/layout/sidebar-rail.styles.ts +15 -0
- package/src/app/components/layout/sidebar.tsx +340 -83
- package/src/app/managers/viewport-layout.manager.ts +10 -0
- package/src/app/stores/viewport-layout.store.ts +39 -3
- package/src/features/agents/components/__tests__/agents-page.test.tsx +62 -39
- package/src/features/agents/components/agents-page.tsx +10 -6
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +145 -0
- package/src/features/chat/components/conversation/__tests__/chat-conversation-panel.test.tsx +69 -762
- package/src/features/chat/components/conversation/__tests__/chat-conversation-workspace-section.test.tsx +132 -0
- package/src/features/chat/components/conversation/chat-conversation-content.tsx +22 -15
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +14 -15
- package/src/features/chat/components/conversation/chat-conversation-panel.tsx +18 -18
- package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +10 -4
- package/src/features/chat/components/layout/__tests__/chat-sidebar-read-state.test.tsx +52 -11
- package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +77 -12
- package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +247 -0
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +182 -21
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +82 -25
- package/src/features/chat/components/layout/chat-sidebar.tsx +79 -93
- package/src/features/chat/components/providers/chat-presenter.provider.tsx +0 -6
- package/src/features/chat/features/conversation/components/session-conversation-area.tsx +289 -0
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +427 -0
- package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +204 -0
- package/src/features/chat/features/conversation/hooks/use-session-conversation-input-attachments.ts +66 -0
- package/src/features/chat/features/{input/hooks/use-chat-input-bar-query-state.ts → conversation/hooks/use-session-conversation-input-query.ts} +32 -17
- package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +281 -0
- package/src/features/chat/features/conversation/utils/session-conversation-input-toolbar.utils.ts +158 -0
- package/src/features/chat/features/input/hooks/__tests__/use-chat-input-surface-state.test.tsx +56 -0
- package/src/features/chat/features/input/hooks/use-chat-input-surface-state.ts +117 -0
- package/src/features/chat/features/input/hooks/use-chat-model-favorites.ts +2 -1
- package/src/features/chat/features/input/input-surface-plugins/__tests__/panel-app-reference-plugin.test.ts +77 -0
- package/src/features/chat/features/input/input-surface-plugins/__tests__/slash-command-plugin.test.ts +108 -0
- package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.types.ts +10 -0
- package/src/features/chat/features/input/input-surface-plugins/input-surface-search.utils.ts +108 -0
- package/src/features/chat/features/input/input-surface-plugins/panel-app-reference-plugin.utils.ts +108 -0
- package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +161 -0
- package/src/features/chat/features/input/utils/__tests__/chat-composer-state.utils.test.ts +22 -1
- package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +26 -13
- package/src/features/chat/features/input/utils/__tests__/ncp-chat-input-availability.utils.test.ts +7 -28
- package/src/features/chat/features/input/utils/chat-composer-state.utils.ts +6 -0
- package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +26 -51
- package/src/features/chat/features/input/utils/chat-input-bar.utils.ts +2 -0
- package/src/features/chat/features/input/utils/ncp-chat-input-availability.utils.ts +5 -6
- package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +47 -12
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +93 -12
- package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +31 -12
- package/src/features/chat/features/message/utils/chat-message-markdown-part.utils.ts +38 -0
- package/src/features/chat/features/message/utils/chat-message-part.utils.ts +1 -1
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +5 -4
- package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +2 -2
- package/src/features/chat/features/session/hooks/__tests__/use-chat-session-project.test.tsx +3 -30
- package/src/features/chat/features/session/hooks/use-chat-session-project.ts +0 -5
- package/src/features/chat/features/session/utils/chat-run-metadata.utils.ts +8 -0
- package/src/features/chat/features/session-type/components/__tests__/{chat-sidebar-create-menu.test.tsx → chat-session-type-menu.test.tsx} +5 -5
- package/src/features/chat/features/session-type/components/__tests__/chat-session-type-option-item.test.tsx +29 -1
- package/src/features/chat/features/session-type/components/{chat-sidebar-create-menu.tsx → chat-session-type-menu.tsx} +13 -9
- package/src/features/chat/features/session-type/components/chat-session-type-option-item.tsx +17 -5
- package/src/features/chat/features/session-type/hooks/__tests__/use-chat-new-session-type-preference.test.tsx +152 -0
- package/src/features/chat/features/session-type/hooks/use-chat-new-session-type-preference.ts +159 -0
- package/src/features/chat/features/welcome/components/__tests__/chat-conversation-welcome.test.tsx +49 -31
- package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +2 -2
- package/src/features/chat/features/welcome/components/chat-conversation-welcome.tsx +21 -10
- package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +2 -2
- package/src/features/chat/features/welcome/components/chat-welcome.tsx +2 -2
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +54 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +44 -76
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +5 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +7 -1
- package/src/features/chat/features/workspace/hooks/use-chat-conversation-workspace-state.ts +40 -31
- package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +59 -1
- package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +109 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +44 -4
- package/src/features/chat/index.ts +0 -1
- package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +51 -99
- package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +135 -21
- package/src/features/chat/managers/chat-session-list.manager.ts +12 -43
- package/src/features/chat/managers/chat-thread.manager.ts +108 -34
- package/src/features/chat/pages/__tests__/ncp-chat-page.test.ts +48 -1
- package/src/features/chat/pages/__tests__/ncp-chat-page.test.tsx +72 -0
- package/src/features/chat/pages/ncp-chat-page.tsx +0 -122
- package/src/features/chat/presenters/chat.presenter.ts +2 -19
- package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +31 -0
- package/src/features/chat/stores/chat-thread.store.ts +42 -26
- package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +24 -0
- package/src/features/marketplace/components/curated-shelves/marketplace-shelf-card.tsx +8 -3
- package/src/features/marketplace/components/marketplace-item-list-view.tsx +2 -2
- package/src/features/marketplace/components/marketplace-list-card.tsx +124 -98
- package/src/features/marketplace/components/marketplace-page-parts.tsx +11 -6
- package/src/features/panel-apps/hooks/use-panel-apps.ts +2 -1
- package/src/platforms/desktop/components/__tests__/desktop-app-shell.test.tsx +50 -10
- package/src/platforms/desktop/components/desktop-app-shell.tsx +34 -10
- package/src/platforms/desktop/components/desktop-window-chrome.tsx +41 -16
- package/src/shared/components/common/__tests__/agent-avatar.test.tsx +3 -1
- package/src/shared/components/common/agent-avatar.tsx +5 -2
- package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +24 -1
- package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +8 -4
- package/src/shared/lib/api/index.ts +1 -0
- package/src/shared/lib/api/preferences/preference-keys.config.ts +9 -0
- package/src/shared/lib/i18n/locales/en-US/chat.json +20 -2
- package/src/shared/lib/i18n/locales/en-US/core.json +2 -0
- package/src/shared/lib/i18n/locales/en-US/marketplace.json +2 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +20 -2
- package/src/shared/lib/i18n/locales/zh-CN/core.json +2 -0
- package/src/shared/lib/i18n/locales/zh-CN/marketplace.json +2 -0
- package/src/shared/lib/ui-document-title/__tests__/ui-document-title.test.ts +49 -0
- package/src/shared/lib/ui-document-title/index.ts +50 -21
- package/dist/assets/channels-list-page-DfpjB8XB.js +0 -8
- package/dist/assets/chat-page-D3QaEqjs.js +0 -105
- package/dist/assets/doc-browser-CuBTcBEZ.js +0 -1
- package/dist/assets/doc-browser-DVHhEb96.js +0 -1
- package/dist/assets/doc-browser-context-BfMXwnrz.js +0 -1
- package/dist/assets/index-ByJCbQqr.css +0 -1
- package/dist/assets/index-DjXqiloY.js +0 -103
- package/dist/assets/mcp-marketplace-page-98-V__3u.js +0 -1
- package/dist/assets/mcp-marketplace-page-BNq_PNmO.js +0 -40
- package/dist/assets/model-config-page-aAUkZkSX.js +0 -1
- package/dist/assets/plus-1Rxl5FlV.js +0 -1
- package/dist/assets/provider-scoped-model-input-we4_Z4gP.js +0 -1
- package/dist/assets/providers-config-page-CtMkPSyu.js +0 -1
- package/dist/assets/remote-fQ7N_r8u.js +0 -1
- package/dist/assets/rotate-cw-CzfIeAJj.js +0 -1
- package/dist/assets/runtime-config-page-TD1UrTbG.js +0 -1
- package/dist/assets/use-config-D8TESeo6.js +0 -1
- package/dist/assets/x-1qETdQ70.js +0 -1
- package/src/features/chat/components/conversation/chat-conversation-alerts.tsx +0 -37
- package/src/features/chat/features/input/components/__tests__/chat-attachment-upload-limit.test.ts +0 -38
- package/src/features/chat/features/input/components/chat-input-bar.container.tsx +0 -496
- package/src/features/chat/features/message/utils/chat-message-inline-content.utils.ts +0 -95
- package/src/features/chat/managers/__tests__/chat-input.manager.test.ts +0 -448
- package/src/features/chat/managers/__tests__/chat-run-snapshot.manager.test.ts +0 -129
- package/src/features/chat/managers/__tests__/chat-run.manager.test.ts +0 -236
- package/src/features/chat/managers/__tests__/chat-session-preference-sync.manager.test.ts +0 -219
- package/src/features/chat/managers/chat-input.manager.ts +0 -430
- package/src/features/chat/managers/chat-run.manager.ts +0 -110
- package/src/features/chat/managers/chat-session-preference-sync.manager.ts +0 -142
- package/src/features/chat/stores/chat-input.store.ts +0 -104
- /package/dist/assets/{config-hints-CTqBnCDp.js → config-hints-BkYBc7z0.js} +0 -0
|
@@ -11,41 +11,14 @@ import {
|
|
|
11
11
|
} from "@/features/chat/components/layout/chat-page-shell";
|
|
12
12
|
import { parseSessionKeyFromRoute } from "@/features/chat/features/session/utils/chat-session-route.utils";
|
|
13
13
|
import { ChatPresenter } from "@/features/chat/presenters/chat.presenter";
|
|
14
|
-
import {
|
|
15
|
-
isNcpAgentStartupUnavailableErrorMessage,
|
|
16
|
-
useNcpSessionConversation,
|
|
17
|
-
} from "@/features/chat/features/ncp/hooks/use-ncp-session-conversation";
|
|
18
|
-
import {
|
|
19
|
-
useNcpChatSelectedSession,
|
|
20
|
-
} from "@/features/chat/features/ncp/hooks/use-ncp-chat-derived-state";
|
|
21
14
|
import { useChatQueryStoreSync } from "@/features/chat/features/ncp/hooks/use-ncp-chat-query-store-sync";
|
|
22
15
|
import {
|
|
23
16
|
ChatPresenterProvider,
|
|
24
17
|
usePresenter,
|
|
25
18
|
} from "@/features/chat/components/providers/chat-presenter.provider";
|
|
26
19
|
import { useConfirmDialog } from "@/shared/hooks/use-confirm-dialog";
|
|
27
|
-
import { useSystemStatus } from "@/features/system-status";
|
|
28
20
|
import { useAppPresenter } from "@/app/components/app-presenter-provider";
|
|
29
|
-
import { isNcpChatRuntimeBlocked, resolveNcpChatSendErrorMessage } from "@/features/chat/features/runtime/utils/ncp-chat-runtime-availability.utils";
|
|
30
21
|
import { useUiShowContentEvent } from "@/features/chat/features/ncp/hooks/use-ui-show-content-event";
|
|
31
|
-
import { readNcpContextWindowValue } from "@/features/chat/features/session/utils/ncp-session-context-metadata.utils";
|
|
32
|
-
|
|
33
|
-
function useChatDraftIntentConsumer() {
|
|
34
|
-
const appPresenter = useAppPresenter();
|
|
35
|
-
const presenter = usePresenter();
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
const applyIntent = (intent: { id: number; prompt: string }) => {
|
|
38
|
-
presenter.startAgentCreationDraft(intent.prompt);
|
|
39
|
-
appPresenter.chatDraftIntentManager.markConsumed(intent.id);
|
|
40
|
-
};
|
|
41
|
-
const unsubscribe = appPresenter.chatDraftIntentManager.subscribe(applyIntent);
|
|
42
|
-
const pendingIntent = appPresenter.chatDraftIntentManager.consumePending();
|
|
43
|
-
if (pendingIntent) {
|
|
44
|
-
applyIntent(pendingIntent);
|
|
45
|
-
}
|
|
46
|
-
return unsubscribe;
|
|
47
|
-
}, [appPresenter, presenter]);
|
|
48
|
-
}
|
|
49
22
|
|
|
50
23
|
function useNcpChatRouteSelection() {
|
|
51
24
|
const { sessionId: routeSessionIdParam } = useParams<{ sessionId?: string }>();
|
|
@@ -59,31 +32,6 @@ function useNcpChatRouteSelection() {
|
|
|
59
32
|
};
|
|
60
33
|
}
|
|
61
34
|
|
|
62
|
-
type NcpChatConversation = ReturnType<typeof useNcpSessionConversation>;
|
|
63
|
-
|
|
64
|
-
function useChatRunRuntimeConnection(params: {
|
|
65
|
-
agent: NcpChatConversation;
|
|
66
|
-
sessionKey: string | undefined;
|
|
67
|
-
}) {
|
|
68
|
-
const presenter = usePresenter();
|
|
69
|
-
const { agent, sessionKey } = params;
|
|
70
|
-
useEffect(() => {
|
|
71
|
-
presenter.chatRunManager.setActiveRuntime({
|
|
72
|
-
sessionKey: sessionKey ?? null,
|
|
73
|
-
sendEnvelope: (envelope) => agent.send(envelope),
|
|
74
|
-
abortCurrentRun: () => agent.abort(),
|
|
75
|
-
resumeCurrentSessionRun: () => agent.streamRun(),
|
|
76
|
-
});
|
|
77
|
-
return () => {
|
|
78
|
-
presenter.chatRunManager.setActiveRuntime(null);
|
|
79
|
-
};
|
|
80
|
-
}, [
|
|
81
|
-
agent,
|
|
82
|
-
presenter,
|
|
83
|
-
sessionKey,
|
|
84
|
-
]);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
35
|
function useNcpChatUiBindings() {
|
|
88
36
|
const presenter = usePresenter();
|
|
89
37
|
const { confirm, ConfirmDialog } = useConfirmDialog();
|
|
@@ -101,42 +49,6 @@ function useNcpChatUiBindings() {
|
|
|
101
49
|
return <ConfirmDialog />;
|
|
102
50
|
}
|
|
103
51
|
|
|
104
|
-
function useChatRunSnapshotSync(params: {
|
|
105
|
-
agent: NcpChatConversation;
|
|
106
|
-
isSending: boolean;
|
|
107
|
-
isRunning: boolean;
|
|
108
|
-
lastSendError: string | null;
|
|
109
|
-
routeSessionKey: string | null;
|
|
110
|
-
}) {
|
|
111
|
-
const presenter = usePresenter();
|
|
112
|
-
const { agent, isRunning, isSending, lastSendError, routeSessionKey } = params;
|
|
113
|
-
useEffect(() => {
|
|
114
|
-
presenter.chatRunManager.applyRunSnapshot({
|
|
115
|
-
routeSessionKey,
|
|
116
|
-
isHydrating: agent.isHydrating,
|
|
117
|
-
isSending,
|
|
118
|
-
isRunning,
|
|
119
|
-
visibleMessages: agent.visibleMessages,
|
|
120
|
-
contextWindow: readNcpContextWindowValue(agent.snapshot.contextWindow),
|
|
121
|
-
sendErrorMessage: lastSendError,
|
|
122
|
-
materializedSessionKey:
|
|
123
|
-
agent.snapshot.activeRun?.sessionId ??
|
|
124
|
-
agent.visibleMessages.find((message) => message.sessionId.trim())?.sessionId ??
|
|
125
|
-
null,
|
|
126
|
-
});
|
|
127
|
-
}, [
|
|
128
|
-
agent.isHydrating,
|
|
129
|
-
agent.snapshot.activeRun?.sessionId,
|
|
130
|
-
agent.snapshot.contextWindow,
|
|
131
|
-
agent.visibleMessages,
|
|
132
|
-
isRunning,
|
|
133
|
-
isSending,
|
|
134
|
-
lastSendError,
|
|
135
|
-
presenter,
|
|
136
|
-
routeSessionKey,
|
|
137
|
-
]);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
52
|
export function NcpChatPage({ view }: ChatPageProps) {
|
|
141
53
|
const appPresenter = useAppPresenter();
|
|
142
54
|
const [presenter] = useState(() => new ChatPresenter(appPresenter));
|
|
@@ -149,52 +61,18 @@ export function NcpChatPage({ view }: ChatPageProps) {
|
|
|
149
61
|
|
|
150
62
|
function NcpChatPageContent({ view }: ChatPageProps) {
|
|
151
63
|
const presenter = usePresenter();
|
|
152
|
-
const systemStatus = useSystemStatus();
|
|
153
|
-
const isRuntimeBlocked = isNcpChatRuntimeBlocked(systemStatus);
|
|
154
64
|
const confirmDialog = useNcpChatUiBindings();
|
|
155
65
|
const routeSelection = useNcpChatRouteSelection();
|
|
156
66
|
const { routeSessionKey, sessionKey } = routeSelection;
|
|
157
67
|
useChatQueryStoreSync({
|
|
158
68
|
sessionKey: sessionKey ?? null,
|
|
159
69
|
});
|
|
160
|
-
const selectedSession = useNcpChatSelectedSession(sessionKey ?? null);
|
|
161
|
-
const agent = useNcpSessionConversation(sessionKey);
|
|
162
|
-
const rawLastSendError =
|
|
163
|
-
agent.hydrateError?.message ?? agent.snapshot.error?.message ?? null;
|
|
164
|
-
const filteredLastSendError =
|
|
165
|
-
systemStatus.phase === "ready" &&
|
|
166
|
-
isNcpAgentStartupUnavailableErrorMessage(rawLastSendError)
|
|
167
|
-
? null
|
|
168
|
-
: rawLastSendError;
|
|
169
|
-
const currentSessionRunning = agent.isRunning || selectedSession?.status === "running";
|
|
170
|
-
const isSending = agent.isSending || currentSessionRunning;
|
|
171
|
-
const lastSendError =
|
|
172
|
-
isRuntimeBlocked
|
|
173
|
-
? null
|
|
174
|
-
: systemStatus.phase === "ready"
|
|
175
|
-
? filteredLastSendError
|
|
176
|
-
: resolveNcpChatSendErrorMessage({
|
|
177
|
-
message: filteredLastSendError,
|
|
178
|
-
status: systemStatus,
|
|
179
|
-
});
|
|
180
|
-
useChatRunRuntimeConnection({
|
|
181
|
-
agent,
|
|
182
|
-
sessionKey,
|
|
183
|
-
});
|
|
184
70
|
useChatSessionSync({
|
|
185
71
|
view,
|
|
186
72
|
routeSessionKey,
|
|
187
73
|
syncRouteSessionSelection:
|
|
188
74
|
presenter.chatSessionListManager.syncRouteSessionSelection,
|
|
189
75
|
});
|
|
190
|
-
useChatDraftIntentConsumer();
|
|
191
76
|
useUiShowContentEvent();
|
|
192
|
-
useChatRunSnapshotSync({
|
|
193
|
-
agent,
|
|
194
|
-
isRunning: currentSessionRunning,
|
|
195
|
-
routeSessionKey,
|
|
196
|
-
lastSendError,
|
|
197
|
-
isSending,
|
|
198
|
-
});
|
|
199
77
|
return <ChatPageLayout view={view} confirmDialog={confirmDialog} />;
|
|
200
78
|
}
|
|
@@ -1,39 +1,22 @@
|
|
|
1
1
|
import { ChatSessionListManager } from '@/features/chat/managers/chat-session-list.manager';
|
|
2
|
-
import { ChatRunManager } from '@/features/chat/managers/chat-run.manager';
|
|
3
2
|
import { ChatUiManager } from '@/features/chat/managers/chat-ui.manager';
|
|
4
|
-
import { ChatInputManager } from '@/features/chat/managers/chat-input.manager';
|
|
5
3
|
import { ChatQueryManager } from '@/features/chat/managers/chat-query.manager';
|
|
6
4
|
import { ChatThreadManager } from '@/features/chat/managers/chat-thread.manager';
|
|
7
5
|
import type { AppPresenter } from '@/app/presenters/app.presenter';
|
|
8
6
|
|
|
9
7
|
export class ChatPresenter {
|
|
10
8
|
readonly chatUiManager: ChatUiManager;
|
|
11
|
-
readonly chatRunManager: ChatRunManager;
|
|
12
9
|
readonly chatSessionListManager: ChatSessionListManager;
|
|
13
|
-
readonly chatInputManager: ChatInputManager;
|
|
14
10
|
readonly chatQueryManager: ChatQueryManager;
|
|
15
11
|
readonly chatThreadManager: ChatThreadManager;
|
|
16
12
|
|
|
17
13
|
constructor(appPresenter: AppPresenter) {
|
|
18
14
|
this.chatUiManager = new ChatUiManager(appPresenter.docBrowserManager);
|
|
19
|
-
this.
|
|
20
|
-
this.chatSessionListManager = new ChatSessionListManager(this.chatUiManager, this.chatRunManager);
|
|
15
|
+
this.chatSessionListManager = new ChatSessionListManager(this.chatUiManager);
|
|
21
16
|
this.chatQueryManager = new ChatQueryManager();
|
|
22
|
-
this.chatInputManager = new ChatInputManager(
|
|
23
|
-
this.chatRunManager,
|
|
24
|
-
this.chatSessionListManager
|
|
25
|
-
);
|
|
26
17
|
this.chatThreadManager = new ChatThreadManager(
|
|
27
18
|
this.chatUiManager,
|
|
28
|
-
this.chatSessionListManager
|
|
29
|
-
this.chatRunManager
|
|
19
|
+
this.chatSessionListManager
|
|
30
20
|
);
|
|
31
21
|
}
|
|
32
|
-
|
|
33
|
-
startAgentCreationDraft = (prompt: string) => {
|
|
34
|
-
this.chatSessionListManager.createSession();
|
|
35
|
-
this.chatSessionListManager.setSelectedAgentId('main');
|
|
36
|
-
this.chatInputManager.setDraft(prompt);
|
|
37
|
-
this.chatInputManager.requestComposerFocusAtEnd();
|
|
38
|
-
};
|
|
39
22
|
}
|
|
@@ -22,6 +22,7 @@ function resetChatThreadStore() {
|
|
|
22
22
|
activeWorkspacePanelKind: null,
|
|
23
23
|
childSessionTabs: [],
|
|
24
24
|
activeChildSessionKey: null,
|
|
25
|
+
activeSideChatDraft: null,
|
|
25
26
|
workspaceFileTabs: [],
|
|
26
27
|
activeWorkspaceFileKey: null,
|
|
27
28
|
workspaceNavigationHistory: [],
|
|
@@ -85,6 +86,36 @@ describe('chat thread workspace panel persistence', () => {
|
|
|
85
86
|
expect(persisted.state.snapshot.workspaceFileTabs[0].fullLines).toBeUndefined();
|
|
86
87
|
});
|
|
87
88
|
|
|
89
|
+
it('does not persist an unmaterialized side chat draft', () => {
|
|
90
|
+
useChatThreadStore.getState().setSnapshot({
|
|
91
|
+
workspacePanelParentKey: 'session-1',
|
|
92
|
+
activeWorkspacePanelKind: 'side-chat-draft',
|
|
93
|
+
activeSideChatDraft: {
|
|
94
|
+
draftKey: 'draft-1',
|
|
95
|
+
parentSessionKey: 'session-1',
|
|
96
|
+
},
|
|
97
|
+
workspaceNavigationHistory: [
|
|
98
|
+
{ kind: 'child-session', key: 'child-session-1' },
|
|
99
|
+
{ kind: 'side-chat-draft', key: 'draft-1' },
|
|
100
|
+
],
|
|
101
|
+
workspaceNavigationHistoryIndex: 1,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const persisted = JSON.parse(
|
|
105
|
+
window.localStorage.getItem(chatThreadWorkspaceStorageKey) ?? '{}',
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
expect(persisted.state.snapshot).toMatchObject({
|
|
109
|
+
workspacePanelParentKey: 'session-1',
|
|
110
|
+
activeWorkspacePanelKind: null,
|
|
111
|
+
workspaceNavigationHistory: [
|
|
112
|
+
{ kind: 'child-session', key: 'child-session-1' },
|
|
113
|
+
],
|
|
114
|
+
workspaceNavigationHistoryIndex: 0,
|
|
115
|
+
});
|
|
116
|
+
expect(persisted.state.snapshot.activeSideChatDraft).toBeUndefined();
|
|
117
|
+
});
|
|
118
|
+
|
|
88
119
|
it('hydrates the workspace panel state and repairs stale active file keys', async () => {
|
|
89
120
|
window.localStorage.setItem(
|
|
90
121
|
chatThreadWorkspaceStorageKey,
|
|
@@ -14,6 +14,11 @@ export type ChatChildSessionTab = {
|
|
|
14
14
|
agentId?: string | null;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
+
export type ChatWorkspaceSideChatDraft = {
|
|
18
|
+
draftKey: string;
|
|
19
|
+
parentSessionKey: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
17
22
|
export type ChatWorkspaceFileTab = {
|
|
18
23
|
key: string;
|
|
19
24
|
parentSessionKey: string | null;
|
|
@@ -32,17 +37,10 @@ export type ChatWorkspaceFileTab = {
|
|
|
32
37
|
};
|
|
33
38
|
|
|
34
39
|
export type ChatWorkspaceNavigationEntry =
|
|
35
|
-
| {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
| {
|
|
40
|
-
kind: 'file';
|
|
41
|
-
key: string;
|
|
42
|
-
}
|
|
43
|
-
| {
|
|
44
|
-
kind: 'cron';
|
|
45
|
-
};
|
|
40
|
+
| { kind: 'child-session'; key: string }
|
|
41
|
+
| { kind: 'side-chat-draft'; key: string }
|
|
42
|
+
| { kind: 'file'; key: string }
|
|
43
|
+
| { kind: 'cron' };
|
|
46
44
|
|
|
47
45
|
export type ChatThreadSnapshot = {
|
|
48
46
|
sessionTypeLabel?: string | null;
|
|
@@ -63,9 +61,10 @@ export type ChatThreadSnapshot = {
|
|
|
63
61
|
parentSessionKey?: string | null;
|
|
64
62
|
parentSessionLabel?: string | null;
|
|
65
63
|
workspacePanelParentKey?: string | null;
|
|
66
|
-
activeWorkspacePanelKind?: "child-session" | "file" | "cron" | null;
|
|
64
|
+
activeWorkspacePanelKind?: "child-session" | "side-chat-draft" | "file" | "cron" | null;
|
|
67
65
|
childSessionTabs: ChatChildSessionTab[];
|
|
68
66
|
activeChildSessionKey?: string | null;
|
|
67
|
+
activeSideChatDraft?: ChatWorkspaceSideChatDraft | null;
|
|
69
68
|
workspaceFileTabs: ChatWorkspaceFileTab[];
|
|
70
69
|
activeWorkspaceFileKey?: string | null;
|
|
71
70
|
workspaceNavigationHistory: ChatWorkspaceNavigationEntry[];
|
|
@@ -105,6 +104,8 @@ type PersistedChatWorkspaceSnapshot = Pick<
|
|
|
105
104
|
| 'workspaceNavigationHistoryIndex'
|
|
106
105
|
>;
|
|
107
106
|
|
|
107
|
+
type PersistedWorkspacePanelKind = 'child-session' | 'file' | 'cron';
|
|
108
|
+
|
|
108
109
|
const initialSnapshot: ChatThreadSnapshot = {
|
|
109
110
|
sessionTypeLabel: null,
|
|
110
111
|
sessionTypeIcon: null,
|
|
@@ -127,6 +128,7 @@ const initialSnapshot: ChatThreadSnapshot = {
|
|
|
127
128
|
activeWorkspacePanelKind: null,
|
|
128
129
|
childSessionTabs: [],
|
|
129
130
|
activeChildSessionKey: null,
|
|
131
|
+
activeSideChatDraft: null,
|
|
130
132
|
workspaceFileTabs: [],
|
|
131
133
|
activeWorkspaceFileKey: null,
|
|
132
134
|
workspaceNavigationHistory: [],
|
|
@@ -158,7 +160,7 @@ function normalizeHistoryIndex(value: unknown, maxIndex: number): number {
|
|
|
158
160
|
|
|
159
161
|
function isWorkspacePanelKind(
|
|
160
162
|
value: unknown,
|
|
161
|
-
): value is
|
|
163
|
+
): value is PersistedWorkspacePanelKind {
|
|
162
164
|
return value === 'child-session' || value === 'file' || value === 'cron';
|
|
163
165
|
}
|
|
164
166
|
|
|
@@ -344,19 +346,33 @@ export const useChatThreadStore = create<ChatThreadStore>()(
|
|
|
344
346
|
name: CHAT_THREAD_WORKSPACE_STORAGE_KEY,
|
|
345
347
|
version: CHAT_THREAD_WORKSPACE_STORAGE_VERSION,
|
|
346
348
|
storage: createJSONStorage(() => window.localStorage),
|
|
347
|
-
partialize: (state): PersistedChatThreadStore =>
|
|
348
|
-
snapshot
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
349
|
+
partialize: (state): PersistedChatThreadStore => {
|
|
350
|
+
const workspaceNavigationHistory = state.snapshot.workspaceNavigationHistory
|
|
351
|
+
.filter((entry) => entry.kind !== 'side-chat-draft');
|
|
352
|
+
const workspaceNavigationHistoryIndex =
|
|
353
|
+
workspaceNavigationHistory.length > 0
|
|
354
|
+
? Math.min(
|
|
355
|
+
state.snapshot.workspaceNavigationHistoryIndex,
|
|
356
|
+
workspaceNavigationHistory.length - 1,
|
|
357
|
+
)
|
|
358
|
+
: 0;
|
|
359
|
+
return {
|
|
360
|
+
snapshot: {
|
|
361
|
+
workspacePanelParentKey: state.snapshot.workspacePanelParentKey,
|
|
362
|
+
activeWorkspacePanelKind:
|
|
363
|
+
state.snapshot.activeWorkspacePanelKind === 'side-chat-draft'
|
|
364
|
+
? null
|
|
365
|
+
: state.snapshot.activeWorkspacePanelKind,
|
|
366
|
+
activeChildSessionKey: state.snapshot.activeChildSessionKey,
|
|
367
|
+
workspaceFileTabs: state.snapshot.workspaceFileTabs
|
|
368
|
+
.slice(-CHAT_THREAD_MAX_PERSISTED_WORKSPACE_FILE_TABS)
|
|
369
|
+
.map(toPersistedWorkspaceFileTab),
|
|
370
|
+
activeWorkspaceFileKey: state.snapshot.activeWorkspaceFileKey,
|
|
371
|
+
workspaceNavigationHistory,
|
|
372
|
+
workspaceNavigationHistoryIndex,
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
},
|
|
360
376
|
merge: (persistedState, currentState) => {
|
|
361
377
|
const persistedSnapshot = isRecord(persistedState)
|
|
362
378
|
? persistedState.snapshot
|
|
@@ -236,6 +236,30 @@ describe("MarketplacePage", () => {
|
|
|
236
236
|
expect(card?.textContent).not.toContain("Skill");
|
|
237
237
|
});
|
|
238
238
|
|
|
239
|
+
it("hides redundant skill tags while keeping useful tags", () => {
|
|
240
|
+
mocks.itemsQuery = createItemsQuery({
|
|
241
|
+
data: {
|
|
242
|
+
total: 1,
|
|
243
|
+
page: 1,
|
|
244
|
+
pageSize: 20,
|
|
245
|
+
totalPages: 1,
|
|
246
|
+
sort: "relevance",
|
|
247
|
+
items: [
|
|
248
|
+
createMarketplaceItem({
|
|
249
|
+
tags: ["skill", "automation", "Skill", "ops"],
|
|
250
|
+
}),
|
|
251
|
+
],
|
|
252
|
+
} satisfies MarketplaceListView,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
render(<MarketplacePage forcedType="skills" />);
|
|
256
|
+
|
|
257
|
+
expect(screen.queryByText("skill")).toBeNull();
|
|
258
|
+
expect(screen.queryByText("Skill")).toBeNull();
|
|
259
|
+
expect(screen.getAllByText("automation").length).toBeGreaterThan(0);
|
|
260
|
+
expect(screen.getAllByText("ops").length).toBeGreaterThan(0);
|
|
261
|
+
});
|
|
262
|
+
|
|
239
263
|
it("does not dim the loaded list during background refresh", () => {
|
|
240
264
|
mocks.itemsQuery = createItemsQuery({
|
|
241
265
|
data: {
|
|
@@ -46,7 +46,7 @@ export function SkillShelfCard(props: {
|
|
|
46
46
|
layout === "rail" ? "w-[260px] shrink-0" : "w-full min-w-0",
|
|
47
47
|
)}
|
|
48
48
|
>
|
|
49
|
-
<div>
|
|
49
|
+
<div className="flex min-h-0 flex-1 flex-col">
|
|
50
50
|
<div className="mb-2.5 flex min-w-0 items-start gap-2.5">
|
|
51
51
|
<MarketplaceItemIcon name={item.name} fallback={item.install.spec} />
|
|
52
52
|
<div className="min-w-0 flex-1 pt-0.5">
|
|
@@ -97,17 +97,22 @@ function formatShelfMeta(item: MarketplaceItemSummary) {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
function TagLine({ tags }: { tags: string[] }) {
|
|
100
|
-
const visibleTags = tags.slice(0, 2);
|
|
100
|
+
const visibleTags = tags.filter(isVisibleShelfTag).slice(0, 2);
|
|
101
101
|
if (visibleTags.length === 0) {
|
|
102
102
|
return null;
|
|
103
103
|
}
|
|
104
104
|
return (
|
|
105
|
-
<div className="mt-
|
|
105
|
+
<div className="mt-auto truncate pt-2 text-[11px] font-medium text-gray-400">
|
|
106
106
|
{visibleTags.join(" / ")}
|
|
107
107
|
</div>
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
function isVisibleShelfTag(tag: string) {
|
|
112
|
+
const normalized = tag.trim().toLowerCase();
|
|
113
|
+
return normalized.length > 0 && normalized !== "skill";
|
|
114
|
+
}
|
|
115
|
+
|
|
111
116
|
function formatUpdatedAt(value: string) {
|
|
112
117
|
const date = value.slice(0, 10);
|
|
113
118
|
return date || value;
|
|
@@ -127,8 +127,8 @@ export function MarketplaceItemListView({
|
|
|
127
127
|
<div
|
|
128
128
|
data-testid={showSkeleton ? "marketplace-list-skeleton" : undefined}
|
|
129
129
|
className={cn(
|
|
130
|
-
"grid grid-cols-1 gap-
|
|
131
|
-
showSkeleton && "min-h-0 flex-1 auto-rows-[
|
|
130
|
+
"grid grid-cols-1 gap-2.5 md:grid-cols-2 xl:grid-cols-3",
|
|
131
|
+
showSkeleton && "min-h-0 flex-1 auto-rows-[156px] content-start",
|
|
132
132
|
)}
|
|
133
133
|
>
|
|
134
134
|
{showSkeleton && <MarketplaceListSkeleton count={36} />}
|