@mtayfur/opencode-prompt-enhancer 0.0.2 → 0.0.4
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/package.json +9 -6
- package/plugins/prompt-enhancer.tsx +109 -7
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mtayfur/opencode-prompt-enhancer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "OpenCode plugin that rewrites rough drafts into stronger prompts.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
8
|
"type": "module",
|
|
9
|
-
"main": "./index.ts",
|
|
10
9
|
"exports": {
|
|
11
10
|
".": "./index.ts",
|
|
12
11
|
"./tui": "./plugins/prompt-enhancer.tsx"
|
|
@@ -22,10 +21,14 @@
|
|
|
22
21
|
"index.ts",
|
|
23
22
|
"plugins"
|
|
24
23
|
],
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
"engines": {
|
|
25
|
+
"opencode": ">=1.3.14"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@opencode-ai/plugin": "*",
|
|
29
|
+
"@opencode-ai/sdk": "*",
|
|
30
|
+
"@opentui/solid": "*",
|
|
31
|
+
"solid-js": "*"
|
|
29
32
|
},
|
|
30
33
|
"devDependencies": {
|
|
31
34
|
"typescript": "5.8.2"
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
2
|
import type { PluginOptions } from "@opencode-ai/plugin"
|
|
3
3
|
import type { Message, Part, TextPart } from "@opencode-ai/sdk/v2"
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
TuiPlugin,
|
|
6
|
+
TuiPluginModule,
|
|
7
|
+
TuiPromptInfo,
|
|
8
|
+
TuiPromptRef,
|
|
9
|
+
TuiRouteCurrent,
|
|
10
|
+
TuiSidebarFileItem,
|
|
11
|
+
TuiSidebarTodoItem,
|
|
12
|
+
TuiSlotPlugin,
|
|
13
|
+
} from "@opencode-ai/plugin/tui"
|
|
5
14
|
|
|
6
15
|
const MAX_RECENT_MESSAGES = 6
|
|
7
16
|
const MAX_CHANGED_FILES = 30
|
|
@@ -10,6 +19,10 @@ const MAX_TODOS = 10
|
|
|
10
19
|
const DIALOG_TITLE = "Enhance Prompt"
|
|
11
20
|
const TOAST_TITLE = "Prompt enhancer"
|
|
12
21
|
const TEMP_SESSION_TITLE = "Prompt Enhancer"
|
|
22
|
+
const HOME_PROMPT_PLACEHOLDERS = {
|
|
23
|
+
normal: ["Fix a TODO in the codebase", "What is the tech stack of this project?", "Fix broken tests"],
|
|
24
|
+
shell: ["ls -la", "git status", "pwd"],
|
|
25
|
+
}
|
|
13
26
|
|
|
14
27
|
const ENHANCER_SYSTEM_PROMPT = `You rewrite rough user drafts into strong prompts for OpenCode, an AI coding assistant.
|
|
15
28
|
|
|
@@ -51,6 +64,7 @@ type ModelRef = {
|
|
|
51
64
|
type Api = Parameters<TuiPlugin>[0]
|
|
52
65
|
type PluginState = {
|
|
53
66
|
enhancing: boolean
|
|
67
|
+
promptRef?: TuiPromptRef
|
|
54
68
|
}
|
|
55
69
|
|
|
56
70
|
function parseModelString(value: string | undefined): ModelRef | undefined {
|
|
@@ -104,6 +118,58 @@ function resolveEnhancerModel(api: Api, options: PluginOptions | undefined): Mod
|
|
|
104
118
|
return parseModelString(api.state.config.small_model || api.state.config.model)
|
|
105
119
|
}
|
|
106
120
|
|
|
121
|
+
function clonePromptInfo(prompt: TuiPromptInfo): TuiPromptInfo {
|
|
122
|
+
return {
|
|
123
|
+
input: prompt.input,
|
|
124
|
+
mode: prompt.mode,
|
|
125
|
+
parts: prompt.parts.map((part) => ({ ...part })),
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function nextPromptInfo(prompt: TuiPromptInfo, input: string): TuiPromptInfo {
|
|
130
|
+
return {
|
|
131
|
+
input,
|
|
132
|
+
mode: prompt.mode,
|
|
133
|
+
parts: prompt.parts.filter((part) => part.type !== "text").map((part) => ({ ...part })),
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function currentPromptText(state: PluginState): string {
|
|
138
|
+
return state.promptRef?.current.input ?? ""
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function bindPromptRef(state: PluginState, forwarded: ((ref: TuiPromptRef | undefined) => void) | undefined, ref: TuiPromptRef | undefined): void {
|
|
142
|
+
state.promptRef = ref
|
|
143
|
+
forwarded?.(ref)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function writePrompt(api: Api, state: PluginState, input: string, signal: AbortSignal, template?: TuiPromptInfo): Promise<void> {
|
|
147
|
+
const promptRef = state.promptRef
|
|
148
|
+
if (promptRef) {
|
|
149
|
+
promptRef.set(nextPromptInfo(template ?? promptRef.current, input))
|
|
150
|
+
promptRef.focus()
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const directory = api.state.path.directory
|
|
155
|
+
const requestOptions = { signal, throwOnError: true } as const
|
|
156
|
+
await api.client.tui.clearPrompt({ directory }, requestOptions)
|
|
157
|
+
if (input) {
|
|
158
|
+
await api.client.tui.appendPrompt({ directory, text: input }, requestOptions)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function restorePrompt(api: Api, state: PluginState, prompt: TuiPromptInfo, signal: AbortSignal): Promise<void> {
|
|
163
|
+
const promptRef = state.promptRef
|
|
164
|
+
if (promptRef) {
|
|
165
|
+
promptRef.set(clonePromptInfo(prompt))
|
|
166
|
+
promptRef.focus()
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
await writePrompt(api, state, prompt.input, signal, prompt)
|
|
171
|
+
}
|
|
172
|
+
|
|
107
173
|
function gatherContext(api: Api): string {
|
|
108
174
|
const sections: string[] = []
|
|
109
175
|
|
|
@@ -231,10 +297,13 @@ function openEnhanceDialog(
|
|
|
231
297
|
|
|
232
298
|
if (signal.aborted) return
|
|
233
299
|
|
|
300
|
+
const initialValue = currentPromptText(state)
|
|
301
|
+
|
|
234
302
|
api.ui.dialog.replace(() => (
|
|
235
303
|
<api.ui.DialogPrompt
|
|
236
304
|
title={DIALOG_TITLE}
|
|
237
305
|
placeholder="Describe what you want to do..."
|
|
306
|
+
value={initialValue}
|
|
238
307
|
onCancel={() => api.ui.dialog.clear()}
|
|
239
308
|
onConfirm={(value) => {
|
|
240
309
|
const input = value.trim()
|
|
@@ -244,7 +313,11 @@ function openEnhanceDialog(
|
|
|
244
313
|
return
|
|
245
314
|
}
|
|
246
315
|
|
|
316
|
+
const originalPrompt = state.promptRef ? clonePromptInfo(state.promptRef.current) : undefined
|
|
247
317
|
state.enhancing = true
|
|
318
|
+
if (originalPrompt) {
|
|
319
|
+
state.promptRef?.set(nextPromptInfo(originalPrompt, ""))
|
|
320
|
+
}
|
|
248
321
|
api.ui.dialog.clear()
|
|
249
322
|
api.ui.toast({
|
|
250
323
|
variant: "info",
|
|
@@ -258,10 +331,7 @@ function openEnhanceDialog(
|
|
|
258
331
|
const enhanced = await enhanceWithModel(api, options, input, signal)
|
|
259
332
|
if (signal.aborted) return
|
|
260
333
|
|
|
261
|
-
|
|
262
|
-
const requestOptions = { signal, throwOnError: true } as const
|
|
263
|
-
await api.client.tui.clearPrompt({ directory }, requestOptions)
|
|
264
|
-
await api.client.tui.appendPrompt({ directory, text: enhanced }, requestOptions)
|
|
334
|
+
await writePrompt(api, state, enhanced, signal, originalPrompt)
|
|
265
335
|
api.ui.toast({
|
|
266
336
|
variant: "success",
|
|
267
337
|
title: "Prompt enhanced",
|
|
@@ -271,6 +341,10 @@ function openEnhanceDialog(
|
|
|
271
341
|
} catch (error) {
|
|
272
342
|
if (signal.aborted) return
|
|
273
343
|
|
|
344
|
+
if (originalPrompt) {
|
|
345
|
+
await restorePrompt(api, state, originalPrompt, signal)
|
|
346
|
+
}
|
|
347
|
+
|
|
274
348
|
const message = error instanceof Error ? error.message : "Model enhancement failed."
|
|
275
349
|
api.ui.toast({ variant: "error", title: TOAST_TITLE, message })
|
|
276
350
|
} finally {
|
|
@@ -285,11 +359,40 @@ function openEnhanceDialog(
|
|
|
285
359
|
const tui: TuiPlugin = async (api, options) => {
|
|
286
360
|
const state: PluginState = { enhancing: false }
|
|
287
361
|
|
|
362
|
+
const promptSlots: TuiSlotPlugin = {
|
|
363
|
+
slots: {
|
|
364
|
+
home_prompt(_ctx, props) {
|
|
365
|
+
return (
|
|
366
|
+
<api.ui.Prompt
|
|
367
|
+
ref={(ref) => bindPromptRef(state, props.ref, ref)}
|
|
368
|
+
workspaceID={props.workspace_id}
|
|
369
|
+
right={<api.ui.Slot name="home_prompt_right" workspace_id={props.workspace_id} />}
|
|
370
|
+
placeholders={HOME_PROMPT_PLACEHOLDERS}
|
|
371
|
+
/>
|
|
372
|
+
)
|
|
373
|
+
},
|
|
374
|
+
session_prompt(_ctx, props) {
|
|
375
|
+
return (
|
|
376
|
+
<api.ui.Prompt
|
|
377
|
+
ref={(ref) => bindPromptRef(state, props.ref, ref)}
|
|
378
|
+
sessionID={props.session_id}
|
|
379
|
+
visible={props.visible}
|
|
380
|
+
disabled={props.disabled}
|
|
381
|
+
onSubmit={props.on_submit}
|
|
382
|
+
right={<api.ui.Slot name="session_prompt_right" session_id={props.session_id} />}
|
|
383
|
+
/>
|
|
384
|
+
)
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
api.slots.register(promptSlots)
|
|
390
|
+
|
|
288
391
|
const unregister = api.command.register(() => [
|
|
289
392
|
{
|
|
290
393
|
title: DIALOG_TITLE,
|
|
291
394
|
value: "prompt-enhancer.enhance",
|
|
292
|
-
description: "
|
|
395
|
+
description: "Enhance prompt with project context (Ctrl+E)",
|
|
293
396
|
category: "Prompt",
|
|
294
397
|
keybind: "ctrl+e",
|
|
295
398
|
suggested: true,
|
|
@@ -315,4 +418,3 @@ const plugin: TuiPluginModule & { id: string } = {
|
|
|
315
418
|
}
|
|
316
419
|
|
|
317
420
|
export default plugin
|
|
318
|
-
|