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
110 changes: 110 additions & 0 deletions todos/01-plugin-inspect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Plugin 01 — RPC & State self-inspector

**Package:** `@devframes/plugin-inspect` · **Dir:** `plugins/inspect/`
**Inspiration:** port of the RPC + shared-state inspector panels from
`vitejs/devtools`.
**SPA stack (Axis B):** Vue + Vite (direct port).
**Diagnostics band:** `DP_INSPECT_00xx`.

## Why first

This is the scaffolding plugin. It is the lowest-risk port, it self-validates the
core wire (RPC registry, shared-state, dump, connection meta, agent surface), and
once it exists it becomes the debugger we use while building every other plugin.
Building it establishes the package/tsdown/alias/turbo scaffolding the rest copy.

## What it does

A devframe that introspects *its own connection* (and, when mounted in a hub, the
hub's): list every registered RPC function with metadata (name, `type`,
`jsonSerializable`, `snapshot`, arg schema), let the user invoke `query` functions
with arguments and inspect results, watch every shared-state key live, and browse
the agent-exposed surface. Essentially the devframe equivalent of the vitejs
DevTools "RPC" and "State" tabs.

## Dogfooding intent

Primary surface: **RPC introspection + shared-state + RPC dump + `connectionMeta`
+ agent host**. This is the most self-referential plugin — it consumes the exact
APIs every other plugin produces, so it is the fastest way to discover whether:

- the RPC registry exposes enough metadata to render a useful inspector (names,
types, valibot arg schemas, `jsonSerializable` flags from `ConnectionMeta`);
- shared-state subscription/broadcast semantics are observable from the client;
- the static `rpc/dump` output round-trips for the `build`/`spa` modes;
- the agent surface (`ctx.agent`, the `BUILTIN_AGENT_RPC`) is browsable.

Expected gaps: missing introspection getters (may need a built-in
`devframe:list-functions` style meta RPC in core), dump fidelity for non-JSON values,
and how a devframe inspects a connection it is *also* part of.

## Host integrations (Axis A)

- `.` — `createInspectDevframe()` factory + default `DevframeDefinition`.
- `/cli` — `npx @devframes/plugin-inspect` opens the inspector against a target.
- `/vite` — mount into a Vite host to inspect that host's devframe connection.
- `/client` — Vue mount helpers + any dock `custom-render` modules.

## Package layout

```
plugins/inspect/
src/
index.ts # `.` default DevframeDefinition + factory
node/index.ts # `/node` setup(ctx): register introspection RPCs + docks
client/index.ts # `/client` Vue app mount + custom-render dock
cli.ts # `/cli`
vite.ts # `/vite`
rpc/
index.ts # serverFunctions tuple + DevframeRpcServerFunctions augment
functions/
list-functions.ts # devframes-plugin-inspect:list-functions (query, snapshot)
invoke.ts # devframes-plugin-inspect:invoke (action) — gated to query fns
list-state-keys.ts # devframes-plugin-inspect:list-state-keys (query)
describe-agent.ts # devframes-plugin-inspect:describe-agent (query, snapshot)
spa/ # Vue + Vite UI
bin.mjs
test/
```

## Node side

- RPC (namespaced `devframes-plugin-inspect:*`):
- `devframes-plugin-inspect:list-functions` — `query`, `snapshot: true`, `jsonSerializable: true`:
returns the registry with metadata. May need a core hook to read the registry;
if absent, that is a tracked gap to add to `devframe` core.
- `devframes-plugin-inspect:invoke` — `action`: invoke a named `query` function with validated args;
refuse `action`/mutating functions for safety.
- `devframes-plugin-inspect:list-state-keys` — enumerate shared-state keys + current snapshots.
- `devframes-plugin-inspect:describe-agent` — surface `ctx.agent` tools/resources.
- Docks: a single `iframe` (or `custom-render`) dock `devframes-plugin-inspect:inspector` titled
"RPC & State", icon e.g. `ph:plugs-duotone`.
- Shared state observed (read-only): all keys; no new keys written except a small
`devframes-plugin-inspect:inspector:ui` for persisted panel UI prefs (serializable).

## Client side

- Vue SPA: three views — Functions (list + invoke), State (live key watcher with
diff), Agent (tools/resources tree). Connects via `connectDevframe()`; derives
base from `document.baseURI`; handles both `websocket` and `static` backends
(degrade invoke to read-only when `backend === 'static'`).

## Milestones

1. Scaffold package + tsdown three-config + alias/turbo/workspace wiring (this is
the template all others copy).
2. `devframes-plugin-inspect:list-functions` + Functions view (read-only).
3. `devframes-plugin-inspect:invoke` for `query` functions + result rendering.
4. State view with live subscription + diff.
5. Agent view; `static`/`spa` degradation; tsnapi snapshot + e2e.

## Open questions / risks

