feat: add Deno launcher, root tasks, and README - #7
Merged
Conversation
Adds the orchestration layer and user-facing docs: - launcher.ts: starts the Python backend and Fresh frontend, streams their output, handles graceful shutdown - deno.json: root tasks (start, dev:web, build:web) - README.md: quick-start guide with vLLM requirements, architecture diagram, and feature list Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Greptile SummaryAdded orchestration layer for Librarian: a Deno-based launcher that manages the Python backend and Fresh frontend as child processes with log streaming and graceful shutdown on SIGINT/SIGTERM.
Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant Launcher as launcher.ts
participant Env as env.schema.json
participant Config as librarian.config.json
participant Frontend as Frontend (Vite)
participant Backend as Backend (uvicorn)
User->>Launcher: deno task start
Launcher->>Env: loadEnvSchema()
Env-->>Launcher: required env vars
Launcher->>Launcher: validateEnv()
Launcher->>Config: loadConfig()
Config-->>Launcher: ports (or defaults)
Launcher->>Launcher: Check frontend port
Launcher->>Frontend: startFrontend(8080, 8001)
Frontend-->>Launcher: stdout/stderr streams
Launcher->>Launcher: streamOutput("frontend")
Launcher->>Launcher: waitForPort(8080)
Launcher->>Launcher: Check backend port
Launcher->>Backend: startBackend(8001)
Backend-->>Launcher: stdout/stderr streams
Launcher->>Launcher: streamOutput("backend")
Launcher->>Backend: Poll /openapi.json
Backend-->>Launcher: Health check OK
User->>Launcher: Ctrl+C (SIGINT)
Launcher->>Frontend: SIGTERM
Launcher->>Backend: SIGTERM
Launcher->>Launcher: Wait 5s or force SIGKILL
Launcher->>User: Exit
Last reviewed commit: 45e7a09 |
Comment on lines
+143
to
+156
| function streamOutput(name: string, stream: ReadableStream<Uint8Array>) { | ||
| const reader = stream.getReader(); | ||
| const decoder = new TextDecoder(); | ||
|
|
||
| (async () => { | ||
| while (true) { | ||
| const { done, value } = await reader.read(); | ||
| if (done) break; | ||
| const text = decoder.decode(value); | ||
| for (const line of text.split("\n").filter((l) => l.trim())) { | ||
| console.log(`[${name}] ${line}`); | ||
| } | ||
| } | ||
| })(); |
There was a problem hiding this comment.
unhandled promise rejection if reader errors
Suggested change
| function streamOutput(name: string, stream: ReadableStream<Uint8Array>) { | |
| const reader = stream.getReader(); | |
| const decoder = new TextDecoder(); | |
| (async () => { | |
| while (true) { | |
| const { done, value } = await reader.read(); | |
| if (done) break; | |
| const text = decoder.decode(value); | |
| for (const line of text.split("\n").filter((l) => l.trim())) { | |
| console.log(`[${name}] ${line}`); | |
| } | |
| } | |
| })(); | |
| function streamOutput(name: string, stream: ReadableStream<Uint8Array>) { | |
| const reader = stream.getReader(); | |
| const decoder = new TextDecoder(); | |
| (async () => { | |
| try { | |
| while (true) { | |
| const { done, value } = await reader.read(); | |
| if (done) break; | |
| const text = decoder.decode(value); | |
| for (const line of text.split("\n").filter((l) => l.trim())) { | |
| console.log(`[${name}] ${line}`); | |
| } | |
| } | |
| } catch (error) { | |
| // Reader errors are non-fatal (process may have exited) | |
| } | |
| })(); | |
| } |
| deno task start | ||
| ``` | ||
|
|
||
| Librarian starts the backend and frontend, then opens your browser. |
There was a problem hiding this comment.
launcher doesn't open browser — line 79 in launcher.ts only logs "Press Ctrl+C to stop"
- README: fix incorrect claim that launcher opens the browser - launcher: wrap streamOutput reader loop in try/catch to handle non-fatal reader errors when a process exits Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove manual uv sync step (uv run handles it automatically) and consolidate to a two-line clone-and-run. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
launcher.ts— orchestrates the Python backend and Fresh frontend: starts both processes, streams their logs, and handles graceful shutdown on Ctrl+C or unexpected exitdeno.json— root-level tasks (deno task start,dev:web,build:web)README.md— user-facing quick-start guide: feature list, architecture diagram, vLLM setup instructions (>= 0.13, no reasoning parser, Hermes tool-call parser required), env vars, and port configTest plan
deno task startlaunches both services and streams[frontend]/[backend]logs🤖 Generated with Claude Code