opencode-ghost 1.0.5 → 1.0.6
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/CHANGELOG.md +7 -0
- package/README.md +10 -4
- package/package.json +1 -1
- package/src/lifecycle.ts +3 -2
- package/src/tui.tsx +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.0.6] - 2026-10-08
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **tui:** Restore retained suggestions when drafts are emptied
|
|
13
|
+
|
|
8
14
|
## [1.0.5] - 2026-10-08
|
|
9
15
|
|
|
10
16
|
### Fixed
|
|
@@ -215,6 +221,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
215
221
|
- Options for `model`, `acceptKeys`, `maxChars`, `idleDelayMs`,
|
|
216
222
|
`recentMessages` and `system`.
|
|
217
223
|
|
|
224
|
+
[1.0.6]: https://github.com/ozandogrultan/opencode-ghost/compare/v1.0.5...v1.0.6
|
|
218
225
|
[1.0.5]: https://github.com/ozandogrultan/opencode-ghost/compare/v1.0.4...v1.0.5
|
|
219
226
|
[1.0.4]: https://github.com/ozandogrultan/opencode-ghost/compare/v1.0.3...v1.0.4
|
|
220
227
|
[1.0.3]: https://github.com/ozandogrultan/opencode-ghost/compare/v1.0.2...v1.0.3
|
package/README.md
CHANGED
|
@@ -17,11 +17,14 @@ a dimmed inline placeholder in the empty composer with
|
|
|
17
17
|
short transcript of the recent turns, and asks a model for one line that
|
|
18
18
|
sounds like you.
|
|
19
19
|
- **Inline empty-composer ghost.** The suggestion renders as the textarea's
|
|
20
|
-
dimmed placeholder
|
|
21
|
-
|
|
20
|
+
dimmed placeholder while the normal composer is empty in an idle session,
|
|
21
|
+
including when unfocused. With the composer focused, `Tab` or `→` inserts it
|
|
22
|
+
as editable text; Enter does not accept
|
|
22
23
|
or submit the ghost. Acceptance never replaces a draft or touches the clipboard.
|
|
23
|
-
- **
|
|
24
|
-
|
|
24
|
+
- **Hides as you type.** Typing and pasting abort pending generation and hide the
|
|
25
|
+
preview. Emptying the composer restores the same suggestion without another
|
|
26
|
+
API call; focus changes also reuse it. Navigation keys leave it intact.
|
|
27
|
+
Left on an empty eligible focused composer returns
|
|
25
28
|
home, even when suggestions are off (`backOnEmptyLeft`).
|
|
26
29
|
- **`/suggest` toggles it.** State is stored durably via the plugin's storage.
|
|
27
30
|
|
|
@@ -137,6 +140,9 @@ When enabling, a suggestion is generated immediately for the current session.
|
|
|
137
140
|
- Accepting uses the composer editor's `insertText` directly, without submitting.
|
|
138
141
|
- Typing, pasting, navigation, a new execution, disabling and unloading cancel
|
|
139
142
|
pending generation. Duplicate completion events do not generate again.
|
|
143
|
+
- Retains only one suggestion, bounded by `maxChars`, for the visible session.
|
|
144
|
+
Acceptance, a new turn, session changes, disabling, model changes and unloading
|
|
145
|
+
discard it.
|
|
140
146
|
|
|
141
147
|
## Caveats
|
|
142
148
|
|
package/package.json
CHANGED
package/src/lifecycle.ts
CHANGED
|
@@ -4,13 +4,13 @@ export function createLifecycle(delay: number, allowed: (sessionID: string) => b
|
|
|
4
4
|
let disposed = false
|
|
5
5
|
let warned = false
|
|
6
6
|
const completed = new Set<string>()
|
|
7
|
-
const
|
|
7
|
+
const interrupt = () => {
|
|
8
8
|
clearTimeout(timer)
|
|
9
9
|
timer = undefined
|
|
10
10
|
controller?.abort()
|
|
11
11
|
controller = undefined
|
|
12
|
-
clear()
|
|
13
12
|
}
|
|
13
|
+
const cancel = () => { interrupt(); clear() }
|
|
14
14
|
const run = async (sessionID: string) => {
|
|
15
15
|
cancel()
|
|
16
16
|
if (disposed || !allowed(sessionID)) return
|
|
@@ -23,6 +23,7 @@ export function createLifecycle(delay: number, allowed: (sessionID: string) => b
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
return {
|
|
26
|
+
interrupt,
|
|
26
27
|
cancel,
|
|
27
28
|
run,
|
|
28
29
|
succeeded(id: string, sessionID: string) {
|
package/src/tui.tsx
CHANGED
|
@@ -154,7 +154,7 @@ export default Plugin.define({
|
|
|
154
154
|
const key = keyName(event)
|
|
155
155
|
const current = suggestion()
|
|
156
156
|
return Boolean(current && inline.visible(getComposer(current.sessionID).editor, current.text) && acceptShortcuts(opts.acceptKeys, context.keymap.shortcuts).has(key) && canGenerate(current.sessionID) && isComposerEmpty(current.sessionID))
|
|
157
|
-
},
|
|
157
|
+
}, () => { lifecycle.interrupt(); inline.clear() })
|
|
158
158
|
|
|
159
159
|
const commandLayers = () => ghostKeymapLayers([
|
|
160
160
|
...opts.acceptKeys.map((key) => acceptCommand(key, () => {
|