Skip to content

Commit 1202f2c

Browse files
committed
feat(queue): support compact command
1 parent 3178ce4 commit 1202f2c

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

‎README.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ do this next /queue front
3333
/queue front /review
3434
/review /queue front
3535
36+
/queue /compact
37+
/queue front /compact
38+
3639
/queue !ls
3740
/queue front !pwd
3841
@@ -57,6 +60,8 @@ do this next /queue front
5760
| `/review /queue` | Queue a slash command using trailing syntax. |
5861
| `/queue front /review` | Queue a slash command before existing queued entries. |
5962
| `/review /queue front` | Queue a slash command before existing queued entries using trailing syntax. |
63+
| `/queue /compact` | Queue OpenCode's built-in TUI `/compact` command. |
64+
| `/queue front /compact` | Queue OpenCode's built-in TUI `/compact` command before existing queued entries. |
6065
| `/queue !ls` | Queue an OpenCode shell block. |
6166
| `/queue front !ls` | Queue an OpenCode shell block before existing queued entries. |
6267
| `/queue` | Show the current queue. |
@@ -87,6 +92,7 @@ When the session is idle:
8792
- `message /queue` sends `message` immediately.
8893
- `/queue /review` runs `/review` immediately.
8994
- `/review /queue` runs `/review` immediately.
95+
- `/queue /compact` runs OpenCode's built-in TUI `/compact` command immediately.
9096
- `/queue !ls` runs `ls` immediately as an OpenCode shell block.
9197
- `/queue` and `/queue list` show the current queue.
9298
- `/queue stop` pauses automatic replay, and `/queue start` resumes it.

‎index.ts‎

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ type QueueInput = { body: string; front: boolean }
2020
type Item =
2121
| { kind: "prompt"; info: Info; label: string; body: string; parts: InputPart[] }
2222
| { kind: "command"; info: Info; source: string; cmd: string; args: string; files: FilePartInput[] }
23+
| { kind: "compact"; info: Info; source: string }
2324
| { kind: "shell"; info: Info; source: string; shell: string }
2425

2526
type EntryOp =
2627
| { kind: "prompt"; label: string; body: string }
2728
| { kind: "command"; source: string; cmd: string; args: string }
29+
| { kind: "compact"; source: string }
2830
| { kind: "shell"; source: string; shell: string }
2931

3032
type Activity = { kind: "idle" } | { kind: "busy" } | { kind: "sending"; idle: boolean }
@@ -85,7 +87,16 @@ const parse = (input: QueueInput, files = 0): Op => {
8587
}
8688

8789
const match = text.match(CMD)
88-
if (match) return { kind: "command", source: text, cmd: match[1], args: match[2] ?? "", front }
90+
if (match) {
91+
const cmd = match[1]
92+
const args = match[2] ?? ""
93+
if (cmd === "compact") {
94+
if (args.trim()) return { kind: "invalid", message: "Queue compact does not accept arguments" }
95+
if (files) return { kind: "invalid", message: "Queue compact does not support attachments" }
96+
return { kind: "compact", source: text, front }
97+
}
98+
return { kind: "command", source: text, cmd, args, front }
99+
}
89100
return { kind: "prompt", label: brief(input.body, files), body: input.body, front }
90101
}
91102

@@ -206,9 +217,18 @@ export const QueuePlugin: Plugin = async ({ client }) => {
206217

207218
const prompt = (sid: string, info: Info, parts: InputPart[], noReply?: boolean) => client.session.prompt({ path: { id: sid }, body: { ...opts(info), noReply, parts } as any })
208219
const shell = (sid: string, command: string, info: Run) => client.session.shell({ path: { id: sid }, body: { agent: info.agent, model: info.model, command } })
220+
// TUI command events target the focused session; queued replay must target the original session.
221+
const compact = (sid: string, info: Info) =>
222+
client.session.summarize({
223+
path: { id: sid },
224+
body: { providerID: info.model.providerID, modelID: info.model.modelID },
225+
throwOnError: true,
226+
})
227+
const tuiCommand = (command: string) => client.tui.executeCommand({ body: { command }, throwOnError: true })
209228

210229
const replay = async (sid: string, item: Item) => {
211230
if (item.kind === "shell") return shell(sid, item.shell, item.info)
231+
if (item.kind === "compact") return compact(sid, item.info)
212232

213233
if (item.kind === "command") {
214234
await client.session.command({
@@ -390,6 +410,11 @@ export const QueuePlugin: Plugin = async ({ client }) => {
390410
throw new Error(HANDLED)
391411
}
392412

413+
if (op.kind === "compact") {
414+
await tuiCommand("session_compact")
415+
throw new Error(HANDLED)
416+
}
417+
393418
if (op.kind === "command") {
394419
await client.session.command({ path: { id: sid }, body: { command: op.cmd, arguments: op.args, parts } as any })
395420
throw new Error(HANDLED)
@@ -412,6 +437,7 @@ export const QueuePlugin: Plugin = async ({ client }) => {
412437
const current = state(sid)
413438
const parts = files(output.parts)
414439
const op = parse(request, parts.length)
440+
const meta = input as Meta
415441

416442
if (control(op)) {
417443
hide(output.message.id, text)
@@ -427,6 +453,11 @@ export const QueuePlugin: Plugin = async ({ client }) => {
427453

428454
if (current.activity.kind === "idle" && !current.stopped) {
429455
if (op.kind === "command") return
456+
if (op.kind === "compact") {
457+
hide(output.message.id, text)
458+
await compact(sid, { agent: output.message.agent, model: output.message.model, variant: meta.variant, controls: meta.controls, fast: meta.fast })
459+
return
460+
}
430461
if (op.kind === "shell") {
431462
hide(output.message.id, text)
432463
await shell(sid, op.shell, { agent: output.message.agent, model: output.message.model })
@@ -436,13 +467,13 @@ export const QueuePlugin: Plugin = async ({ client }) => {
436467
return
437468
}
438469

439-
const meta = input as Meta
440470
const info = { agent: output.message.agent, model: { ...output.message.model }, variant: meta.variant, controls: meta.controls, fast: meta.fast }
441471
const prior = await latest(sid)
442472
if (prior) Object.assign(output.message, opts(prior))
443473
else console.warn("QueuePlugin could not neutralize queued placeholder metadata because the session has no previous message context")
444474
let item: Item
445475
if (op.kind === "shell") item = { kind: "shell", info, source: op.source, shell: op.shell }
476+
else if (op.kind === "compact") item = { kind: "compact", info, source: op.source }
446477
else if (op.kind === "command") item = { kind: "command", info, source: op.source, cmd: op.cmd, args: op.args, files: parts }
447478
else {
448479
item = {

0 commit comments

Comments
 (0)