@nextclaw/ui 0.15.23 → 0.15.25

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 (119) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/assets/{api-Glw2OGXK.js → api-FK7tikI1.js} +4 -4
  3. package/dist/assets/appearance-settings-page-BYbvl2wj.js +1 -0
  4. package/dist/assets/{channels-list-page-C7E4Sxwd.js → channels-list-page-CocdcIko.js} +2 -2
  5. package/dist/assets/{chat-page-BT6dNI-4.js → chat-page-C5E-LLVd.js} +1 -1
  6. package/dist/assets/config-split-page-CA_a0AJ5.js +1 -0
  7. package/dist/assets/confirm-dialog-CxZfenjK.js +5 -0
  8. package/dist/assets/desktop-update-config-BEKC8Ly9.js +1 -0
  9. package/dist/assets/{dist-dv_SUR54.js → dist-BH7W5yCi.js} +1 -1
  10. package/dist/assets/{dist-CtLyEJeO.js → dist-CaYdVVeO.js} +1 -1
  11. package/dist/assets/doc-browser-Cl2ldE3f.js +1 -0
  12. package/dist/assets/doc-browser-DXCSd63E.js +1 -0
  13. package/dist/assets/{doc-browser-context-BIBjkwfV.js → doc-browser-context-FDPs3gJf.js} +1 -1
  14. package/dist/assets/form-actions-0c0aw_bl.js +1 -0
  15. package/dist/assets/i18n-provider-DkITJNz8.js +1 -0
  16. package/dist/assets/index-CQ2LcI2p.css +1 -0
  17. package/dist/assets/index-CrdfvBVg.js +107 -0
  18. package/dist/assets/loader-circle-DHtUxCIA.js +1 -0
  19. package/dist/assets/mcp-marketplace-page-Bc_jI5iH.js +9 -0
  20. package/dist/assets/mcp-marketplace-page-CzCieD9r.js +1 -0
  21. package/dist/assets/model-config-page-C4jw-pcj.js +1 -0
  22. package/dist/assets/{navigation-link-CB0OQbnY.js → navigation-link-CVy0_kVl.js} +2 -2
  23. package/dist/assets/plus-CG1RwZQq.js +1 -0
  24. package/dist/assets/provider-scoped-model-input-CmH4BFvc.js +1 -0
  25. package/dist/assets/providers-config-page-CJQjwzaw.js +1 -0
  26. package/dist/assets/react-DjFBVA0n.js +8 -0
  27. package/dist/assets/{refresh-cw-Ba0LZou4.js → refresh-cw-j2bl79Ea.js} +1 -1
  28. package/dist/assets/remote-BIlpD3yL.js +1 -0
  29. package/dist/assets/rotate-cw-bKG8zH8M.js +1 -0
  30. package/dist/assets/runtime-config-page-B_x2Glz5.js +1 -0
  31. package/dist/assets/{save-DTOAvqzt.js → save-BKNrtK81.js} +1 -1
  32. package/dist/assets/{search-D4X5DNMe.js → search-CkOm65W_.js} +1 -1
  33. package/dist/assets/{search-config-page-Cr6254K5.js → search-config-page-BaIijtmO.js} +1 -1
  34. package/dist/assets/{secrets-config-page-W2Hx332d.js → secrets-config-page-CJjtdFAl.js} +2 -2
  35. package/dist/assets/security-config-DB8apj09.js +1 -0
  36. package/dist/assets/{select-CDv0g2Pj.js → select-Ea7ffKCE.js} +2 -2
  37. package/dist/assets/{settings-2-CoxzNABp.js → settings-2-CtyN3m_V.js} +1 -1
  38. package/dist/assets/skeleton-Bt6zxcAB.js +1 -0
  39. package/dist/assets/{tag-chip-CjkZEoS2.js → tag-chip-C9l4xsKp.js} +1 -1
  40. package/dist/assets/x-CowtCu9Z.js +1 -0
  41. package/dist/index.html +20 -20
  42. package/package.json +8 -8
  43. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +30 -1
  44. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +1 -1
  45. package/src/features/chat/features/conversation/hooks/__tests__/use-session-provider-model-catalog.test.tsx +54 -2
  46. package/src/features/chat/features/conversation/hooks/use-chat-composer-reference-intent.ts +10 -1
  47. package/src/features/chat/features/conversation/hooks/use-session-provider-model-catalog.ts +76 -1
  48. package/src/features/chat/features/conversation/utils/session-conversation-input-toolbar.utils.ts +6 -1
  49. package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +29 -0
  50. package/src/features/chat/features/input/utils/__tests__/chat-input-bar.utils.test.ts +12 -3
  51. package/src/features/chat/features/input/utils/chat-composer-token-protocol.utils.ts +5 -0
  52. package/src/features/chat/features/input/utils/chat-conversation-excerpt-token.utils.ts +59 -0
  53. package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +42 -16
  54. package/src/features/chat/features/input/utils/chat-input-toolbar.utils.ts +50 -14
  55. package/src/features/chat/features/message/components/chat-message-list.container.tsx +40 -0
  56. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +5 -0
  57. package/src/features/chat/features/ncp/hooks/__tests__/use-hydrated-ncp-agent.test.tsx +40 -3
  58. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.selection.test.tsx +66 -0
  59. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +13 -1
  60. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +573 -90
  61. package/src/features/chat/features/workspace/components/__tests__/workspace-text-selection-menu.test.tsx +11 -4
  62. package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +389 -288
  63. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +54 -35
  64. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +79 -148
  65. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +149 -94
  66. package/src/features/chat/features/workspace/components/project-files/__tests__/workspace-directory-entry-menu.test.tsx +50 -0
  67. package/src/features/chat/features/workspace/components/project-files/workspace-directory-entry-menu.tsx +209 -0
  68. package/src/features/chat/features/workspace/components/project-files/workspace-directory-tree.tsx +411 -0
  69. package/src/features/chat/features/workspace/components/project-files/workspace-new-folder-tree-item.tsx +112 -0
  70. package/src/features/chat/features/workspace/components/project-files/workspace-project-files-toolbar.tsx +64 -0
  71. package/src/features/chat/features/workspace/components/workspace-text-selection-menu.tsx +17 -195
  72. package/src/features/chat/features/workspace/hooks/use-workspace-explorer-layout.ts +88 -0
  73. package/src/features/chat/features/workspace/hooks/use-workspace-file-actions.ts +335 -0
  74. package/src/features/chat/features/workspace/utils/chat-workspace-file-path-mutation.utils.ts +58 -0
  75. package/src/features/chat/features/workspace/utils/chat-workspace-file-tab.utils.ts +23 -22
  76. package/src/features/chat/features/workspace/utils/chat-workspace-panel-layout.utils.ts +13 -4
  77. package/src/features/chat/managers/__tests__/chat-composer-intent.manager.test.ts +94 -45
  78. package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +103 -99
  79. package/src/features/chat/managers/chat-composer-intent.manager.ts +83 -34
  80. package/src/features/chat/managers/chat-thread.manager.ts +132 -128
  81. package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +20 -40
  82. package/src/features/chat/stores/chat-thread.store.ts +47 -74
  83. package/src/features/chat/types/chat-input-bar.types.ts +3 -0
  84. package/src/features/side-dock/components/__tests__/side-dock.test.tsx +1 -0
  85. package/src/features/side-dock/configs/side-dock-built-in-items.config.ts +0 -9
  86. package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +35 -38
  87. package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +25 -19
  88. package/src/shared/components/ui/context-menu/__tests__/context-menu.test.tsx +60 -34
  89. package/src/shared/components/ui/context-menu/context-menu.tsx +95 -68
  90. package/src/shared/lib/api/managers/client.manager.ts +31 -17
  91. package/src/shared/lib/api/server-path/server-path.types.ts +66 -0
  92. package/src/shared/lib/api/types.ts +145 -116
  93. package/src/shared/lib/api/utils/server-path.utils.ts +35 -11
  94. package/src/shared/lib/i18n/locales/en-US/chat.json +49 -1
  95. package/src/shared/lib/i18n/locales/zh-CN/chat.json +49 -1
  96. package/dist/assets/appearance-settings-page-Bl_W_9m7.js +0 -1
  97. package/dist/assets/config-split-page-D5BgtKrm.js +0 -1
  98. package/dist/assets/confirm-dialog-Bf907Azu.js +0 -5
  99. package/dist/assets/desktop-update-config-BwuyBPJb.js +0 -1
  100. package/dist/assets/doc-browser-C23NDGh5.js +0 -1
  101. package/dist/assets/doc-browser-DlOOhBxI.js +0 -1
  102. package/dist/assets/form-actions-DAzi68Cn.js +0 -1
  103. package/dist/assets/index-BLNg2yg0.css +0 -1
  104. package/dist/assets/index-D3EKjEyK.js +0 -107
  105. package/dist/assets/loader-circle-BSg5u0r4.js +0 -1
  106. package/dist/assets/mcp-marketplace-page-ByhvQQj5.js +0 -9
  107. package/dist/assets/mcp-marketplace-page-CytXwnUs.js +0 -1
  108. package/dist/assets/model-config-page-bgEx3MjQ.js +0 -1
  109. package/dist/assets/plus-CNjWdLhZ.js +0 -1
  110. package/dist/assets/provider-scoped-model-input-8F6JMd2n.js +0 -1
  111. package/dist/assets/providers-config-page-CxpTjR81.js +0 -1
  112. package/dist/assets/react-Bk2ydNTe.js +0 -8
  113. package/dist/assets/remote-Dv38PuMV.js +0 -1
  114. package/dist/assets/rotate-cw-IkYVk9JX.js +0 -1
  115. package/dist/assets/runtime-config-page-C0ByyUVr.js +0 -1
  116. package/dist/assets/security-config-1E8OF4kR.js +0 -1
  117. package/dist/assets/skeleton-DW018fJv.js +0 -1
  118. package/dist/assets/use-confirm-dialog-CavtY1vJ.js +0 -1
  119. package/dist/assets/x-PTXYTEwz.js +0 -1
