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
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ LDFLAGS = -s -w \
# tool via //go:embed
# - frontend/public/docs.md → served by Vite at /docs.md so the Docs page's
# "Copy as Markdown" button reads the same bytes
# - cli/commands/reference.md → embedded by the `orva docs` command via
# //go:embed so the slim CLI renders the same reference offline
# Single source of truth lives at docs/reference.md. Edit it, run
# `make docs-embed`, and both UI + MCP serve the new content.
# `make docs-embed`, and UI + MCP + CLI serve the new content.
docs-embed:
@cp docs/reference.md backend/internal/mcp/reference.md
@cp docs/reference.md frontend/public/docs.md
@cp docs/reference.md cli/commands/reference.md

# Copy adapter sources + bundled SDK into backend/cmd/orva/adapters/ so
# //go:embed has them at build time. Keeps backend/runtimes/ as the
Expand Down
46 changes: 45 additions & 1 deletion cli/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@ cli/
├── output.go # shared output framework (stdout/stderr split, table|json, color, confirm)
├── activity.go # `orva activity`
├── channels.go # `orva channels …`
├── chat.go # `orva chat` (interactive AI REPL + one-shot -p, SSE)
├── completion.go # `orva completion {bash|zsh|fish|powershell}`
├── completions.go # dynamic shell completions (fn names, runtimes, models)
├── cron.go # `orva cron …`
├── deploy.go # `orva deploy <path> [--watch]`
├── deployments.go # `orva deployments list/get/logs`
├── diff.go # `orva diff <function>` (unified diff between deployments)
├── dns.go # `orva dns get/set`
├── docs.go # `orva docs` (renders embedded docs/reference.md)
├── firewall.go # `orva firewall list/add/enable/disable/delete/resolve`
├── fixtures.go # `orva fixtures list/get/save/delete/test`
├── functions.go # `orva functions …`
Expand All @@ -38,7 +41,10 @@ cli/
├── traces.go # `orva traces list/get/baseline`
├── upgrade.go # `orva upgrade` (self-update via go-selfupdate)
├── webhooks.go # `orva webhooks …`
└── commands_test.go # command-tree + flag-presence tests
├── commands_test.go # command-tree + flag-presence tests
├── chat_test.go # chat SSE drive + approval-flow tests (httptest)
├── reference.md # GENERATED — embedded by docs.go (make docs-embed)
└── theme/ # lipgloss color palette (theme.New(enabled))
```

The HTTP client and `~/.orva/config.yaml` loader live at `internal/client/`
Expand All @@ -59,6 +65,44 @@ non-TTY without it). New commands should render through this layer
rather than calling `fmt.Print*` directly, so the streams and formats
stay consistent.

## Color & theming (`theme/`)

Color lives in one place: `cli/commands/theme` wraps `charmbracelet/lipgloss`
(pure-Go, auto-degrades truecolor → 256 → 16 and adapts to light/dark
backgrounds). `theme.New(enabled)` returns a `*Styles`; when `enabled` is false
every style is a no-op pass-through that emits no ANSI. Commands get theirs via
`styles(cmd)` in `output.go`, which gates on the same `colorEnabled(cmd)` chain
(`--no-color` → `NO_COLOR` → JSON mode → non-TTY) — so color control stays a
single decision. `okf()` and the `diff` colorizer render through the theme.
**Don't** push ANSI into `tabwriter` cells: the escape bytes break column
alignment, so table bodies stay uncolored by design.

## AI chat (`orva chat`)

`chat.go` is the terminal front end to the AI assistant — the same agent the
dashboard drives, over `POST /api/v1/ai/chat` (SSE) with the CLI's existing API
key (the AI endpoints accept it; they need `admin`). Interactive REPL by
default, or one-shot with `-p` (supports `@file`/`@-`). It reuses `consumeSSE`
for the wire format and `client.Send(Request{..., Ctx, NoTimeout})` for a
cancellable streaming POST (Ctrl-C aborts the turn, not the process).

- **Rendering:** assistant text streams raw to stdout live; on a TTY (not
`--raw`/`ORVA_CHAT_NO_GLAMOUR`) the message is re-rendered with `glamour` by
erasing the streamed block and reprinting — guarded by terminal-size checks,
degrades to raw if anything is uncertain. Thinking + tool status go to stderr;
stdout stays clean for piping.
- **Approvals:** the CLI never sets the policy; it reacts to `requires_approval`
/`awaiting_approval`. Write tools prompt `[y/N]`; non-interactive without
`--auto-approve` fails closed. The global `-y` is intentionally **not** honored
for AI tool approval.
- **Selection:** `--provider/--model/--thinking` are per-session overrides;
`/model` and `/thinking` persist via `PUT /api/v1/ai/selection`.

Markdown rendering uses `glamour` (pulls `chroma`), which adds ~8 MB to the slim
binary (~12 MB → ~20 MB). The same `docs/reference.md` is embedded for
`orva docs` via `//go:embed reference.md`; `make docs-embed` keeps that copy in
sync alongside the MCP and frontend copies.

## Build commands

```bash
Expand Down
Loading
Loading