|
@@ -1,201 +1,196 @@
|
|
|
-# OpenCode v2 (`opencode2`) Compatibility
|
|
|
|
|
|
|
+# OpenCode v2 compatibility and native migration
|
|
|
|
|
|
|
|
-oh-my-opencode-slim installs and runs on **both** OpenCode v1 (`opencode`) and
|
|
|
|
|
-OpenCode v2 (`opencode2`) from a single published package. This document
|
|
|
|
|
-explains how the dual-compatibility works and what is supported on each host.
|
|
|
|
|
|
|
+## Current status
|
|
|
|
|
|
|
|
-## How it works
|
|
|
|
|
|
|
+OpenCode v2 compatibility is currently provided by a **v1-to-v2 adapter**. It
|
|
|
|
|
+is not a native v2 implementation, and native v2 support has not shipped.
|
|
|
|
|
|
|
|
-The package's default export is an object:
|
|
|
|
|
|
|
+The current path is `src/v2/setup.ts`:
|
|
|
|
|
|
|
|
-```ts
|
|
|
|
|
-export default {
|
|
|
|
|
- id: 'oh-my-opencode-slim',
|
|
|
|
|
- server: OhMyOpenCodeLite, // v1 plugin function (PluginInput) => Promise<Hooks>
|
|
|
|
|
- setup: createV2Setup(), // v2 promise-plugin setup (ctx) => Promise<cleanup>
|
|
|
|
|
-};
|
|
|
|
|
-```
|
|
|
|
|
|
|
+1. v2 calls the package's `default.setup(ctx)` entry point.
|
|
|
|
|
+2. The adapter builds a v1-shaped `PluginInput`, including a client shim and
|
|
|
|
|
+ `process.cwd()` as the project directory.
|
|
|
|
|
+3. It invokes the existing `OhMyOpenCodeLite` v1 factory and receives v1
|
|
|
|
|
+ `Hooks`.
|
|
|
|
|
+4. It translates those hooks into v2 agent, tool, command, session-context,
|
|
|
|
|
+ tool-lifecycle, and event registrations.
|
|
|
|
|
+5. It returns cleanup functions for the v2 registrations and the v1 factory.
|
|
|
|
|
+
|
|
|
|
|
+This preserves useful behavior while both hosts are supported, but it is a
|
|
|
|
|
+best-effort compatibility layer. Registration failures are independently
|
|
|
|
|
+isolated, so a plugin can load with only part of its behavior registered.
|
|
|
|
|
+
|
|
|
|
|
+The beta checkout used for the migration target is OpenCode `v2` at
|
|
|
|
|
+`d6deb62379c54dc60468b80c498bd6a5899797cf`.
|
|
|
|
|
+
|
|
|
|
|
+## Installing the current adapter on v2
|
|
|
|
|
|
|
|
-- **v1 loader** (`readV1Plugin` in `packages/opencode/src/plugin/shared.ts`)
|
|
|
|
|
- detects an object with a `server` field and calls `plugin.server(input)`.
|
|
|
|
|
- This is the original, unchanged v1 code path — v1 behavior is identical to
|
|
|
|
|
- previous releases.
|
|
|
|
|
-- **v2 loader** (`PluginModule` schema in
|
|
|
|
|
- `packages/core/src/plugin/supervisor.ts`) decodes `default` as
|
|
|
|
|
- `{ id, setup }` (Effect Schema 4 rejects function defaults) and calls
|
|
|
|
|
- `setup(ctx)` via the promise-plugin bridge.
|
|
|
|
|
-
|
|
|
|
|
-Two builds are produced:
|
|
|
|
|
-
|
|
|
|
|
-| Export | File | Build | Externals |
|
|
|
|
|
-|---|---|---|---|
|
|
|
|
|
-| `.` (main) | `dist/index.js` | `build:plugin` | zod, jsdom, @ast-grep/napi, @opencode-ai/* (shared with v1 host) |
|
|
|
|
|
-| `./server` | `dist/server.js` | `build:v2` | @ast-grep/napi, jsdom only (self-contained for v2) |
|
|
|
|
|
-
|
|
|
|
|
-v2's plugin resolver tries the `server` subpath first
|
|
|
|
|
-(`subpaths: ["server", ""]`), so a v2 package install loads the self-contained
|
|
|
|
|
-`dist/server.js`. v1 uses the main entry.
|
|
|
|
|
-
|
|
|
|
|
-## The v2 adapter (`src/v2/setup.ts`)
|
|
|
|
|
-
|
|
|
|
|
-`setup(ctx)` wraps the existing v1 factory rather than reimplementing it:
|
|
|
|
|
-
|
|
|
|
|
-1. Builds a v1-shaped `PluginInput` from the v2 context (`process.cwd()` for
|
|
|
|
|
- `directory`; a shim `client` that delegates `session.abort/prompt/messages`,
|
|
|
|
|
- `app.log`, and `tui.showToast` to the v2 context or graceful no-ops).
|
|
|
|
|
-2. Invokes `OhMyOpenCodeLite(pluginInput)` to reuse **all** existing build
|
|
|
|
|
- logic (config, agents, tools, hooks, job board, multiplexer, companion).
|
|
|
|
|
-3. Runs the v1 `config()` hook against a synthesized config to resolve agent
|
|
|
|
|
- models and the slash commands.
|
|
|
|
|
-4. Bridges the returned v1 `Hooks` into v2 registrations:
|
|
|
|
|
- - `agent` → `ctx.agent.transform` (model/prompt/permission adaptation +
|
|
|
|
|
- `subagent`/`execute` permission mapping + prompt rewrite `task`→`subagent`)
|
|
|
|
|
- - `tool` → `ctx.tool.transform` (zod shape → JSON schema; execute shimmed)
|
|
|
|
|
- - `command` → `ctx.command.transform` (deepwork/reflect/loop)
|
|
|
|
|
- - `experimental.chat.system.transform` +
|
|
|
|
|
- `experimental.chat.messages.transform` → `ctx.session.hook("context")`
|
|
|
|
|
- (SystemPart[]/Message.content shape conversion)
|
|
|
|
|
- - `tool.execute.before/after` → `ctx.tool.hook`
|
|
|
|
|
- - `event` → `ctx.event.subscribe()` loop
|
|
|
|
|
- - `dispose` → returned cleanup
|
|
|
|
|
-
|
|
|
|
|
-Each bridge is independently try/catch-guarded so one failure cannot disable
|
|
|
|
|
-the rest.
|
|
|
|
|
-
|
|
|
|
|
-## Feature matrix
|
|
|
|
|
-
|
|
|
|
|
-| Capability | v1 (`opencode`) | v2 (`opencode2`) | Notes |
|
|
|
|
|
-|---|---|---|---|
|
|
|
|
|
-| Orchestrator + specialist agents | ✅ | ✅ | |
|
|
|
|
|
-| Agent prompts / system injection | ✅ | ✅ | via `session.hook("context")` |
|
|
|
|
|
-| Delegation to subagents | ✅ `task` | ✅ `subagent` | prompts rewritten for v2 |
|
|
|
|
|
-| Tools (ast-grep, webfetch, task_message, task_cancel, task_revive, wait_for_user, acp_run) | ✅ | ✅* | `*` ast-grep/webfetch need `@ast-grep/napi`/`jsdom` resolvable |
|
|
|
|
|
-| Slash commands `/deepwork` `/reflect` `/loop` | ✅ | ✅ | |
|
|
|
|
|
-| Message transforms (phase reminder, skills filter, image routing, display-name rewrite) | ✅ | ✅ | |
|
|
|
|
|
-| Event handling (session tracking, lifecycle) | ✅ | ✅ | |
|
|
|
|
|
-| Tool execute hooks (apply-patch recovery, task-session, json-recovery) | ✅ | ✅ | |
|
|
|
|
|
-| Built-in MCPs (context7, grep.app) | ✅ | ⚠️ config-only | v2 has no programmatic MCP hook; add 2 lines to `opencode.json` — see [below](#restoring-built-in-mcps-on-v2) |
|
|
|
|
|
-| `/preset` (interactive switcher) | ✅ | ❌ at load only | the switcher is a v1-TUI 3-level UI; on v2 set `"preset"` in the config file (applies at load) |
|
|
|
|
|
-| Foreground model fallback (rate-limit failover) | ✅ | ❌ | v2 locks the model at session creation; the plugin API has no per-prompt model override, session model-setter, or `/model` command, so mid-flight switching is impossible |
|
|
|
|
|
-| Orchestrator wake scheduler (`backgroundJobs.orchestratorWake`) | ✅ | ❌ | Requires host `session.get` / `todo` / `children` / `status` / `promptAsync`; the v2 shim lacks these APIs so the capability-gated feature stays inactive |
|
|
|
|
|
-| Multiplexer (tmux/zellij/herdr/cmux panes) | ✅ | ❌ | v1-TUI-pane integration; v2 renders subagents natively instead |
|
|
|
|
|
-| Companion app | ✅ | ⚠️ unverified | independent desktop app; test separately against v2 |
|
|
|
|
|
-| Default agent on new session | ✅ orchestrator | ⚠️ TUI shows `build` | v1 sets `default_agent`; v2's TUI ignores that field and defaults to the first agent in its list (`build`). `run`/API still default to orchestrator. See [limitations](#limitations) |
|
|
|
|
|
-
|
|
|
|
|
-## Installing on v2
|
|
|
|
|
-
|
|
|
|
|
-Add to `~/.config/opencode2/opencode.json`:
|
|
|
|
|
|
|
+The existing package install remains. In the beta checkout, the executable is
|
|
|
|
|
+`opencode2` but the global configuration root is still named `opencode`:
|
|
|
|
|
+
|
|
|
|
|
+Add to `~/.config/opencode/opencode.json`:
|
|
|
|
|
|
|
|
```json
|
|
```json
|
|
|
{
|
|
{
|
|
|
- "plugin": ["oh-my-opencode-slim@latest"]
|
|
|
|
|
|
|
+ "plugins": ["oh-my-opencode-slim@latest"]
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-For local development, point at the built `dist/server.js` directly:
|
|
|
|
|
|
|
+For local development, use the v2 bundle directly:
|
|
|
|
|
|
|
|
```json
|
|
```json
|
|
|
{
|
|
{
|
|
|
- "plugin": ["/path/to/oh-my-opencode-slim/dist/server.js"]
|
|
|
|
|
|
|
+ "plugins": ["/path/to/oh-my-opencode-slim/dist/server.js"]
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-Then build:
|
|
|
|
|
|
|
+Build the two host bundles with:
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
bun install
|
|
bun install
|
|
|
-bun run build # produces dist/index.js (v1) AND dist/server.js (v2)
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-Verify with `opencode2 run "list your specialist agents" --standalone` — the
|
|
|
|
|
-orchestrator should name explorer, librarian, oracle, designer, fixer.
|
|
|
|
|
-
|
|
|
|
|
-## Configuring models on v2
|
|
|
|
|
-
|
|
|
|
|
-Agent models are resolved the same way as v1 (per-agent `model` in
|
|
|
|
|
-`oh-my-opencode-slim.json`, or inherited from the session/host default). On v2,
|
|
|
|
|
-set a working provider+model in your v2 config or the plugin's config file so
|
|
|
|
|
-delegated subagents can run.
|
|
|
|
|
-
|
|
|
|
|
-> **Rate-limit fallback is not available on v2.** v2 locks a session's model at
|
|
|
|
|
-> creation; the plugin context exposes no per-prompt model override, no
|
|
|
|
|
-> session-level model setter, and no `/model` command. If you hit a 429/rate
|
|
|
|
|
-> limit, switch the model manually (start a new session or change the configured
|
|
|
|
|
-> model) — the plugin cannot do this automatically on v2.
|
|
|
|
|
-
|
|
|
|
|
-## Restoring built-in MCPs on v2
|
|
|
|
|
-
|
|
|
|
|
-v2 has no programmatic MCP-registration hook, so the plugin's two built-in
|
|
|
|
|
-remote MCPs are not auto-registered. They are plain remote URLs — copy this into
|
|
|
|
|
-your `~/.config/opencode2/opencode.json` to restore them:
|
|
|
|
|
-
|
|
|
|
|
-```json
|
|
|
|
|
-{
|
|
|
|
|
- "mcp": {
|
|
|
|
|
- "context7": {
|
|
|
|
|
- "type": "remote",
|
|
|
|
|
- "url": "https://mcp.context7.com/mcp",
|
|
|
|
|
- "headers": { "CONTEXT7_API_KEY": "$CONTEXT7_API_KEY" }
|
|
|
|
|
- },
|
|
|
|
|
- "gh_grep": { "type": "remote", "url": "https://mcp.grep.app" }
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
|
|
+bun run build
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-(`context7` needs `CONTEXT7_API_KEY`; `gh_grep` needs nothing. Drop either key
|
|
|
|
|
-if unused.) The librarian agent uses these for library-docs lookup and
|
|
|
|
|
-GitHub-wide code search; without them it still works via `webfetch`.
|
|
|
|
|
-
|
|
|
|
|
-## Limitations
|
|
|
|
|
-
|
|
|
|
|
-### Interview
|
|
|
|
|
-
|
|
|
|
|
-`/interview` is supported on v2 through a marker command and a trailing-message
|
|
|
|
|
-context bridge. The bridge keeps an in-memory transcript projection from v2
|
|
|
|
|
-context and streamed text events, and uses the v2 session methods for prompts,
|
|
|
|
|
-notifications, and renames. The markdown document remains the durable source
|
|
|
|
|
-of truth; completion responses without `<interview_state>` rewrite the current
|
|
|
|
|
-spec while retaining frontmatter and Q&A history.
|
|
|
|
|
-
|
|
|
|
|
-These are **v2 API constraints**, not adapter gaps — they cannot be fixed in the
|
|
|
|
|
-plugin without v2 adding the corresponding capability:
|
|
|
|
|
-
|
|
|
|
|
-- **Foreground model fallback impossible.** v2's `SessionPromptInput` has no
|
|
|
|
|
- `model` field, the plugin `SessionDomain` exposes only
|
|
|
|
|
- `create/get/prompt/generate/command/synthetic/interrupt` (no model setter),
|
|
|
|
|
- and there is no `/model` command. A session's model is fixed at creation, so
|
|
|
|
|
- the plugin cannot switch models on a rate-limited foreground session.
|
|
|
|
|
- v1-only.
|
|
|
|
|
-- **Interactive `/preset` switcher impossible.** The switcher is a three-level
|
|
|
|
|
- v1-TUI UI (`@opentui/solid`). v2 slash commands are template-only (no
|
|
|
|
|
- interactive UI, no execute handler). **Workaround:** set `"preset"` in
|
|
|
|
|
- `oh-my-opencode-slim.json` — it applies at plugin load and resolves all agent
|
|
|
|
|
- models correctly.
|
|
|
|
|
-- **No programmatic MCP registration.** v2's plugin context has no MCP domain.
|
|
|
|
|
- Declare MCPs in `opencode.json` (snippet above).
|
|
|
|
|
-- **Multiplexer panes.** tmux/zellij/herdr integration is a v1-TUI feature; v2
|
|
|
|
|
- renders subagents natively, so this is intentionally not ported.
|
|
|
|
|
-- **TUI default agent is `build`, not `orchestrator`.** v1 sets
|
|
|
|
|
- `default_agent = "orchestrator"` in its config hook and the v1 TUI honors it.
|
|
|
|
|
- The v2 adapter does call `ctx.agent.transform(draft => draft.default("orchestrator"))`,
|
|
|
|
|
- which makes `run`/API default to the orchestrator — but the v2 TUI ignores the
|
|
|
|
|
- `default_agent` config field entirely and instead defaults to the **first agent
|
|
|
|
|
- in its list** (`list()[0]`, insertion order), which is v2's built-in `build`.
|
|
|
|
|
- The plugin API offers no list-reorder, and `AgentDraft` has no "move to front".
|
|
|
|
|
- Effect: `opencode2 run` and programmatic sessions use the orchestrator; opening
|
|
|
|
|
- the v2 TUI / starting a new session there defaults to `build` (switch once; the
|
|
|
|
|
- choice is persisted per-session via `saved.session[id].agent`, but each brand-new
|
|
|
|
|
- session resets to `build`). Requires an upstream v2 change (TUI honoring
|
|
|
|
|
- `default_agent`, or a list-order/default API for plugins) to fix.
|
|
|
|
|
-
|
|
|
|
|
-These are adapter/environment caveats that can be worked around:
|
|
|
|
|
-
|
|
|
|
|
-- **Path-based dev loading.** When v2 loads the plugin by absolute file path it
|
|
|
|
|
- appends a `?mtime=` cache-busting query, which can break resolution of
|
|
|
|
|
- externalized bare imports (`@ast-grep/napi`, `jsdom`) from the plugin's
|
|
|
|
|
- `node_modules`. The plugin still loads (these are lazy-imported only by the
|
|
|
|
|
- ast-grep and webfetch tools); install as a package or ensure the externals are
|
|
|
|
|
- resolvable to enable those tools locally.
|
|
|
|
|
-- **directory source.** v2's plugin context does not expose the project
|
|
|
|
|
- directory, so the adapter uses `process.cwd()`. Run `opencode2` from your
|
|
|
|
|
- project root (or use `--standalone`, which sets cwd to the project).
|
|
|
|
|
|
|
+The build currently produces `dist/index.js` for v1 and `dist/server.js` for
|
|
|
|
|
+the v2 adapter. Run OpenCode v2 from the project directory, or use
|
|
|
|
|
+`--standalone`, because the adapter has no project-directory field and uses
|
|
|
|
|
+`process.cwd()`.
|
|
|
|
|
+
|
|
|
|
|
+## Adapter limitations
|
|
|
|
|
+
|
|
|
|
|
+These are limitations of the transitional implementation, not proof that the
|
|
|
|
|
+official v2 API lacks the capability:
|
|
|
|
|
+
|
|
|
|
|
+- The adapter must construct fake v1 input and translate v1 hook shapes. It
|
|
|
|
|
+ cannot provide the type or lifecycle guarantees of a native v2 plugin.
|
|
|
|
|
+- It uses a client shim with only selected operations and graceful no-ops.
|
|
|
|
|
+ Legacy code that expects v1 client state, task/session helpers, headers, or
|
|
|
|
|
+ UI behavior cannot be made equivalent by the shim.
|
|
|
|
|
+- The v1 factory and synthesized `config()` hook remain the source of agent,
|
|
|
|
|
+ tool, command, and runtime wiring. Failed bridges are logged and skipped
|
|
|
|
|
+ rather than failing setup as a native plugin should.
|
|
|
|
|
+- The adapter currently does not register built-in MCP definitions through the
|
|
|
|
|
+ v2 MCP domain. OpenCode v2 does provide that domain; native migration must
|
|
|
|
|
+ use it rather than treating MCP support as config-only.
|
|
|
|
|
+- The adapter's interview bridge reconstructs only an in-memory projection
|
|
|
|
|
+ from v2 context and events. It is not a durable, reload-safe v2 history
|
|
|
|
|
+ implementation.
|
|
|
|
|
+- Absolute-path development loading can expose externalized `jsdom` and
|
|
|
|
|
+ `@ast-grep/napi` resolution problems. Installing the package or making those
|
|
|
|
|
+ dependencies resolvable avoids this adapter/build issue.
|
|
|
|
|
+
|
|
|
|
|
+## Supported native v2 surface
|
|
|
|
|
+
|
|
|
|
|
+The beta Promise plugin API uses `define({ id, setup(context) })`; setup returns
|
|
|
|
|
+cleanup and registrations are disposed with plugin scope. Its domains include:
|
|
|
|
|
+
|
|
|
|
|
+- `agent`: inspect/update/remove agents, set the default, and transform the
|
|
|
|
|
+ agent catalog;
|
|
|
|
|
+- `tool`: add tools and hook `execute.before`/`execute.after`;
|
|
|
|
|
+- `command`: add executable command definitions and reload commands;
|
|
|
|
|
+- `session`: create/get/switch agent/switch model, prompt, generate, command,
|
|
|
|
|
+ synthetic, interrupt, rename, wait, and hook `context`, `model.request`,
|
|
|
|
|
+ `http.request`, or `http.response`;
|
|
|
|
|
+- `event`: subscribe to the server event stream;
|
|
|
|
|
+- `mcp`: transform, add, update, remove, and reload MCP configurations;
|
|
|
|
|
+- `shell`, `skill`, `storage`, and `websearch`: supported domain APIs for the
|
|
|
|
|
+ corresponding native integrations.
|
|
|
|
|
+
|
|
|
|
|
+Session `context` is the supported native replacement for v1 raw message
|
|
|
|
|
+transforms. Native code should mutate the v2 `system`, `messages`, and `tools`
|
|
|
|
|
+context directly, without converting through v1 `{ info, parts }` objects.
|
|
|
|
|
+
|
|
|
|
|
+## Native target architecture
|
|
|
|
|
+
|
|
|
|
|
+The target is a separate native Promise-plugin composition, not a more capable
|
|
|
|
|
+adapter:
|
|
|
|
|
+
|
|
|
|
|
+1. Keep host-neutral configuration, agent definitions, prompt construction, and
|
|
|
|
|
+ tool definitions in shared modules.
|
|
|
|
|
+2. Move the existing v1 composition behind an explicit `src/v1` boundary.
|
|
|
|
|
+3. Implement a native `define({ id, setup })` composition that registers agents,
|
|
|
|
|
+ tools, executable commands, MCPs, session context/model hooks, tool hooks,
|
|
|
|
|
+ and event handling through the official domains.
|
|
|
|
|
+4. Replace the client shim, local v2 type mirror, and interview bridge with
|
|
|
|
|
+ native context and lifecycle modules.
|
|
|
|
|
+5. Make required registration failures fail setup; do not silently continue
|
|
|
|
|
+ with a partial native installation.
|
|
|
|
|
+
|
|
|
|
|
+The native implementation must not invoke the v1 factory, convert v2 values to
|
|
|
|
|
+v1 hook payloads, or retain legacy lifecycle ownership merely to preserve
|
|
|
|
|
+parity.
|
|
|
|
|
+
|
|
|
|
|
+## Behaviors to deliberately retire
|
|
|
|
|
+
|
|
|
|
|
+Exact v1 parity is not possible through the supported v2 Promise API. The
|
|
|
|
|
+following behaviors must be explicitly retired from the native v2 target,
|
|
|
|
|
+rather than emulated with shims:
|
|
|
|
|
+
|
|
|
|
|
+- legacy background-job ownership and orchestrator wake scheduling;
|
|
|
|
|
+- child-pane multiplexer integration (tmux, zellij, herdr, and cmux);
|
|
|
|
|
+- runtime foreground-model failover;
|
|
|
|
|
+- tool permission prompt/cancellation interception;
|
|
|
|
|
+- initiator-header injection;
|
|
|
|
|
+- interview-history reconstruction after a plugin reload.
|
|
|
|
|
+
|
|
|
|
|
+The beta API also has no exact plugin hooks for compaction prompt replacement,
|
|
|
|
|
+permission-prompt interception, or synthetic text completion. Those behaviors
|
|
|
|
|
+need a product-level replacement or explicit retirement; they must not be
|
|
|
|
|
+presented as native parity.
|
|
|
|
|
+
|
|
|
|
|
+TUI toasts and the interactive `/preset` switcher are **not** required
|
|
|
|
|
+retirements. The beta plugin package exposes TUI participation through
|
|
|
|
|
+`tui: true` and the TUI context surface, so native migration should evaluate
|
|
|
|
|
+those controls as API opportunities. The current adapter does not bridge them;
|
|
|
|
|
+that is an adapter gap, not a claim that the native API cannot support them.
|
|
|
|
|
+
|
|
|
|
|
+Small-model selection is an inventory decision, not a predeclared retirement.
|
|
|
|
|
+The current implementation uses `runtime.smallModel()` for SmartFetch's
|
|
|
|
|
+secondary-model selection. The native migration must determine the supported
|
|
|
|
|
+v2 equivalent and its parity requirements during inventory.
|
|
|
|
|
+
|
|
|
|
|
+The official API does provide MCP registration, session model switching, and
|
|
|
|
|
+executable command registration. Those are migration opportunities, not
|
|
|
|
|
+retirements. In particular, the old documentation claim that v2 has no model
|
|
|
|
|
+setter or programmatic MCP surface is outdated for the beta checkout.
|
|
|
|
|
+
|
|
|
|
|
+The current adapter does not preserve the v1 `/preset` TUI experience. Native
|
|
|
|
|
+migration should decide whether the v2 TUI context can provide an equivalent
|
|
|
|
|
+interactive control or whether a documented noninteractive config/command
|
|
|
|
|
+workflow is preferable; it must not claim v1 UI parity before that work is
|
|
|
|
|
+verified.
|
|
|
|
|
+
|
|
|
|
|
+## Verification gates
|
|
|
|
|
+
|
|
|
|
|
+Validation is required at each migration boundary:
|
|
|
|
|
+
|
|
|
|
|
+1. **Architecture gate:** approve the host-neutral boundary, native domain
|
|
|
|
|
+ mapping, parity definition, and deliberate retirements.
|
|
|
|
|
+2. **Static/runtime gate:** compile, lint, and run unit tests for shared code,
|
|
|
|
|
+ the v1 host, and native registrations. Required registration failures must
|
|
|
|
|
+ be observable failures.
|
|
|
|
|
+3. **v2 host smoke gate:** using the beta checkout's embedded-host patterns and
|
|
|
|
|
+ `bun run dev:live`, prove plugin loading, agent/tool/command/MCP registration,
|
|
|
|
|
+ a session-context transform, tool lifecycle hooks, event handling, and
|
|
|
|
|
+ cleanup.
|
|
|
|
|
+4. **v1 compatibility gate:** retain the existing v1 load/smoke path until the
|
|
|
|
|
+ cutover is complete; verify that the v1 factory remains unchanged during
|
|
|
|
|
+ the transition.
|
|
|
|
|
+5. **Release-readiness gate:** verify the published package entry points,
|
|
|
|
|
+ install path, native v2 smoke artifact, documented retirements, and absence
|
|
|
|
|
+ of adapter-only claims before removing the transitional path.
|
|
|
|
|
+
|
|
|
|
|
+## Migration roadmap
|
|
|
|
|
+
|
|
|
|
|
+1. **Inventory:** map each v1 behavior to an official v2 domain, classify it as
|
|
|
|
|
+ native, adapter-only, or retired, and obtain approval for the retirements.
|
|
|
|
|
+2. **Separate composition:** introduce shared host-neutral config/prompt/tool
|
|
|
|
|
+ logic, move v1 composition to `src/v1`, and implement native Promise setup
|
|
|
|
|
+ with strict registration and cleanup.
|
|
|
|
|
+3. **Prove both hosts:** run the v2 host smoke and v1 compatibility gates in
|
|
|
|
|
+ parallel; compare supported behavior without expanding the shim.
|
|
|
|
|
+4. **Cut over v2:** make the native composition the v2 entry point, remove the
|
|
|
|
|
+ v1 adapter, client shim, local v2 type mirror, and interview bridge, then
|
|
|
|
|
+ retain v1 only for the verified cutover period.
|
|
|
|
|
+5. **Complete migration:** after release-readiness review, decide whether the
|
|
|
|
|
+ v1 host can be retired and remove remaining compatibility-only code.
|