@neurocode-ai/session-ui 1.18.8

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 (114) hide show
  1. package/package.json +71 -0
  2. package/src/components/apply-patch-file.test.ts +43 -0
  3. package/src/components/apply-patch-file.ts +78 -0
  4. package/src/components/basic-tool.css +358 -0
  5. package/src/components/basic-tool.stories.tsx +133 -0
  6. package/src/components/basic-tool.tsx +343 -0
  7. package/src/components/dock-prompt.stories.tsx +62 -0
  8. package/src/components/dock-prompt.tsx +23 -0
  9. package/src/components/file-media.tsx +291 -0
  10. package/src/components/file-search.tsx +72 -0
  11. package/src/components/file-ssr.tsx +197 -0
  12. package/src/components/file.css +46 -0
  13. package/src/components/file.tsx +1202 -0
  14. package/src/components/line-comment-annotations.tsx +637 -0
  15. package/src/components/line-comment-styles.ts +292 -0
  16. package/src/components/line-comment.stories.tsx +115 -0
  17. package/src/components/line-comment.tsx +439 -0
  18. package/src/components/markdown-cache.tsx +78 -0
  19. package/src/components/markdown-code-state.test.ts +32 -0
  20. package/src/components/markdown-code-state.ts +22 -0
  21. package/src/components/markdown-inline-code-kind.test.ts +46 -0
  22. package/src/components/markdown-inline-code-kind.ts +1915 -0
  23. package/src/components/markdown-preload.test.ts +18 -0
  24. package/src/components/markdown-shiki.worker.ts +104 -0
  25. package/src/components/markdown-stream.test.ts +194 -0
  26. package/src/components/markdown-stream.ts +110 -0
  27. package/src/components/markdown-worker-protocol.test.ts +81 -0
  28. package/src/components/markdown-worker-protocol.ts +48 -0
  29. package/src/components/markdown-worker-queue.test.ts +49 -0
  30. package/src/components/markdown-worker-queue.ts +64 -0
  31. package/src/components/markdown-worker-transport.test.ts +56 -0
  32. package/src/components/markdown-worker-transport.ts +41 -0
  33. package/src/components/markdown-worker.ts +122 -0
  34. package/src/components/markdown.css +377 -0
  35. package/src/components/markdown.stories.tsx +53 -0
  36. package/src/components/markdown.tsx +678 -0
  37. package/src/components/message-file.test.ts +63 -0
  38. package/src/components/message-file.ts +34 -0
  39. package/src/components/message-nav.css +127 -0
  40. package/src/components/message-nav.stories.tsx +7 -0
  41. package/src/components/message-nav.tsx +102 -0
  42. package/src/components/message-part-text.ts +3 -0
  43. package/src/components/message-part.css +1569 -0
  44. package/src/components/message-part.stories.tsx +7 -0
  45. package/src/components/message-part.test.ts +28 -0
  46. package/src/components/message-part.tsx +2662 -0
  47. package/src/components/session-diff.test.ts +135 -0
  48. package/src/components/session-diff.ts +145 -0
  49. package/src/components/session-retry.tsx +74 -0
  50. package/src/components/session-review.css +247 -0
  51. package/src/components/session-review.stories.tsx +7 -0
  52. package/src/components/session-review.tsx +657 -0
  53. package/src/components/session-turn.css +241 -0
  54. package/src/components/session-turn.stories.tsx +7 -0
  55. package/src/components/session-turn.tsx +543 -0
  56. package/src/components/shell-submessage-motion.stories.tsx +346 -0
  57. package/src/components/shell-submessage.css +23 -0
  58. package/src/components/timeline-playground.stories.tsx +2090 -0
  59. package/src/components/tool-count-label.css +57 -0
  60. package/src/components/tool-count-label.tsx +58 -0
  61. package/src/components/tool-count-summary.css +102 -0
  62. package/src/components/tool-count-summary.stories.tsx +238 -0
  63. package/src/components/tool-count-summary.tsx +52 -0
  64. package/src/components/tool-error-card.css +91 -0
  65. package/src/components/tool-error-card.stories.tsx +92 -0
  66. package/src/components/tool-error-card.tsx +157 -0
  67. package/src/components/tool-status-title.css +89 -0
  68. package/src/components/tool-status-title.tsx +133 -0
  69. package/src/context/data.tsx +64 -0
  70. package/src/context/index.ts +1 -0
  71. package/src/pierre/comment-hover.ts +83 -0
  72. package/src/pierre/commented-lines.ts +91 -0
  73. package/src/pierre/diff-selection.ts +71 -0
  74. package/src/pierre/file-find.ts +485 -0
  75. package/src/pierre/file-runtime.ts +114 -0
  76. package/src/pierre/file-selection.ts +85 -0
  77. package/src/pierre/index.ts +186 -0
  78. package/src/pierre/media.ts +110 -0
  79. package/src/pierre/selection-bridge.ts +132 -0
  80. package/src/pierre/virtualizer.ts +100 -0
  81. package/src/pierre/worker.ts +52 -0
  82. package/src/styles/index.css +14 -0
  83. package/src/v2/components/attachment-card-v2.css +70 -0
  84. package/src/v2/components/attachment-card-v2.tsx +33 -0
  85. package/src/v2/components/basic-tool-v2.css +163 -0
  86. package/src/v2/components/basic-tool-v2.stories.tsx +137 -0
  87. package/src/v2/components/basic-tool-v2.tsx +139 -0
  88. package/src/v2/components/comment-card-v2.tsx +64 -0
  89. package/src/v2/components/line-comment-annotations-v2.tsx +220 -0
  90. package/src/v2/components/prompt-input/attachments.ts +266 -0
  91. package/src/v2/components/prompt-input/index.tsx +706 -0
  92. package/src/v2/components/prompt-input/interaction.ts +482 -0
  93. package/src/v2/components/prompt-input/machine.test.ts +164 -0
  94. package/src/v2/components/prompt-input/machine.ts +261 -0
  95. package/src/v2/components/prompt-input/prompt-input.stories.tsx +221 -0
  96. package/src/v2/components/prompt-input/store.test.ts +116 -0
  97. package/src/v2/components/prompt-input/store.ts +152 -0
  98. package/src/v2/components/prompt-input/types.ts +106 -0
  99. package/src/v2/components/session-file-panel-v2.tsx +43 -0
  100. package/src/v2/components/session-progress-indicator-v2.css +875 -0
  101. package/src/v2/components/session-progress-indicator-v2.stories.tsx +66 -0
  102. package/src/v2/components/session-progress-indicator-v2.tsx +32 -0
  103. package/src/v2/components/session-review-empty-changes-v2.tsx +17 -0
  104. package/src/v2/components/session-review-empty-no-git-v2.tsx +28 -0
  105. package/src/v2/components/session-review-file-preview-v2-virtualize.test.ts +13 -0
  106. package/src/v2/components/session-review-file-preview-v2-virtualize.ts +5 -0
  107. package/src/v2/components/session-review-file-preview-v2.tsx +290 -0
  108. package/src/v2/components/session-review-v2.css +458 -0
  109. package/src/v2/components/session-review-v2.tsx +340 -0
  110. package/src/v2/components/tool-error-card-v2.css +200 -0
  111. package/src/v2/components/tool-error-card-v2.stories.tsx +91 -0
  112. package/src/v2/components/tool-error-card-v2.tsx +166 -0
  113. package/sst-env.d.ts +10 -0
  114. package/tsconfig.json +19 -0
