@nextclaw/ui 0.14.1-beta.0 → 0.14.1-beta.1

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 (126) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/assets/{api-C6EDHBDR.js → api-dQ6uQSZG.js} +3 -3
  3. package/dist/assets/{channels-list-page-DKj6m1Hc.js → channels-list-page-DfpjB8XB.js} +2 -2
  4. package/dist/assets/chat-page-D3QaEqjs.js +105 -0
  5. package/dist/assets/{config-split-page-CjlmJy8X.js → config-split-page-CeFfbaqc.js} +1 -1
  6. package/dist/assets/{confirm-dialog-B39X0pYp.js → confirm-dialog-C95Y4QPC.js} +1 -1
  7. package/dist/assets/{desktop-update-config-DfUQ8nly.js → desktop-update-config-CcK6jiEb.js} +1 -1
  8. package/dist/assets/{dist-CmMro3nV.js → dist-DTGzeil6.js} +1 -1
  9. package/dist/assets/{dist-BIYV2-Ia.js → dist-fGogBmPA.js} +1 -1
  10. package/dist/assets/doc-browser-CuBTcBEZ.js +1 -0
  11. package/dist/assets/{doc-browser-CDtUtcim.js → doc-browser-DVHhEb96.js} +1 -1
  12. package/dist/assets/{doc-browser-context-DZbC9zVB.js → doc-browser-context-BfMXwnrz.js} +1 -1
  13. package/dist/assets/{ellipsis-DDpgTzgx.js → ellipsis-D2F4KMiU.js} +1 -1
  14. package/dist/assets/{external-link-D2cBOCqn.js → external-link-CcgtBK26.js} +1 -1
  15. package/dist/assets/index-ByJCbQqr.css +1 -0
  16. package/dist/assets/index-DjXqiloY.js +103 -0
  17. package/dist/assets/mcp-marketplace-page-98-V__3u.js +1 -0
  18. package/dist/assets/mcp-marketplace-page-BNq_PNmO.js +40 -0
  19. package/dist/assets/model-config-page-aAUkZkSX.js +1 -0
  20. package/dist/assets/plus-1Rxl5FlV.js +1 -0
  21. package/dist/assets/provider-scoped-model-input-we4_Z4gP.js +1 -0
  22. package/dist/assets/providers-config-page-CtMkPSyu.js +1 -0
  23. package/dist/assets/{react-DYQXXGbH.js → react-CTqdhFMk.js} +1 -1
  24. package/dist/assets/remote-fQ7N_r8u.js +1 -0
  25. package/dist/assets/rotate-cw-CzfIeAJj.js +1 -0
  26. package/dist/assets/runtime-config-page-TD1UrTbG.js +1 -0
  27. package/dist/assets/{save-BNVTgBVn.js → save-C9fKWfVB.js} +1 -1
  28. package/dist/assets/{search-CKCzwLId.js → search-D5FQ5q0X.js} +1 -1
  29. package/dist/assets/{search-config-page-DG5Q2hF1.js → search-config-page-AMEJJNIS.js} +1 -1
  30. package/dist/assets/secrets-config-page-CcgJnvBO.js +3 -0
  31. package/dist/assets/{select-CIRwTNP4.js → select-Cu5n0E-3.js} +2 -2
  32. package/dist/assets/{tag-chip-DKhVFtTE.js → tag-chip-C5aOtjxu.js} +1 -1
  33. package/dist/assets/use-config-D8TESeo6.js +1 -0
  34. package/dist/assets/x-1qETdQ70.js +1 -0
  35. package/dist/index.html +14 -14
  36. package/package.json +9 -9
  37. package/src/features/chat/components/conversation/__tests__/chat-conversation-panel.test.tsx +12 -63
  38. package/src/features/chat/components/conversation/chat-conversation-content.tsx +11 -50
  39. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +15 -2
  40. package/src/features/chat/features/input/components/chat-input-bar.container.tsx +84 -6
  41. package/src/features/chat/features/input/hooks/use-chat-input-bar-query-state.ts +2 -0
  42. package/src/features/chat/features/input/hooks/use-chat-model-favorites.ts +87 -0
  43. package/src/features/chat/features/input/utils/__tests__/chat-input-bar.utils.test.ts +64 -24
  44. package/src/features/chat/features/input/utils/__tests__/ncp-chat-input-availability.utils.test.ts +1 -0
  45. package/src/features/chat/features/input/utils/chat-input-bar.utils.ts +21 -12
  46. package/src/features/chat/features/input/utils/chat-input-toolbar.utils.ts +80 -25
  47. package/src/features/chat/features/message/utils/__tests__/chat-message-file-operation.utils.test.ts +310 -0
  48. package/src/features/chat/features/message/utils/__tests__/chat-message-test.utils.ts +43 -0
  49. package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +1 -346
  50. package/src/features/chat/features/message/utils/chat-message-tool-card.utils.ts +10 -9
  51. package/src/features/chat/features/message/utils/file-operation/diff.utils.ts +39 -36
  52. package/src/features/chat/features/message/utils/file-operation/line-builder.utils.ts +46 -38
  53. package/src/features/chat/features/message/utils/file-operation/parsed-block.utils.ts +18 -15
  54. package/src/features/chat/features/session/components/session-header/__tests__/chat-session-project-badge.test.tsx +25 -25
  55. package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +15 -2
  56. package/src/features/chat/features/session-type/components/__tests__/chat-sidebar-create-menu.test.tsx +24 -0
  57. package/src/features/chat/features/session-type/components/chat-sidebar-create-menu.tsx +10 -1
  58. package/src/features/chat/features/welcome/components/__tests__/chat-conversation-welcome.test.tsx +193 -0
  59. package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +123 -0
  60. package/src/features/chat/features/welcome/components/chat-conversation-welcome.tsx +104 -0
  61. package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +72 -0
  62. package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +54 -0
  63. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +132 -0
  64. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +82 -0
  65. package/src/features/chat/features/welcome/components/chat-welcome.tsx +121 -0
  66. package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-project-options.utils.test.ts +53 -0
  67. package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-selection.utils.test.ts +63 -0
  68. package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-visibility.utils.test.ts +34 -0
  69. package/src/features/chat/features/welcome/utils/chat-welcome-project-options.utils.ts +71 -0
  70. package/src/features/chat/features/welcome/utils/chat-welcome-selection.utils.ts +79 -0
  71. package/src/features/chat/features/welcome/utils/chat-welcome-visibility.utils.ts +17 -0
  72. package/src/features/chat/managers/__tests__/chat-input.manager.test.ts +65 -0
  73. package/src/features/chat/managers/chat-input.manager.ts +24 -2
  74. package/src/features/chat/stores/chat-input.store.ts +2 -0
  75. package/src/features/chat/types/chat-input-bar.types.ts +5 -0
  76. package/src/features/marketplace/utils/marketplace-installed-cache.utils.ts +27 -23
  77. package/src/features/settings/components/config/provider-form.tsx +284 -387
  78. package/src/features/settings/components/config/provider-status-badge.tsx +4 -4
  79. package/src/features/settings/components/config/secrets-config-form.tsx +11 -135
  80. package/src/features/settings/hooks/use-provider-auth-flow.ts +140 -0
  81. package/src/features/settings/pages/__tests__/model-config-page.test.tsx +16 -0
  82. package/src/features/settings/pages/secrets-config-page.tsx +2 -1
  83. package/src/features/settings/utils/__tests__/provider-form-support.utils.test.ts +60 -1
  84. package/src/features/settings/utils/__tests__/secrets-config-form.utils.test.ts +66 -0
  85. package/src/features/settings/utils/provider-form-context.utils.ts +131 -0
  86. package/src/features/settings/utils/provider-form-model.utils.ts +101 -0
  87. package/src/features/settings/utils/provider-form-support.utils.ts +102 -1
  88. package/src/features/settings/utils/secrets-config-form.utils.ts +139 -0
  89. package/src/features/system-status/components/config/runtime-agent-list-card.tsx +17 -11
  90. package/src/features/system-status/components/config/runtime-binding-list-card.tsx +14 -9
  91. package/src/features/system-status/components/config/runtime-config-editor.tsx +8 -5
  92. package/src/features/system-status/components/config/runtime-entry-list-card.tsx +14 -9
  93. package/src/features/system-status/components/config/runtime-settings-card.tsx +16 -7
  94. package/src/features/system-status/components/runtime-security-card.tsx +79 -25
  95. package/src/shared/components/common/__tests__/searchable-model-input.test.tsx +34 -0
  96. package/src/shared/components/common/provider-scoped-model-input.tsx +1 -0
  97. package/src/shared/components/common/searchable-model-input.tsx +102 -87
  98. package/src/shared/components/ui/README.md +7 -0
  99. package/src/shared/components/ui/popover.tsx +19 -3
  100. package/src/shared/components/ui/select.tsx +14 -4
  101. package/src/shared/hooks/use-infinite-scroll-loader.ts +14 -10
  102. package/src/shared/lib/api/index.ts +2 -0
  103. package/src/shared/lib/api/preferences/preference.types.ts +22 -0
  104. package/src/shared/lib/api/preferences/preference.utils.ts +40 -0
  105. package/src/shared/lib/i18n/locales/en-US/chat.json +16 -1
  106. package/src/shared/lib/i18n/locales/en-US/core.json +1 -0
  107. package/src/shared/lib/i18n/locales/zh-CN/chat.json +16 -1
  108. package/src/shared/lib/i18n/locales/zh-CN/core.json +1 -0
  109. package/dist/assets/chat-page-BXngLJY6.js +0 -105
  110. package/dist/assets/doc-browser-B6Wc_TIY.js +0 -1
  111. package/dist/assets/index-DTb_XVIH.js +0 -103
  112. package/dist/assets/index-ayiPYhf1.css +0 -1
  113. package/dist/assets/mcp-marketplace-page-DZ9H0v05.js +0 -1
  114. package/dist/assets/mcp-marketplace-page-cnVWf7QQ.js +0 -40
  115. package/dist/assets/model-config-page-Bcb35AVv.js +0 -1
  116. package/dist/assets/plus-CYE1onU2.js +0 -1
  117. package/dist/assets/provider-scoped-model-input-kdoNp4HG.js +0 -1
  118. package/dist/assets/providers-config-page-CQSibSwO.js +0 -1
  119. package/dist/assets/remote-BlJDbXOI.js +0 -1
  120. package/dist/assets/rotate-cw-BWbvFDAX.js +0 -1
  121. package/dist/assets/runtime-config-page-Tn2yLQ0c.js +0 -1
  122. package/dist/assets/secrets-config-page-BXn5Uuwp.js +0 -3
  123. package/dist/assets/use-config-DgKM9VIU.js +0 -1
  124. package/dist/assets/x-Cm3JjYut.js +0 -1
  125. package/src/features/chat/components/__tests__/chat-welcome.test.tsx +0 -45
  126. package/src/features/chat/components/chat-welcome.tsx +0 -102
