summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/context/prompt.tsx
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-02-12 09:49:14 -0600
committerGitHub <[email protected]>2026-02-12 09:49:14 -0600
commitff4414bb152acfddb5c0eb073c38bedc1df4ae14 (patch)
tree78381c67d21ef6f089647f6b19e7aa2976840dbc /packages/app/src/context/prompt.tsx
parent56ad2db02055955f926fda0e4a89055b22ead6f9 (diff)
downloadopencode-ff4414bb152acfddb5c0eb073c38bedc1df4ae14.tar.gz
opencode-ff4414bb152acfddb5c0eb073c38bedc1df4ae14.zip
chore: refactor packages/app files (#13236)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: Frank <[email protected]>
Diffstat (limited to 'packages/app/src/context/prompt.tsx')
-rw-r--r--packages/app/src/context/prompt.tsx109
1 files changed, 61 insertions, 48 deletions
diff --git a/packages/app/src/context/prompt.tsx b/packages/app/src/context/prompt.tsx
index 99fab6c19..064892105 100644
--- a/packages/app/src/context/prompt.tsx
+++ b/packages/app/src/context/prompt.tsx
@@ -1,4 +1,4 @@
-import { createStore } from "solid-js/store"
+import { createStore, type SetStoreFunction } from "solid-js/store"
import { createSimpleContext } from "@opencode-ai/ui/context"
import { batch, createMemo, createRoot, onCleanup } from "solid-js"
import { useParams } from "@solidjs/router"
@@ -60,27 +60,23 @@ function isSelectionEqual(a?: FileSelection, b?: FileSelection) {
)
}
+function isPartEqual(partA: ContentPart, partB: ContentPart) {
+ switch (partA.type) {
+ case "text":
+ return partB.type === "text" && partA.content === partB.content
+ case "file":
+ return partB.type === "file" && partA.path === partB.path && isSelectionEqual(partA.selection, partB.selection)
+ case "agent":
+ return partB.type === "agent" && partA.name === partB.name
+ case "image":
+ return partB.type === "image" && partA.id === partB.id
+ }
+}
+
export function isPromptEqual(promptA: Prompt, promptB: Prompt): boolean {
if (promptA.length !== promptB.length) return false
for (let i = 0; i < promptA.length; i++) {
- const partA = promptA[i]
- const partB = promptB[i]
- if (partA.type !== partB.type) return false
- if (partA.type === "text" && partA.content !== (partB as TextPart).content) {
- return false
- }
- if (partA.type === "file") {
- const fileA = partA as FileAttachmentPart
- const fileB = partB as FileAttachmentPart
- if (fileA.path !== fileB.path) return false
- if (!isSelectionEqual(fileA.selection, fileB.selection)) return false
- }
- if (partA.type === "agent" && partA.name !== (partB as AgentPart).name) {
- return false
- }
- if (partA.type === "image" && partA.id !== (partB as ImageAttachmentPart).id) {
- return false
- }
+ if (!isPartEqual(promptA[i], promptB[i])) return false
}
return true
}
@@ -104,6 +100,48 @@ function clonePrompt(prompt: Prompt): Prompt {
return prompt.map(clonePart)
}
+function contextItemKey(item: ContextItem) {
+ if (item.type !== "file") return item.type
+ const start = item.selection?.startLine
+ const end = item.selection?.endLine
+ const key = `${item.type}:${item.path}:${start}:${end}`
+
+ if (item.commentID) {
+ return `${key}:c=${item.commentID}`
+ }
+
+ const comment = item.comment?.trim()
+ if (!comment) return key
+ const digest = checksum(comment) ?? comment
+ return `${key}:c=${digest.slice(0, 8)}`
+}
+
+function createPromptActions(
+ setStore: SetStoreFunction<{
+ prompt: Prompt
+ cursor?: number
+ context: {
+ items: (ContextItem & { key: string })[]
+ }
+ }>,
+) {
+ return {
+ set(prompt: Prompt, cursorPosition?: number) {
+ const next = clonePrompt(prompt)
+ batch(() => {
+ setStore("prompt", next)
+ if (cursorPosition !== undefined) setStore("cursor", cursorPosition)
+ })
+ },
+ reset() {
+ batch(() => {
+ setStore("prompt", clonePrompt(DEFAULT_PROMPT))
+ setStore("cursor", 0)
+ })
+ },
+ }
+}
+
const WORKSPACE_KEY = "__workspace__"
const MAX_PROMPT_SESSIONS = 20
@@ -134,21 +172,7 @@ function createPromptSession(dir: string, id: string | undefined) {
}),
)
- function keyForItem(item: ContextItem) {
- if (item.type !== "file") return item.type
- const start = item.selection?.startLine
- const end = item.selection?.endLine
- const key = `${item.type}:${item.path}:${start}:${end}`
-
- if (item.commentID) {
- return `${key}:c=${item.commentID}`
- }
-
- const comment = item.comment?.trim()
- if (!comment) return key
- const digest = checksum(comment) ?? comment
- return `${key}:c=${digest.slice(0, 8)}`
- }
+ const actions = createPromptActions(setStore)
return {
ready,
@@ -158,7 +182,7 @@ function createPromptSession(dir: string, id: string | undefined) {
context: {
items: createMemo(() => store.context.items),
add(item: ContextItem) {
- const key = keyForItem(item)
+ const key = contextItemKey(item)
if (store.context.items.find((x) => x.key === key)) return
setStore("context", "items", (items) => [...items, { key, ...item }])
},
@@ -166,19 +190,8 @@ function createPromptSession(dir: string, id: string | undefined) {
setStore("context", "items", (items) => items.filter((x) => x.key !== key))
},
},
- set(prompt: Prompt, cursorPosition?: number) {
- const next = clonePrompt(prompt)
- batch(() => {
- setStore("prompt", next)
- if (cursorPosition !== undefined) setStore("cursor", cursorPosition)
- })
- },
- reset() {
- batch(() => {
- setStore("prompt", clonePrompt(DEFAULT_PROMPT))
- setStore("cursor", 0)
- })
- },
+ set: actions.set,
+ reset: actions.reset,
}
}