Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .changeset/restore-design-tui.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
"@reddb-io/redcode": patch
"@reddb-io/redcode": minor
---

Restore Design as the cyan third mode in the fullscreen TUI, alongside Build and Plan. Keep prototyping, browser feedback, image assets, SVG-to-GIF exports and approved Plan handoffs attached to the same conversation. Reopen pre-0.22 prototypes without overwriting their sources, and retain the new Design revision and rendering services.
Restore Design as the cyan third mode in the fullscreen TUI, alongside Build and Plan. Keep prototyping, browser feedback, image assets, SVG-to-GIF exports and approved Plan handoffs attached to the same conversation. Reopen pre-0.22 prototypes without overwriting their sources, and retain the new Design revision and rendering services. Queued browser feedback respects session interruption and requires an explicit retry to resume.
8 changes: 4 additions & 4 deletions packages/redcode/src/design/feedback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { EventV2Bridge } from "@/event-v2-bridge"
import { SessionEvent } from "@reddb-io/redcode-core/session/event"
export * as DesignFeedback from "./feedback"

import { Context, Deferred, Effect, Exit, Layer, Schedule, Scope, Semaphore, Schema, Option } from "effect"
import { Context, Deferred, Effect, Exit, Layer, Schedule, Scope, Semaphore, Schema } from "effect"
import { eq } from "drizzle-orm"
import { Design } from "@reddb-io/redcode-schema/design"
import { DesignStore } from "@reddb-io/redcode-core/design/store"
Expand All @@ -27,9 +27,9 @@ const make = Effect.gen(function* () {
const off = yield* events.listen((event) =>
Effect.sync(() => {
if (event.type !== SessionEvent.Turn.Ended.type || event.location?.directory !== instance.directory) return
const data = Schema.decodeUnknownOption(SessionEvent.Turn.Ended.data)(event.data)
if (Option.isNone(data) || data.value.finished) return
const queue = queues.get(data.value.sessionID)
// Live events already contain decoded DateTime values. Validate their type, not the wire representation.
if (!Schema.is(Schema.toType(SessionEvent.Turn.Ended.data))(event.data) || event.data.finished) return
const queue = queues.get(event.data.sessionID)
if (queue) queue.interruption++
}),
)
Expand Down
27 changes: 25 additions & 2 deletions packages/redcode/test/design/tui-studio.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SessionMessage } from "@reddb-io/redcode-schema/session-message"
import { DesignFeedback } from "../../src/design/feedback"
import { SessionStatus } from "../../src/session/status"
import { SessionPrompt } from "../../src/session/prompt"
import { EventV2Bridge } from "../../src/event-v2-bridge"
import { SessionEvent } from "@reddb-io/redcode-core/session/event"
import { DesignLegacy } from "../../src/design/legacy"
Expand All @@ -26,6 +27,7 @@ const it = testEffect(
DesignStudio.node,
DesignFeedback.node,
SessionStatus.node,
SessionPrompt.node,
EventV2Bridge.node,
Agent.node,
Session.node,
Expand Down Expand Up @@ -179,6 +181,13 @@ it.instance("queued browser feedback does not restart an interrupted TUI session
const status = yield* SessionStatus.Service
const events = yield* EventV2Bridge.Service
const session = yield* sessions.create({ agent: "design" })
const prompt = yield* SessionPrompt.Service
const initial = yield* prompt.prompt({
sessionID: session.id,
agent: "design",
noReply: true,
parts: [{ type: "text", text: "Create a settings prototype" }],
})
const document = yield* studio.use(
Effect.gen(function* () {
const store = yield* DesignStore.Service
Expand Down Expand Up @@ -210,8 +219,22 @@ it.instance("queued browser feedback does not restart an interrupted TUI session
finished: false,
})
yield* status.set(session.id, { type: "idle" })
yield* Effect.sleep("300 millis")
expect(yield* sessions.messages({ sessionID: session.id })).toHaveLength(0)
yield* Effect.sleep("2 seconds")
expect((yield* sessions.messages({ sessionID: session.id })).map((message) => message.info.id)).toEqual([
initial.info.id,
])
expect(yield* status.get(session.id)).toEqual({ type: "idle" })
}),
{
config: {
model: "fixture/fixture",
provider: {
fixture: {
npm: "@ai-sdk/openai-compatible",
models: { fixture: { name: "Fixture", limit: { context: 100000, output: 4096 } } },
options: { apiKey: "fixture", baseURL: "http://127.0.0.1:1/v1" },
},
},
},
},
)
Loading