@@ -145,6 +145,8 @@ export function buildChatMessageTexts(
145
145
  ): ChatMessageTexts {
146
146
  void language;
147
147
  return {
148
+ addSelectionToChatLabel: t("chatWorkspaceAddToChat"),
149
+ selectionTooLongLabel: t("chatWorkspaceExcerptSelectionTooLong"),
148
150
  copyCodeLabel: t("chatCodeCopy"),
149
151
  copiedCodeLabel: t("chatCodeCopied"),
150
152
  copyMessageLabel: t("chatMessageCopy"),
@@ -154,6 +156,9 @@ export function buildChatMessageTexts(
154
156
  mermaidExpandLabel: t("chatMermaidExpand"),
155
157
  mermaidLoadingLabel: t("chatMermaidLoading"),
156
158
  mermaidRenderErrorLabel: t("chatMermaidRenderError"),
159
+ previewZoomInLabel: t("chatPreviewZoomIn"),
160
+ previewZoomOutLabel: t("chatPreviewZoomOut"),
161
+ previewResetZoomLabel: t("chatPreviewResetZoom"),
157
162
  typingLabel: t("chatTyping"),
158
163
  reasoningCharacterCountTemplates: {
159
164
  inProgress: t("chatReasoningInProgressCharacterCount"),
@@ -248,10 +248,9 @@ describe("useHydratedNcpAgent", () => {
248
248
  );
249
249
 
250
250
  await vi.waitFor(() => {
251
- expect(result.current.hydrateError?.message).toBe(
252
- "stream disconnected",
253
- );
251
+ expect(mocks.stream).toHaveBeenCalledTimes(1);
254
252
  });
253
+ expect(result.current.hydrateError).toBeNull();
255
254
  await act(async () => {
256
255
  await vi.runOnlyPendingTimersAsync();
257
256
  });
@@ -268,4 +267,42 @@ describe("useHydratedNcpAgent", () => {
268
267
  vi.useRealTimers();
269
268
  }
270
269
  });
270
+
271
+ it("reports a stream error only after repeated immediate recovery failures", async () => {
272
+ vi.useFakeTimers();
273
+ try {
274
+ const client = {
275
+ stop: mocks.stop.mockResolvedValue(undefined),
276
+ stream: mocks.stream.mockRejectedValue(new Error("stream unavailable")),
277
+ subscribe: vi.fn(() => () => {}),
278
+ send: mocks.send,
279
+ } as unknown as NcpAgentClientEndpoint;
280
+ const loadSeed = vi.fn().mockResolvedValue({ messages: [], status: "idle" });
281
+ const { result } = renderHook(() =>
282
+ useHydratedNcpAgent({
283
+ sessionId: "session-offline",
284
+ client: client as never,
285
+ loadSeed,
286
+ }),
287
+ );
288
+
289
+ await vi.waitFor(() => expect(mocks.stream).toHaveBeenCalledTimes(1));
290
+ expect(result.current.hydrateError).toBeNull();
291
+
292
+ await act(async () => {
293
+ await vi.runOnlyPendingTimersAsync();
294
+ });
295
+ await vi.waitFor(() => expect(mocks.stream).toHaveBeenCalledTimes(2));
296
+ expect(result.current.hydrateError).toBeNull();
297
+
298
+ await act(async () => {
299
+ await vi.runOnlyPendingTimersAsync();
300
+ });
301
+ await vi.waitFor(() => {
302
+ expect(result.current.hydrateError?.message).toBe("stream unavailable");
303
+ });
304
+ } finally {
305
+ vi.useRealTimers();
306
+ }
307
+ });
271
308
  });
@@ -0,0 +1,66 @@
1
+ import type { ReactNode } from "react";
2
+ import { fireEvent, render, screen } from "@testing-library/react";
3
+ import { describe, expect, it, vi } from "vitest";
4
+ import { ChatSessionWorkspaceFilePreview } from "@/features/chat/features/workspace/components/chat-session-workspace-file-preview";
5
+
6
+ const onTextExcerptAdd = vi.fn();
7
+
8
+ vi.mock("@/shared/hooks/use-server-path-read", () => ({
9
+ useServerPathRead: () => ({
10
+ isLoading: false,
11
+ error: null,
12
+ data: {
13
+ kind: "markdown",
14
+ resolvedPath: "/Users/demo/.nextclaw/workspace/BOOT.md",
15
+ startLine: 1,
16
+ text: "Add short, explicit startup instructions.",
17
+ truncated: false,
18
+ },
19
+ }),
20
+ }));
21
+
22
+ vi.mock("@/shared/hooks/use-server-path-browse", () => ({
23
+ useServerPathBrowse: () => ({ isLoading: false, error: new Error("not a directory"), data: null }),
24
+ }));
25
+
26
+ vi.mock("@nextclaw/agent-chat-ui", () => ({
27
+ ChatMessageMarkdown: ({ text }: { text: string }) => <div>{text}</div>,
28
+ FileOperationCodeSurface: () => null,
29
+ ChatTextSelectionAction: ({ children, onAddToChat }: { children: ReactNode; onAddToChat: (value: { text: string }) => void }) => (
30
+ <div>
31
+ {children}
32
+ <button type="button" onClick={() => onAddToChat({ text: "Add short, explicit startup instructions." })}>
33
+ select excerpt
34
+ </button>
35
+ </div>
36
+ ),
37
+ }));
38
+
39
+ describe("ChatSessionWorkspaceFilePreview selection", () => {
40
+ it("uses the resolved absolute path when a shell-style workspace root cannot be compared in the browser", () => {
41
+ render(
42
+ <ChatSessionWorkspaceFilePreview
43
+ file={{
44
+ key: "boot",
45
+ parentSessionKey: null,
46
+ path: "/Users/demo/.nextclaw/workspace/BOOT.md",
47
+ label: "BOOT.md",
48
+ viewMode: "preview",
49
+ }}
50
+ sessionProjectRoot="~/.nextclaw/workspace"
51
+ sessionWorkingDir="~/.nextclaw/workspace"
52
+ onFileOpen={vi.fn()}
53
+ onTextExcerptAdd={onTextExcerptAdd}
54
+ />,
55
+ );
56
+
57
+ fireEvent.click(screen.getByRole("button", { name: "select excerpt" }));
58
+ expect(onTextExcerptAdd).toHaveBeenCalledWith({
59
+ path: "/Users/demo/.nextclaw/workspace/BOOT.md",
60
+ label: "BOOT.md",
61
+ excerpt: "Add short, explicit startup instructions.",
62
+ startLine: 1,
63
+ endLine: 1,
64
+ });
65
+ });
66
+ });
@@ -1,4 +1,5 @@
1
1
  import { fireEvent, render, screen, waitFor } from "@testing-library/react";
2
+ import type { ReactNode } from "react";
2
3
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
4
  import type {
4
5
  ChatFileOpenActionViewModel,
@@ -38,6 +39,7 @@ vi.mock("@/shared/hooks/use-server-path-browse", () => ({
38
39
  }));
39
40
 
40
41
  vi.mock("@nextclaw/agent-chat-ui", () => ({
42
+ ChatTextSelectionAction: ({ children }: { children: ReactNode }) => children,
41
43
  ChatMessageMarkdown: ({ text }: { text: string }) => (
42
44
  <div data-testid="markdown-preview">{text}</div>
43
45
  ),
@@ -56,6 +58,16 @@ vi.mock("@nextclaw/agent-chat-ui", () => ({
56
58
  ),
57
59
  }));
58
60
 
61
+ vi.mock("@/features/chat/components/providers/chat-presenter.provider", () => ({
62
+ usePresenter: () => ({
63
+ chatThreadManager: { removeWorkspacePath: vi.fn(), renameWorkspacePath: vi.fn() },
64
+ chatComposerIntentManager: {
65
+ requestDirectoryReference: vi.fn(),
66
+ requestFileReference: vi.fn(),
67
+ },
68
+ }),
69
+ }));
70
+
59
71
  vi.mock("docx-preview", () => ({
60
72
  renderAsync: (...args: unknown[]) => renderDocxMock(...args),
61
73
  }));
@@ -787,7 +799,7 @@ describe("ChatSessionWorkspaceFilePreview breadcrumbs", () => {
787
799
  screen.getByTestId("workspace-file-breadcrumb-scroll").className,
788
800
  ).toContain("py-1.5");
789
801
  expect(
790
- screen.getByTestId("workspace-file-breadcrumbs").className,
802
+ screen.getByTestId("workspace-file-breadcrumb-scroll").className,
791
803
  ).toContain("workspace-horizontal-scrollbar");
792
804
  });
793
805