opencode-ghost 0.5.1 → 1.0.0
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 +13 -2
- package/README.md +108 -96
- package/package.json +7 -8
- package/src/composer.ts +68 -0
- package/src/lifecycle.ts +41 -0
- package/src/options.ts +30 -28
- package/src/placeholder.ts +46 -0
- package/src/stateless.ts +22 -187
- package/src/text.ts +47 -51
- package/src/transcript.ts +44 -0
- package/src/tui.tsx +217 -914
- package/src/builtins.ts +0 -28
- package/src/completion.ts +0 -78
package/src/builtins.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Builtin TUI slash commands. The plugin API does not expose the TUI's own
|
|
3
|
-
* command palette, so the completable subset we observed in the shipped binary
|
|
4
|
-
* is curated here. Names are fixed; descriptions are ours and only used for the
|
|
5
|
-
* completion display.
|
|
6
|
-
*/
|
|
7
|
-
export type BuiltinCommand = {
|
|
8
|
-
name: string
|
|
9
|
-
description: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const BUILTIN_COMMANDS: BuiltinCommand[] = [
|
|
13
|
-
{ name: "new", description: "New session" },
|
|
14
|
-
{ name: "agent", description: "Cycle agent" },
|
|
15
|
-
{ name: "model", description: "Choose model" },
|
|
16
|
-
{ name: "mcp", description: "Toggle MCP servers" },
|
|
17
|
-
{ name: "open", description: "Command palette" },
|
|
18
|
-
{ name: "share", description: "Share session" },
|
|
19
|
-
{ name: "unshare", description: "Unshare session" },
|
|
20
|
-
{ name: "compact", description: "Compact session" },
|
|
21
|
-
{ name: "export", description: "Export session" },
|
|
22
|
-
{ name: "fork", description: "Fork session" },
|
|
23
|
-
{ name: "undo", description: "Undo messages" },
|
|
24
|
-
{ name: "redo", description: "Redo messages" },
|
|
25
|
-
{ name: "terminal", description: "Toggle terminal" },
|
|
26
|
-
{ name: "workspace", description: "Workspace controls" },
|
|
27
|
-
{ name: "suggest", description: "Toggle prompt suggestions" },
|
|
28
|
-
]
|
package/src/completion.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure slash-command completion: given the current prompt input, the pool of
|
|
3
|
-
* known command names (configured commands, skills, and builtins) and optional
|
|
4
|
-
* per-command argument hints, decide what ghost text to render and what Tab
|
|
5
|
-
* should insert.
|
|
6
|
-
*/
|
|
7
|
-
export type CommandPool = {
|
|
8
|
-
readonly name: string
|
|
9
|
-
readonly description?: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type Completion = {
|
|
13
|
-
/** Dimmed text rendered after the input, e.g. `warm` for `/keep`+`warm`. */
|
|
14
|
-
ghost?: string
|
|
15
|
-
/** What Tab places into the input when accepting. */
|
|
16
|
-
insert?: string
|
|
17
|
-
/** Argument options shown as `[a | b]`, filtered by the word in progress. */
|
|
18
|
-
args?: string[]
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Parse leading `/name args...` from the input; `args` is "" until a space exists. */
|
|
22
|
-
function parseSlash(input: string): { name: string; args: string; nameComplete: boolean } | undefined {
|
|
23
|
-
if (!input.startsWith("/")) return undefined
|
|
24
|
-
const line = input.split("\n")[0]
|
|
25
|
-
const space = line.indexOf(" ")
|
|
26
|
-
if (space === -1) return { name: line.slice(1), args: "", nameComplete: false }
|
|
27
|
-
return { name: line.slice(1, space), args: line.slice(space + 1), nameComplete: true }
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Options that still match the word being typed, excluding an exact hit. */
|
|
31
|
-
function matchOptions(typed: string, options: readonly string[]): string[] | undefined {
|
|
32
|
-
const lower = typed.toLowerCase()
|
|
33
|
-
const matches = options.filter(
|
|
34
|
-
(option) => option.toLowerCase() !== lower && option.toLowerCase().startsWith(lower),
|
|
35
|
-
)
|
|
36
|
-
return matches.length > 0 ? matches : undefined
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function completeCommand(
|
|
40
|
-
input: string,
|
|
41
|
-
pool: readonly CommandPool[],
|
|
42
|
-
argHints: Readonly<Record<string, readonly string[]>> = {},
|
|
43
|
-
): Completion | undefined {
|
|
44
|
-
const parsed = parseSlash(input)
|
|
45
|
-
if (!parsed) return undefined
|
|
46
|
-
const lower = parsed.name.toLowerCase()
|
|
47
|
-
const exact = pool.find((command) => command.name.toLowerCase() === lower)
|
|
48
|
-
|
|
49
|
-
// Still typing the command name (no space yet).
|
|
50
|
-
if (!parsed.nameComplete) {
|
|
51
|
-
if (exact) {
|
|
52
|
-
const hints = argHints[lower]
|
|
53
|
-
return {
|
|
54
|
-
args: hints ? [...hints] : undefined,
|
|
55
|
-
insert: `/${exact.name} `,
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
const matches = pool.filter((command) => command.name.toLowerCase().startsWith(lower))
|
|
59
|
-
if (matches.length === 0) return undefined
|
|
60
|
-
const next = matches[0]
|
|
61
|
-
return { ghost: next.name.slice(parsed.name.length), insert: `/${next.name} ` }
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// `/name args...`: complete the in-progress argument word against hints.
|
|
65
|
-
const hintList = argHints[lower]
|
|
66
|
-
if (!hintList) return undefined
|
|
67
|
-
const matches = matchOptions(parsed.args, hintList)
|
|
68
|
-
if (!matches) return undefined
|
|
69
|
-
const ghost = matches[0].slice(parsed.args.length)
|
|
70
|
-
const result: Completion = {
|
|
71
|
-
ghost,
|
|
72
|
-
insert: `/${parsed.name} ${parsed.args + ghost} `,
|
|
73
|
-
}
|
|
74
|
-
// Enumerate the accepted options only while the argument is still empty;
|
|
75
|
-
// once part of the word is typed, ghost the rest of the matching option.
|
|
76
|
-
if (parsed.args === "") result.args = matches
|
|
77
|
-
return result
|
|
78
|
-
}
|