@@ -0,0 +1,152 @@
1
+ import { batch, type Accessor } from "solid-js"
2
+ import type { SetStoreFunction, Store } from "solid-js/store"
3
+ import type {
4
+ PromptInputV2AgentPart,
5
+ PromptInputV2Attachment,
6
+ PromptInputV2Comment,
7
+ PromptInputV2FilePart,
8
+ PromptInputV2Model,
9
+ PromptInputV2PersistedState,
10
+ PromptInputV2Prompt,
11
+ } from "./types"
12
+
13
+ export type PromptInputV2StoreTuple = [
14
+ Store<PromptInputV2PersistedState> | Accessor<Store<PromptInputV2PersistedState>>,
15
+ SetStoreFunction<PromptInputV2PersistedState>,
16
+ ]
17
+
18
+ export type PromptInputV2StoreInput = PromptInputV2StoreTuple | Accessor<PromptInputV2StoreTuple>
19
+
20
+ export function createPromptInputV2Store(input: PromptInputV2StoreInput) {
21
+ const tuple = () => (typeof input === "function" ? input() : input)
22
+ const store = () => {
23
+ const value = tuple()[0]
24
+ return typeof value === "function" ? value() : value
25
+ }
26
+ const setStore = () => tuple()[1]
27
+
28
+ return {
29
+ get state() {
30
+ return store()
31
+ },
32
+ setPrompt(prompt: PromptInputV2Prompt, cursor?: number) {
33
+ batch(() => {
34
+ setStore()("prompt", prompt)
35
+ if (cursor !== undefined) setStore()("cursor", cursor)
36
+ })
37
+ },
38
+ setCursor(cursor: number) {
39
+ setStore()("cursor", cursor)
40
+ },
41
+ setText(content: string) {
42
+ batch(() => {
43
+ setStore()("prompt", (prompt) => [
44
+ { type: "text", content, start: 0, end: content.length },
45
+ ...prompt.filter((part) => part.type !== "text"),
46
+ ])
47
+ setStore()("cursor", content.length)
48
+ })
49
+ },
50
+ addText(content: string) {
51
+ const cursor = store().cursor ?? promptLength(store().prompt)
52
+ batch(() => {
53
+ setStore()("prompt", (prompt) => insertText(prompt, cursor, content))
54
+ setStore()("cursor", cursor + content.length)
55
+ })
56
+ },
57
+ reset() {
58
+ batch(() => {
59
+ setStore()("prompt", [{ type: "text", content: "", start: 0, end: 0 }])
60
+ setStore()("cursor", 0)
61
+ })
62
+ },
63
+ setModel(model: PromptInputV2Model | undefined) {
64
+ setStore()("model", model)
65
+ },
66
+ setVariant(variant: string | null) {
67
+ if (store().model) setStore()("model", "variant", variant)
68
+ },
69
+ addContext(item: PromptInputV2Comment) {
70
+ if (store().context.items.some((entry) => entry.key === item.key)) return
71
+ setStore()("context", "items", (items) => [...items, item])
72
+ },
73
+ removeContext(key: string) {
74
+ setStore()("context", "items", (items) => items.filter((item) => item.key !== key))
75
+ },
76
+ addMention(mention: PromptInputV2FilePart | PromptInputV2AgentPart) {
77
+ const text = store()
78
+ .prompt.map((part) => ("content" in part ? part.content : ""))
79
+ .join("")
80
+ const end = store().cursor ?? text.length
81
+ const start = text.slice(0, end).lastIndexOf("@")
82
+ setStore()("prompt", insertMention(store().prompt, start < 0 ? end : start, end, mention))
83
+ setStore()("cursor", (start < 0 ? end : start) + mention.content.length + 1)
84
+ },
85
+ addAttachment(attachment: PromptInputV2Attachment) {
86
+ setStore()("prompt", (prompt) => [...prompt, attachment])
87
+ },
88
+ removeAttachment(id: string) {
89
+ setStore()("prompt", (parts) => parts.filter((part) => part.type !== "image" || part.id !== id))
90
+ },
91
+ }
92
+ }
93
+
94
+ export type PromptInputV2Store = ReturnType<typeof createPromptInputV2Store>
95
+
96
+ function insertText(prompt: PromptInputV2Prompt, cursor: number, content: string): PromptInputV2Prompt {
97
+ let position = 0
98
+ let inserted = false
99
+ const parts = prompt.flatMap<PromptInputV2Prompt[number]>((part) => {
100
+ if (part.type === "image") return [part]
101
+ const start = position
102
+ position += part.content.length
103
+ if (inserted) return [part]
104
+ if (part.type === "text" && cursor >= start && cursor <= position) {
105
+ inserted = true
106
+ const offset = cursor - start
107
+ return [{ ...part, content: part.content.slice(0, offset) + content + part.content.slice(offset) }]
108
+ }
109
+ if (cursor > start) return [part]
110
+ inserted = true
111
+ return [{ type: "text", content, start: 0, end: 0 }, part]
112
+ })
113
+ if (!inserted) parts.push({ type: "text", content, start: 0, end: 0 })
114
+ return withOffsets(parts)
115
+ }
116
+
117
+ function insertMention(
118
+ prompt: PromptInputV2Prompt,
119
+ start: number,
120
+ end: number,
121
+ mention: PromptInputV2FilePart | PromptInputV2AgentPart,
122
+ ): PromptInputV2Prompt {
123
+ let position = 0
124
+ const parts = prompt.flatMap<PromptInputV2Prompt[number]>((part) => {
125
+ if (part.type === "image") return [part]
126
+ const partStart = position
127
+ position += part.content.length
128
+ if (part.type !== "text" || start < partStart || end > position) return [part]
129
+ const before = part.content.slice(0, start - partStart)
130
+ const after = part.content.slice(end - partStart)
131
+ return [
132
+ ...(before ? [{ type: "text" as const, content: before, start: 0, end: 0 }] : []),
133
+ mention,
134
+ { type: "text" as const, content: ` ${after}`, start: 0, end: 0 },
135
+ ]
136
+ })
137
+ return withOffsets(parts)
138
+ }
139
+
140
+ function withOffsets(prompt: PromptInputV2Prompt): PromptInputV2Prompt {
141
+ let offset = 0
142
+ return prompt.map((part) => {
143
+ if (part.type === "image") return part
144
+ const next = { ...part, start: offset, end: offset + part.content.length }
145
+ offset = next.end
146
+ return next
147
+ })
148
+ }
149
+
150
+ function promptLength(prompt: PromptInputV2Prompt) {
151
+ return prompt.reduce((length, part) => length + ("content" in part ? part.content.length : 0), 0)
152
+ }
@@ -0,0 +1,106 @@
1
+ import type { FilePartSource } from "@neurocode-ai/sdk/v2/client"
2
+
3
+ type PromptInputV2PartBase = {
4
+ content: string
5
+ start: number
6
+ end: number
7
+ }
8
+
9
+ export type PromptInputV2TextPart = PromptInputV2PartBase & {
10
+ type: "text"
11
+ }
12
+
13
+ export type PromptInputV2FilePart = PromptInputV2PartBase & {
14
+ type: "file"
15
+ path: string
16
+ selection?: PromptInputV2Selection
17
+ mime?: string
18
+ filename?: string
19
+ url?: string
20
+ source?: FilePartSource
21
+ }
22
+
23
+ export type PromptInputV2AgentPart = PromptInputV2PartBase & {
24
+ type: "agent"
25
+ name: string
26
+ }
27
+
28
+ export type PromptInputV2Attachment = {
29
+ type: "image"
30
+ id: string
31
+ filename: string
32
+ sourcePath?: string
33
+ mime: string
34
+ dataUrl: string
35
+ }
36
+
37
+ export type PromptInputV2Prompt = (
38
+ | PromptInputV2TextPart
39
+ | PromptInputV2FilePart
40
+ | PromptInputV2AgentPart
41
+ | PromptInputV2Attachment
42
+ )[]
43
+
44
+ export type PromptInputV2Model = {
45
+ providerID: string
46
+ modelID: string
47
+ variant?: string | null
48
+ }
49
+
50
+ export type PromptInputV2Selection = {
51
+ startLine: number
52
+ startChar: number
53
+ endLine: number
54
+ endChar: number
55
+ }
56
+
57
+ export type PromptInputV2Comment = {
58
+ type: "file"
59
+ key: string
60
+ path: string
61
+ selection?: PromptInputV2Selection
62
+ comment?: string
63
+ commentID?: string
64
+ commentOrigin?: "review" | "file"
65
+ preview?: string
66
+ }
67
+
68
+ export type PromptInputV2PersistedState = {
69
+ prompt: PromptInputV2Prompt
70
+ cursor?: number
71
+ model?: PromptInputV2Model
72
+ context: {
73
+ items: PromptInputV2Comment[]
74
+ }
75
+ }
76
+
77
+ export type PromptInputV2HistoryEntry = {
78
+ prompt: PromptInputV2Prompt
79
+ metadata?: unknown
80
+ }
81
+
82
+ export type PromptInputV2History = {
83
+ entries: (mode: "normal" | "shell") => PromptInputV2HistoryEntry[]
84
+ add: (prompt: PromptInputV2Prompt, mode: "normal" | "shell") => void
85
+ capture?: () => unknown
86
+ restore?: (metadata: unknown) => void
87
+ }
88
+
89
+ export type PromptInputV2Option = {
90
+ id: string
91
+ label: string
92
+ providerID?: string
93
+ }
94
+
95
+ export type PromptInputV2Suggestion = {
96
+ id: string
97
+ kind: "agent" | "command" | "file" | "reference" | "resource"
98
+ label: string
99
+ title?: string
100
+ trigger?: string
101
+ description?: string
102
+ path?: string
103
+ keybind?: string[]
104
+ recent?: boolean
105
+ mention?: PromptInputV2FilePart | PromptInputV2AgentPart
106
+ }
@@ -0,0 +1,43 @@
1
+ import { Show, type JSX, type ParentProps } from "solid-js"
2
+ import "./session-review-v2.css"
3
+
4
+ export function SessionFilePanelV2(props: {
5
+ sidebar?: JSX.Element
6
+ toolbar: boolean
7
+ toolbarStart?: JSX.Element
8
+ toolbarEnd?: JSX.Element
9
+ children?: JSX.Element
10
+ }) {
11
+ return (
12
+ <div data-component="session-review-v2">
13
+ <div data-slot="session-review-v2-body">
14
+ {props.sidebar}
15
+ <div data-slot="session-review-v2-preview">
16
+ <Show when={props.toolbar}>
17
+ <div data-slot="session-review-v2-toolbar">
18
+ <div data-slot="session-review-v2-toolbar-group" class="session-review-v2-toolbar-group--start">
19
+ {props.toolbarStart}
20
+ </div>
21
+ <Show when={props.toolbarEnd}>
22
+ {(toolbar) => (
23
+ <div data-slot="session-review-v2-toolbar-group" class="session-review-v2-toolbar-group--segments">
24
+ {toolbar()}
25
+ </div>
26
+ )}
27
+ </Show>
28
+ </div>
29
+ </Show>
30
+ {props.children}
31
+ </div>
32
+ </div>
33
+ </div>
34
+ )
35
+ }
36
+
37
+ export function SessionFilePanelV2Title(props: ParentProps) {
38
+ return <div data-slot="session-review-v2-toolbar-title">{props.children}</div>
39
+ }
40
+
41
+ export function SessionFilePanelV2Empty(props: ParentProps) {
42
+ return <div data-slot="session-review-v2-empty">{props.children}</div>
43
+ }