- Does core expose (or should it expose) a registry-introspection API? If not,
decide whether to add a built-in meta RPC to `devframe` core vs. keep it in the
plugin. **This is likely the first real framework change the effort forces.**
- How much of the `vitejs/devtools` Vue code ports cleanly vs. needs a rewrite
against devframe's client (`connectDevframe`, `rpc.sharedState`) rather than
Vite DevTools' kit client.
- Safety model for `devframes-plugin-inspect:invoke` (which function types are invokable; argument
validation surface).
102 changes: 102 additions & 0 deletions todos/02-plugin-terminals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Plugin 02 — Terminals

**Package:** `@devframes/plugin-terminals` · **Dir:** `plugins/terminals/`
**Inspiration:** replace Vite DevTools' built-in terminal panel with a portable,
hub-native one.
**SPA stack (Axis B):** Vanilla TS + Vite (+ `@xterm/xterm`).
**Diagnostics band:** `DP_TERMINALS_00xx`.

## What it does

A terminal panel: list registered terminal sessions, stream their live output,
spawn new child-process terminals (configurable allowed commands), and
terminate/restart them. The host already provides most of this — the hub
`terminals` host (`packages/hub/src/node/host-terminals.ts`) exposes `register`,
`update`, and `startChildProcess` (via `tinyexec`) and mirrors output into the
`devframe:terminals` streaming channel with `devframe:terminals:updated`
broadcasts. This plugin is the **reference UI + a thin spawn/control RPC** on top
of that subsystem.

## Dogfooding intent

Primary surface: **hub `terminals` host + `startChildProcess` + RPC streaming +
replay**. This is the first heavy consumer of streaming, so it will stress:

- the `devframe:terminals` streaming channel (backpressure, replay window for
late-joining clients, ordering across stdout/stderr);
- session lifecycle (`terminate()`/`restart()`/`getChildProcess()`) and the
`terminal:session:updated` events;
- whether the existing host API is enough to drive a full UI, or needs additions
(resize/PTY, input/write-to-stdin, exit codes, env/cwd per session).

Expected gaps: interactive input (the current host streams output; a real
terminal needs stdin + PTY/resize), and replay semantics for reconnects.

## Host integrations (Axis A)

- `.` — `createTerminalsDevframe(options)` (allowed commands, default cwd) +
default definition.
- `/cli` — standalone terminal panel bound to the launching shell's cwd.
- `/vite` — mount into a Vite host (the literal "replace Vite DevTools terminal"
use case).
- `/client` — xterm mount + dock `custom-render` module.

## Package layout

```
plugins/terminals/
src/
index.ts
node/index.ts # setup(ctx): wire terminals host, register control RPCs + dock
client/index.ts # xterm.js renderer, attaches to devframe:terminals stream
cli.ts
vite.ts
rpc/
index.ts
functions/
spawn.ts # devframes-plugin-terminals:spawn (action) → ctx.terminals.startChildProcess
terminate.ts # devframes-plugin-terminals:terminate (action)
restart.ts # devframes-plugin-terminals:restart (action)
write.ts # devframes-plugin-terminals:write (action) — stdin, IF host gains support
list.ts # devframes-plugin-terminals:list (query)
spa/
bin.mjs
test/
```

## Node side

- Uses `ctx.terminals` directly; control RPCs are thin wrappers that call into the
host and return session descriptors.
- `devframes-plugin-terminals:spawn` validates the requested command against an allow-list passed
to `createTerminalsDevframe` (security: never spawn arbitrary commands from the
client without opt-in). Diagnostics `DP_TERMINALS_00xx` for disallowed command / unknown
session / spawn failure.
- Subscribes the UI to the `devframe:terminals` streaming channel and
`devframe:terminals:updated` broadcast.

## Client side

- Vanilla TS + xterm.js. One xterm instance per session, fed from the streaming
channel reader; tabs/list driven by `devframes-plugin-terminals:list` + the updated broadcast.
Toolbar: spawn (from allow-list), terminate, restart, clear.

## Milestones