@@ -1,42 +1,5 @@
1
1
  import { ToolInvocationStatus, type UiMessage } from "@nextclaw/agent-chat";
2
- import { adaptChatMessages } from "../chat-message.utils";
3
- import type { ChatMessageSource } from "../chat-message.utils";
4
-
5
- function toSource(uiMessages: UiMessage[]): ChatMessageSource[] {
6
- return uiMessages as unknown as ChatMessageSource[];
7
- }
8
-
9
- const defaultTexts = {
10
- roleLabels: {
11
- user: "You",
12
- assistant: "Assistant",
13
- tool: "Tool",
14
- system: "System",
15
- fallback: "Message",
16
- },
17
- reasoningLabel: "Reasoning",
18
- toolCallLabel: "Tool Call",
19
- toolResultLabel: "Tool Result",
20
- toolInputLabel: "Input",
21
- toolNoOutputLabel: "No output",
22
- toolOutputLabel: "Output",
23
- toolStatusPreparingLabel: "Preparing",
24
- toolStatusRunningLabel: "Running",
25
- toolStatusCompletedLabel: "Completed",
26
- toolStatusFailedLabel: "Failed",
27
- toolStatusCancelledLabel: "Cancelled",
28
- imageAttachmentLabel: "Image attachment",
29
- fileAttachmentLabel: "File attachment",
30
- unknownPartLabel: "Unknown Part",
31
- };
32
-
33
- function adapt(uiMessages: ChatMessageSource[]) {
34
- return adaptChatMessages({
35
- uiMessages,
36
- formatTimestamp: (value) => `formatted:${value}`,
37
- texts: defaultTexts,
38
- });
39
- }
2
+ import { adapt, toSource, type ChatMessageSource } from "./chat-message-test.utils";
40
3
 
