mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-21 18:26:09 +00:00
feat(simulation): expose normalized terminal frames
This commit is contained in:
@@ -110,6 +110,25 @@ export function matches(harness: Pick<Harness, "screen">, text: string) {
|
||||
return harness.screen().includes(text)
|
||||
}
|
||||
|
||||
export const capture = Effect.fn("SimulationActions.capture")(function* (harness: Harness) {
|
||||
yield* Effect.tryPromise(() => harness.renderOnce())
|
||||
const buffer = harness.renderer.currentRenderBuffer
|
||||
return {
|
||||
cols: buffer.width,
|
||||
rows: buffer.height,
|
||||
cursor: [0, 0] as const,
|
||||
lines: buffer.getSpanLines().map((line) => ({
|
||||
spans: line.spans.map((span) => ({
|
||||
text: span.text,
|
||||
fg: span.fg.toInts(),
|
||||
bg: span.bg.toInts(),
|
||||
attributes: span.attributes,
|
||||
width: span.width,
|
||||
})),
|
||||
})),
|
||||
} satisfies SimulationProtocol.Frontend.CapturedFrame
|
||||
})
|
||||
|
||||
export const screenshot = Effect.fn("SimulationActions.screenshot")(function* (harness: Harness, name?: string) {
|
||||
const filename = name ?? `screenshot-${crypto.randomUUID()}`
|
||||
if (!filename || filename.includes("/") || filename.includes("\\") || extname(filename))
|
||||
|
||||
@@ -6,6 +6,8 @@ import { SimulationRenderer } from "./renderer"
|
||||
|
||||
function handle(harness: Harness, request: SimulationProtocol.Frontend.Request) {
|
||||
switch (request.method) {
|
||||
case "ui.capture":
|
||||
return SimulationActions.capture(harness)
|
||||
case "ui.screenshot":
|
||||
return SimulationActions.screenshot(harness, request.params?.name)
|
||||
case "ui.state":
|
||||
|
||||
@@ -95,6 +95,29 @@ export namespace Frontend {
|
||||
export const Screenshot = Schema.String
|
||||
export type Screenshot = Schema.Schema.Type<typeof Screenshot>
|
||||
|
||||
export const Color = Schema.Tuple([Schema.Number, Schema.Number, Schema.Number, Schema.Number])
|
||||
export type Color = Schema.Schema.Type<typeof Color>
|
||||
|
||||
export const CapturedFrame = Schema.Struct({
|
||||
cols: Schema.Number,
|
||||
rows: Schema.Number,
|
||||
cursor: Schema.Tuple([Schema.Number, Schema.Number]),
|
||||
lines: Schema.Array(
|
||||
Schema.Struct({
|
||||
spans: Schema.Array(
|
||||
Schema.Struct({
|
||||
text: Schema.String,
|
||||
fg: Color,
|
||||
bg: Color,
|
||||
attributes: Schema.Number,
|
||||
width: Schema.Number,
|
||||
}),
|
||||
),
|
||||
}),
|
||||
),
|
||||
})
|
||||
export interface CapturedFrame extends Schema.Schema.Type<typeof CapturedFrame> {}
|
||||
|
||||
export const RecordingFinish = Schema.String
|
||||
export type RecordingFinish = Schema.Schema.Type<typeof RecordingFinish>
|
||||
|
||||
@@ -142,6 +165,7 @@ export namespace Frontend {
|
||||
...JsonRpc.RequestFields,
|
||||
method: Schema.Literals(["ui.enter", "ui.state", "ui.recording.finish"]),
|
||||
}),
|
||||
Schema.Struct({ ...JsonRpc.RequestFields, method: Schema.Literal("ui.capture") }),
|
||||
])
|
||||
export type Request = Schema.Schema.Type<typeof Request>
|
||||
export const decodeRequest = Schema.decodeUnknownSync(Request)
|
||||
|
||||
@@ -25,6 +25,17 @@ test("scopes the frontend control server and reports malformed JSON", async () =
|
||||
result: { focused: { editor: false }, elements: [] },
|
||||
})
|
||||
|
||||
socket.send(JSON.stringify({ jsonrpc: "2.0", id: 2, method: "ui.capture" }))
|
||||
expect(yield* Queue.take(messages)).toMatchObject({
|
||||
id: 2,
|
||||
result: {
|
||||
cols: 100,
|
||||
rows: 40,
|
||||
cursor: [0, 0],
|
||||
lines: expect.any(Array),
|
||||
},
|
||||
})
|
||||
|
||||
socket.send("{")
|
||||
expect(yield* Queue.take(messages)).toMatchObject({
|
||||
id: null,
|
||||
|
||||
Reference in New Issue
Block a user