1. Scaffold (copy from #1). Dock + `devframes-plugin-terminals:list` + render existing sessions'
buffered output.
2. Live streaming via `devframe:terminals` channel into xterm; reconnect/replay.
3. `devframes-plugin-terminals:spawn` / `terminate` / `restart` with allow-list.
4. (If host extended) stdin `devframes-plugin-terminals:write` + resize/PTY.
5. tsnapi snapshot + Playwright e2e (spawn → output → terminate).

## Open questions / risks

- **Interactive input / PTY.** The hub host today is output-streaming. A genuine
replacement for the Vite DevTools terminal needs stdin and resize. Decide:
extend `@devframes/hub` `terminals` host (preferred, benefits all consumers) vs.
plugin-local PTY. This is the main framework-change candidate from this plugin.
- Replay window sizing for the streaming channel on reconnect.
- Security model for `spawn` (allow-list shape, default-deny).
- Overlap with code-server (#7), which also runs long-lived processes — keep the
spawn/stream primitives reusable.
102 changes: 102 additions & 0 deletions todos/03-plugin-git-dashboard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Plugin 03 — Git Dashboard

**Package:** `@devframes/plugin-git` · **Dir:** `plugins/git/`
**Inspiration:** GitLens — repository insight surfaced inline.
**SPA stack (Axis B):** Vue + Vite (reuses inspector UI primitives), vanilla
fallback acceptable.
**Diagnostics band:** `DP_GIT_00xx`.

## What it does

A repository dashboard for the workspace: current branch + status (staged/
unstaged/untracked), recent commit log with author/date/message, per-file blame,
branch list, and a diff viewer. Read-only first; optional write actions
(stage/commit/checkout) behind explicit opt-in. The first "real product" tool, so
it exercises data-heavy RPC end to end.

## Dogfooding intent

Primary surface: **RPC `query`/`snapshot` + shared-state + long-lived file
watching + `json-render` + commands/docks**. Stresses:

- larger / structured RPC payloads (commit lists, diffs) and whether `snapshot:
true` + the dump path handle them for `build`/`spa` modes;
- a long-lived watcher (repo HEAD / index changes) pushing shared-state updates,
and the debounce behavior `createHubContext` applies in `dev` mode;
- `json-render` driven docks (`ctx.createJsonRenderer`) as an alternative to a
full custom SPA for some panels;
- command-palette entries (`devframes-plugin-git:checkout`, `devframes-plugin-git:fetch`) via `ctx.commands`.

Expected gaps: efficient diffing of large repos over RPC, incremental updates vs.
full snapshots, and error diagnostics for non-repo / detached-HEAD states.

## Host integrations (Axis A)

- `.` — `createGitDevframe(options)` (repo root override, write-enabled flag).
- `/cli` — `npx @devframes/plugin-git` → standalone dashboard for cwd repo.
- `/vite`, `/nuxt` — mount into a host dev server (in-IDE-like sidebar).
- `/client` — Vue app + dock renderers.

## Package layout

```
plugins/git/
src/
index.ts
node/index.ts
client/index.ts
cli.ts
vite.ts
nuxt.ts # optional
rpc/
index.ts
functions/
status.ts # devframes-plugin-git:status (query, snapshot)
log.ts # devframes-plugin-git:log (query) — paginated
diff.ts # devframes-plugin-git:diff (query)
blame.ts # devframes-plugin-git:blame (query)
branches.ts # devframes-plugin-git:branches (query)
stage.ts # devframes-plugin-git:stage (action, write-gated)
commit.ts # devframes-plugin-git:commit (action, write-gated)
checkout.ts # devframes-plugin-git:checkout (action, write-gated)
watcher.ts # HEAD/index watcher → shared-state push
spa/
bin.mjs
test/ # use a temp git repo fixture
```

## Node side

- Git access via `simple-git` (or `isomorphic-git` for zero-binary portability —
decide in milestone 0; add to the `deps` catalog). Run commands relative to
`ctx.workspaceRoot` / `ctx.cwd`.
- Watcher updates `devframes-plugin-git:state` shared state (branch, ahead/behind, dirty counts) on
`.git/HEAD` / index changes; debounced.
- Write RPCs only registered when `createGitDevframe({ write: true })`; otherwise
omitted from the registry entirely (not just hidden). Diagnostics `DP_GIT_00xx`:
not-a-repo, dirty-tree-conflict, write-disabled.

## Client side

- Vue SPA: Status, History (commit graph/log), Diff, Branches, Blame views.
Reuses table/tree/diff primitives; consider sharing with #1 if a UI kit emerges.

## Milestones

1. Scaffold. `devframes-plugin-git:status` + Status view (read-only).
2. `devframes-plugin-git:log` (paginated) + History; `devframes-plugin-git:diff` + Diff viewer.
3. Live `devframes-plugin-git:state` watcher → shared state.
4. `devframes-plugin-git:branches` + `devframes-plugin-git:blame`.
5. Opt-in write actions + command-palette entries.
6. tsnapi snapshot + e2e against a temp-repo fixture.

## Open questions / risks

- **`simple-git` (spawns `git`) vs `isomorphic-git` (pure JS).** Portability and
the standalone `npx` story favor `isomorphic-git`; fidelity/perf favor
`simple-git`. Decide in milestone 0.
- Diff/log payload size — paginate and/or stream; revisit whether `snapshot`
scales for large repos.
- Whether to lean on `json-render` docks for simple panels (cheaper, no SPA build)
vs. the full Vue SPA — good place to dogfood `createJsonRenderer`.
- Write actions are a footgun; default read-only, gate explicitly.
Loading
Loading