41
4
  it("maps markdown, reasoning, and tool parts into UI view models", () => {
42
5
  const messages: UiMessage[] = [
@@ -576,311 +539,3 @@ it("renders asset tool results as previewable files", () => {
576
539
  },
577
540
  });
578
541
  });
579
-
580
- it("builds edit-file previews from structured args before the tool finishes", () => {
581
- const adapted = adapt([
582
- {
583
- id: "assistant-edit-preview",
584
- role: "assistant",
585
- parts: [
586
- {
587
- type: "tool-invocation",
588
- toolInvocation: {
589
- status: ToolInvocationStatus.CALL,
590
- toolCallId: "edit-call-1",
591
- toolName: "edit_file",
592
- args: JSON.stringify({
593
- path: "src/app.ts",
594
- oldText: "const color = 'red';",
595
- newText: "const color = 'blue';",
596
- }),
597
- parsedArgs: {
598
- path: "src/app.ts",
599
- oldText: "const color = 'red';",
600
- newText: "const color = 'blue';",
601
- },
602
- },
603
- },
604
- ],
605
- },
606
- ] as unknown as ChatMessageSource[]);
607
-
608
- const editLines =
609
- adapted[0]?.parts[0]?.type === "tool-card"
610
- ? (adapted[0].parts[0].card.fileOperation?.blocks[0]?.lines ?? [])
611
- : [];
612
-
613
- expect(adapted[0]?.parts[0]).toMatchObject({
614
- type: "tool-card",
615
- card: {
616
- toolName: "edit_file",
617
- summary: "src/app.ts",
618
- statusTone: "running",
619
- fileOperation: {
620
- blocks: [
621
- {
622
- path: "src/app.ts",
623
- lines: [
624
- {
625
- kind: "remove",
626
- text: "const color = 'red';",
627
- },
628
- {
629
- kind: "add",
630
- text: "const color = 'blue';",
631
- },
632
- ],
633
- },
634
- ],
635
- },
636
- },
637
- });
638
- expect(editLines[0]).not.toHaveProperty("oldLineNumber");
639
- expect(editLines[1]).not.toHaveProperty("newLineNumber");
640
- });
641
-
642
- it("uses structured edit-file result line numbers after the tool finishes", () => {
643
- const adapted = adapt([
644
- {
645
- id: "assistant-edit-result",
646
- role: "assistant",
647
- parts: [
648
- {
649
- type: "tool-invocation",
650
- toolInvocation: {
651
- status: ToolInvocationStatus.RESULT,
652
- toolCallId: "edit-result-1",
653
- toolName: "edit_file",
654
- args: JSON.stringify({
655
- path: "src/app.ts",
656
- oldText: "const color = 'red';",
657
- newText: "const color = 'blue';",
658
- }),
659
- parsedArgs: {
660
- path: "src/app.ts",
661
- oldText: "const color = 'red';",
662
- newText: "const color = 'blue';",
663
- },
664
- result: {
665
- path: "src/app.ts",
666
- oldStartLine: 27,
667
- newStartLine: 27,
668
- message: "Edited src/app.ts",
669
- },
670
- },
671
- },
672
- ],
673
- },
674
- ] as unknown as ChatMessageSource[]);
675
-
676
- expect(adapted[0]?.parts[0]).toMatchObject({
677
- type: "tool-card",
678
- card: {
679
- toolName: "edit_file",
680
- summary: "src/app.ts",
681
- statusTone: "success",
682
- fileOperation: {
683
- blocks: [
684
- {
685
- path: "src/app.ts",
686
- lines: [
687
- {
688
- kind: "remove",
689
- text: "const color = 'red';",
690
- oldLineNumber: 27,
691
- },
692
- {
693
- kind: "add",
694
- text: "const color = 'blue';",
695
- newLineNumber: 27,
696
- },
697
- ],
698
- },
699
- ],
700
- },
701
- },
702
- });
703
- });
704
-
705
- it("builds write-file previews from partial native args before the JSON is complete", () => {
706
- const adapted = adapt([
707
- {
708
- id: "assistant-write-preview",
709
- role: "assistant",
710
- parts: [
711
- {
712
- type: "tool-invocation",
713
- toolInvocation: {
714
- status: ToolInvocationStatus.PARTIAL_CALL,
715
- toolCallId: "write-call-1",
716
- toolName: "write_file",
717
- args: '{"path":"games/snake.html","content":"<!DOCTYPE html>\\n<canvas id=\\"game\\"></canvas>\\n<script>const score = 1;',
718
- },
719
- },
720
- ],
721
- },
722
- ] as unknown as ChatMessageSource[]);
723
-
724
- expect(adapted[0]?.parts[0]).toMatchObject({
725
- type: "tool-card",
726
- card: {
727
- toolName: "write_file",
728
- summary: "games/snake.html",
729
- statusTone: "running",
730
- statusLabel: "Running",
731
- fileOperation: {
732
- blocks: [
733
- {
734
- display: "preview",
735
- path: "games/snake.html",
736
- lines: expect.arrayContaining([
737
- expect.objectContaining({
738
- kind: "add",
739
- text: "<!DOCTYPE html>",
740
- }),
741
- expect.objectContaining({
742
- kind: "add",
743
- text: '<canvas id="game"></canvas>',
744
- }),
745
- ]),
746
- },
747
- ],
748
- },
749
- },
750
- });
751
- });
752
-
753
- it("keeps completed write-file cards in preview mode instead of falling back to raw byte summaries", () => {
754
- const adapted = adapt([
755
- {
756
- id: "assistant-write-result",
757
- role: "assistant",
758
- parts: [
759
- {
760
- type: "tool-invocation",
761
- toolInvocation: {
762
- status: ToolInvocationStatus.RESULT,
763
- toolCallId: "write-result-1",
764
- toolName: "write_file",
765
- args: JSON.stringify({
766
- path: "games/snake.html",
767
- content: '<!DOCTYPE html>\n<canvas id="game"></canvas>',
768
- }),
769
- result: "Wrote 3906 bytes to games/snake.html",
770
- },
771
- },
772
- ],
773
- },
774
- ] as unknown as ChatMessageSource[]);
775
-
776
- expect(adapted[0]?.parts[0]).toMatchObject({
777
- type: "tool-card",
778
- card: {
779
- toolName: "write_file",
780
- summary: "games/snake.html",
781
- statusTone: "success",
782
- fileOperation: {
783
- blocks: [
784
- {
785
- display: "preview",
786
- path: "games/snake.html",
787
- lines: [
788
- {
789
- kind: "add",
790
- text: "<!DOCTYPE html>",
791
- newLineNumber: 1,
792
- },
793
- {
794
- kind: "add",
795
- text: '<canvas id="game"></canvas>',
796
- newLineNumber: 2,
797
- },
798
- ],
799
- },
800
- ],
801
- },
802
- },
803
- });
804
- expect(adapted[0]?.parts[0]).not.toMatchObject({
805
- type: "tool-card",
806
- card: {
807
- output: "Wrote 3906 bytes to games/snake.html",
808
- },
809
- });
810
- });
811
-
812
- it("renders codex file_change results as structured diff previews", () => {
813
- const adapted = adapt([
814
- {
815
- id: "assistant-file-change",
816
- role: "assistant",
817
- parts: [
818
- {
819
- type: "tool-invocation",
820
- toolInvocation: {
821
- status: ToolInvocationStatus.RESULT,
822
- toolCallId: "file-change-1",
823
- toolName: "file_change",
824
- args: JSON.stringify({
825
- changes: [
826
- {
827
- path: "src/main.ts",
828
- diff: [
829
- "--- a/src/main.ts",
830
- "+++ b/src/main.ts",
831
- "@@ -109,1 +109,1 @@",
832
- "-console.log('old');",
833
- "+console.log('new');",
834
- ].join("\n"),
835
- },
836
- ],
837
- }),
838
- result: {
839
- status: "completed",
840
- changes: [
841
- {
842
- path: "src/main.ts",
843
- diff: [
844
- "--- a/src/main.ts",
845
- "+++ b/src/main.ts",
846
- "@@ -109,1 +109,1 @@",
847
- "-console.log('old');",
848
- "+console.log('new');",
849
- ].join("\n"),
850
- },
851
- ],
852
- },
853
- },
854
- },
855
- ],
856
- },
857
- ] as unknown as ChatMessageSource[]);
858
-
859
- expect(adapted[0]?.parts[0]).toMatchObject({
860
- type: "tool-card",
861
- card: {
862
- toolName: "file_change",
863
- summary: "src/main.ts",
864
- statusTone: "success",
865
- fileOperation: {
866
- blocks: [
867
- {
868
- path: "src/main.ts",
869
- lines: [
870
- {
871
- kind: "remove",
872
- text: "console.log('old');",
873
- oldLineNumber: 109,
874
- },
875
- {
876
- kind: "add",
877
- text: "console.log('new');",
878
- newLineNumber: 109,
879
- },
880
- ],
881
- },
882
- ],
883
- },
884
- },
885
- });
886
- });
@@ -150,17 +150,18 @@ export function resolveToolCardStatus(params: {
150
150
  ChatToolPartViewModel,
151
151
  "kind" | "hasResult" | "statusTone" | "statusLabel"
152
152
  > {
153
+ const { cancelled, error, result, status, texts } = params;
153
154
  const rawStatus =
154
- typeof params.status === "string" ? params.status.trim().toLowerCase() : "";
155
+ typeof status === "string" ? status.trim().toLowerCase() : "";
155
156
  const hasError =
156
- typeof params.error === "string" && params.error.trim().length > 0;
157
- const isCancelled = params.cancelled === true || rawStatus === "cancelled";
157
+ typeof error === "string" && error.trim().length > 0;
158
+ const isCancelled = cancelled === true || rawStatus === "cancelled";
158
159
  if (isCancelled) {
159
160
  return {
160
161
  kind: "result",
161
162
  hasResult: true,
162
163
  statusTone: "cancelled",
163
- statusLabel: params.texts.toolStatusCancelledLabel,
164
+ statusLabel: texts.toolStatusCancelledLabel,
164
165
  };
165
166
  }
166
167
  if (hasError || rawStatus === "error") {
@@ -168,15 +169,15 @@ export function resolveToolCardStatus(params: {
168
169
  kind: "result",
169
170
  hasResult: true,
170
171
  statusTone: "error",
171
- statusLabel: params.texts.toolStatusFailedLabel,
172
+ statusLabel: texts.toolStatusFailedLabel,
172
173
  };
173
174
  }
174
- if (rawStatus === "result" || params.result != null) {
175
+ if (rawStatus === "result" || result != null) {
175
176
  return {
176
177
  kind: "result",
177
178
  hasResult: true,
178
179
  statusTone: "success",
179
- statusLabel: params.texts.toolStatusCompletedLabel,
180
+ statusLabel: texts.toolStatusCompletedLabel,
180
181
  };
181
182
  }
182
183
  if (rawStatus === "partial-call") {
@@ -184,14 +185,14 @@ export function resolveToolCardStatus(params: {
184
185
  kind: "call",
185
186
  hasResult: false,
186
187
  statusTone: "running",
187
- statusLabel: params.texts.toolStatusRunningLabel,
188
+ statusLabel: texts.toolStatusRunningLabel,
188
189
  };
189
190
  }
190
191
  return {
191
192
  kind: "call",
192
193
  hasResult: false,
193
194
  statusTone: "running",
194
- statusLabel: params.texts.toolStatusRunningLabel,
195
+ statusLabel: texts.toolStatusRunningLabel,
195
196
  };
196
197
  }
197
198
 
@@ -24,16 +24,17 @@ export function buildRawPreviewBlock(params: {
24
24
  oldStartLine?: number | null;
25
25
  newStartLine?: number | null;
26
26
  }): ParsedBlock | null {
27
- const previewText = params.text.trim();
27
+ const { newStartLine: rawNewStartLine, oldStartLine: rawOldStartLine, operation, path, text } = params;
28
+ const previewText = text.trim();
28
29
  if (!previewText) {
29
30
  return null;
30
31
  }
31
32
  const previewKind =
32
- params.operation?.trim().toLowerCase() === "write" ? "add" : "context";
33
+ operation?.trim().toLowerCase() === "write" ? "add" : "context";
33
34
  const oldStartLine =
34
- typeof params.oldStartLine === "number" ? params.oldStartLine : 1;
35
+ typeof rawOldStartLine === "number" ? rawOldStartLine : 1;
35
36
  const newStartLine =
36
- typeof params.newStartLine === "number" ? params.newStartLine : 1;
37
+ typeof rawNewStartLine === "number" ? rawNewStartLine : 1;
37
38
  const lines = buildPreviewLines({
38
39
  text: previewText,
39
40
  kind: previewKind,
@@ -41,10 +42,10 @@ export function buildRawPreviewBlock(params: {
41
42
  newStartLine,
42
43
  });
43
44
  return {
44
- path: params.path,
45
+ path,
45
46
  display: "preview",
46
47
  caption: buildCaption({
47
- operation: params.operation,
48
+ operation,
48
49
  lines,
49
50
  }),
50
51
  lines,
@@ -62,10 +63,11 @@ export function buildFullReplaceBlock(params: {
62
63
  oldStartLine?: number | null;
63
64
  newStartLine?: number | null;
64
65
  }): ParsedBlock | null {
66
+ const { afterText, beforeText, operation, path } = params;
65
67
  const { oldStartLine, newStartLine } = readDefaultDiffStartLines(params);
66
68
  const lines = buildLineDiff({
67
- beforeText: params.beforeText ?? "",
68
- afterText: params.afterText ?? "",
69
+ beforeText: beforeText ?? "",
70
+ afterText: afterText ?? "",
69
71
  oldStartLine,
70
72
  newStartLine,
71
73
  });
@@ -74,16 +76,16 @@ export function buildFullReplaceBlock(params: {
74
76
  return null;
75
77
  }
76
78
  return {
77
- path: params.path,
79
+ path,
78
80
  display: "diff",
79
81
  caption: buildCaption({
80
- operation: params.operation,
82
+ operation,
81
83
  lines,
82
84
  }),
83
85
  lines: limited.lines,
84
86
  ...(limited.truncated ? { fullLines: lines } : {}),
85
- ...(params.beforeText != null ? { beforeText: params.beforeText } : {}),
86
- ...(params.afterText != null ? { afterText: params.afterText } : {}),
87
+ ...(beforeText != null ? { beforeText } : {}),
88
+ ...(afterText != null ? { afterText } : {}),
87
89
  ...(typeof oldStartLine === "number" ? { oldStartLine } : {}),
88
90
  ...(typeof newStartLine === "number" ? { newStartLine } : {}),
89
91
  truncated: limited.truncated,
@@ -95,23 +97,24 @@ function updateApplyPatchCursor(params: {
95
97
  flushCurrent: () => void;
96
98
  setCurrent: (path: string, operation: string) => void;
97
99
  }): boolean {
98
- if (params.line.startsWith("*** Update File: ")) {
99
- params.flushCurrent();
100
- params.setCurrent(
101
- params.line.slice("*** Update File: ".length).trim(),
100
+ const { flushCurrent, line, setCurrent } = params;
101
+ if (line.startsWith("*** Update File: ")) {
102
+ flushCurrent();
103
+ setCurrent(
104
+ line.slice("*** Update File: ".length).trim(),
102
105
  "update",
103
106
  );
104
107
  return true;
105
108
  }
106
- if (params.line.startsWith("*** Add File: ")) {
107
- params.flushCurrent();
108
- params.setCurrent(params.line.slice("*** Add File: ".length).trim(), "add");
109
+ if (line.startsWith("*** Add File: ")) {
110
+ flushCurrent();
111
+ setCurrent(line.slice("*** Add File: ".length).trim(), "add");
109
112
  return true;
110
113
  }
111
- if (params.line.startsWith("*** Delete File: ")) {
112
- params.flushCurrent();
113
- params.setCurrent(
114
- params.line.slice("*** Delete File: ".length).trim(),
114
+ if (line.startsWith("*** Delete File: ")) {
115
+ flushCurrent();
116
+ setCurrent(
117
+ line.slice("*** Delete File: ".length).trim(),
115
118
  "delete",
116
119
  );
117
120
  return true;
@@ -128,18 +131,18 @@ function appendPatchLine(params: {
128
131
  oldLineNumber?: number;
129
132
  newLineNumber?: number;
130
133
  } {
131
- const { currentLines, line } = params;
134
+ const { currentLines, line, newLineNumber, oldLineNumber } = params;
132
135
  if (line.startsWith("+")) {
133
136
  currentLines.push(
134
137
  createLine({
135
138
  kind: "add",
136
139
  text: line.slice(1),
137
- newLineNumber: params.newLineNumber,
140
+ newLineNumber,
138
141
  }),
139
142
  );
140
143
  return {
141
- oldLineNumber: params.oldLineNumber,
142
- newLineNumber: incrementLineNumber(params.newLineNumber),
144
+ oldLineNumber,
145
+ newLineNumber: incrementLineNumber(newLineNumber),
143
146
  };
144
147
  }
145
148
  if (line.startsWith("-")) {
@@ -147,12 +150,12 @@ function appendPatchLine(params: {
147
150
  createLine({
148
151
  kind: "remove",
149
152
  text: line.slice(1),
150
- oldLineNumber: params.oldLineNumber,
153
+ oldLineNumber,
151
154
  }),
152
155
  );
153
156
  return {
154
- oldLineNumber: incrementLineNumber(params.oldLineNumber),
155
- newLineNumber: params.newLineNumber,
157
+ oldLineNumber: incrementLineNumber(oldLineNumber),
158
+ newLineNumber,
156
159
  };
157
160
  }
158
161
  if (line.startsWith(" ")) {
@@ -160,18 +163,18 @@ function appendPatchLine(params: {
160
163
  createLine({
161
164
  kind: "context",
162
165
  text: line.slice(1),
163
- oldLineNumber: params.oldLineNumber,
164
- newLineNumber: params.newLineNumber,
166
+ oldLineNumber,
167
+ newLineNumber,
165
168
  }),
166
169
  );
167
170
  return {
168
- oldLineNumber: incrementLineNumber(params.oldLineNumber),
169
- newLineNumber: incrementLineNumber(params.newLineNumber),
171
+ oldLineNumber: incrementLineNumber(oldLineNumber),
172
+ newLineNumber: incrementLineNumber(newLineNumber),
170
173
  };
171
174
  }
172
175
  return {
173
- oldLineNumber: params.oldLineNumber,
174
- newLineNumber: params.newLineNumber,
176
+ oldLineNumber,
177
+ newLineNumber,
175
178
  };
176
179
  }
177
180