158 lines
4.8 KiB
Markdown
158 lines
4.8 KiB
Markdown
# Plan: Full AI CLI Integration Through Real Opencode
|
|
|
|
## Goal
|
|
|
|
Run the real ComputerCraft `ai` CLI against a real `opencode serve` process through the WebSocket bridge proxy, while using the fake provider/model fixture proven by `opencode-fake-provider-direct-plan.md`.
|
|
|
|
This test should cover the actual runtime chain used in-game.
|
|
|
|
## Dependency
|
|
|
|
Do not implement this plan until `.plans/opencode-fake-provider-direct-plan.md` has produced a working fake provider fixture.
|
|
|
|
Update this plan first with the concrete results from plan 1:
|
|
|
|
- Working fake provider plugin code shape.
|
|
- Working opencode startup command/env.
|
|
- Working readiness endpoint.
|
|
- Any internal prompt behavior discovered.
|
|
|
|
## Desired Boundary
|
|
|
|
Real:
|
|
|
|
- CraftOS-PC harness
|
|
- `/programs/ai.lua`
|
|
- `/apis/libai.lua`
|
|
- `/apis/libhttpws.lua`
|
|
- `tools/mcp-bridge` opencode proxy
|
|
- `opencode serve`
|
|
- opencode sessions/messages/agents/model selection
|
|
|
|
Fake:
|
|
|
|
- The provider/model response behavior only, through the reusable fake provider fixture from plan 1
|
|
|
|
## Runtime Chain
|
|
|
|
```text
|
|
CraftOS /programs/ai.lua
|
|
-> libai.lua
|
|
-> libhttpws.lua
|
|
-> mcp-bridge opencode proxy
|
|
-> real opencode serve
|
|
-> fake provider/model
|
|
```
|
|
|
|
## Test Fixture
|
|
|
|
Reuse the fake provider workspace generator from plan 1.
|
|
|
|
Response mappings needed for the CLI cases:
|
|
|
|
```json
|
|
[
|
|
{ "match": "reply with exactly: pong", "reply": "pong" },
|
|
{ "match": "fresh start", "reply": "new reply" },
|
|
{ "match": "continue please", "reply": "plain reply" }
|
|
]
|
|
```
|
|
|
|
Keep the mapping fixture easy to extend so future CLI cases can add entries without changing provider code.
|
|
|
|
## CraftOS Wrapper
|
|
|
|
Create or update a Lua wrapper under:
|
|
|
|
- `tools/mcp-bridge/test-integration/lua/ai-cli-check.lua`
|
|
|
|
The wrapper should:
|
|
|
|
1. Accept the WebSocket proxy URL as its first argument.
|
|
2. Clear stale settings:
|
|
- `opencc.server_url`
|
|
- `opencc.session_id`
|
|
3. Set:
|
|
- `opencc.bridge_url`
|
|
- `opencc.request_timeout_seconds`
|
|
4. Run:
|
|
- `ai sessions`
|
|
- `ai ping`
|
|
- `ai new fresh start`
|
|
- `ai continue please`
|
|
5. Print markers around each command.
|
|
6. Print persisted session markers after commands.
|
|
7. Call `os.shutdown()`.
|
|
|
|
Expected marker examples:
|
|
|
|
```lua
|
|
print('--- sessions ---');
|
|
shell.run('/programs/ai.lua', 'sessions');
|
|
|
|
print('--- ping ---');
|
|
shell.run('/programs/ai.lua', 'ping');
|
|
print('SESSION_AFTER_PING=' .. tostring(settings.get('opencc.session_id')));
|
|
|
|
print('--- new ---');
|
|
shell.run('/programs/ai.lua', 'new', 'fresh', 'start');
|
|
print('SESSION_AFTER_NEW=' .. tostring(settings.get('opencc.session_id')));
|
|
|
|
print('--- ask ---');
|
|
shell.run('/programs/ai.lua', 'continue', 'please');
|
|
print('SESSION_AFTER_ASK=' .. tostring(settings.get('opencc.session_id')));
|
|
```
|
|
|
|
## Node Test Implementation
|
|
|
|
Add or replace the current CLI integration test under:
|
|
|
|
- `tools/mcp-bridge/test-integration/ai-cli.test.ts`
|
|
|
|
Test steps:
|
|
|
|
1. Create temp fake-provider opencode workspace using the plan 1 fixture.
|
|
2. Start `opencode serve` on a random local port.
|
|
3. Poll until opencode is ready.
|
|
4. Start `startOpencodeProxy({ opencodeUrl })`.
|
|
5. Start CraftOS with:
|
|
- `mountRepo: true`
|
|
- `shellArgs: [proxyUrl]`
|
|
- a generous timeout, likely `30_000` or higher depending on measured opencode startup time
|
|
6. Assert CLI output includes:
|
|
- `pong`
|
|
- `new reply`
|
|
- `plain reply`
|
|
- session markers proving `ai new` replaces the session and plain `ai ...` reuses it
|
|
7. Stop CraftOS, proxy, and opencode in `finally`.
|
|
|
|
## Useful Assertions
|
|
|
|
- `ai sessions` exits without an opencode transport/config error.
|
|
- `ai ping` prints `pong`.
|
|
- `ai new fresh start` prints `new reply`.
|
|
- Plain `ai continue please` prints `plain reply`.
|
|
- `SESSION_AFTER_NEW` is non-empty.
|
|
- `SESSION_AFTER_ASK` equals `SESSION_AFTER_NEW`.
|
|
- If `SESSION_AFTER_PING` is printed, decide whether ping should persist a session or whether `ai ping` should become non-persistent in a separate behavior change.
|
|
|
|
## Current Open Questions
|
|
|
|
- Should `ai ping` persist `opencc.session_id`? Current `programs/ai.lua` calls `ai.ping(askOptions())`, and `libai.ping` behavior must be checked before asserting this too tightly.
|
|
- Should `ai sessions` be expected to show no sessions, one session, or just avoid failing before messages are created? Real opencode behavior may differ from the old fake HTTP server.
|
|
- Does opencode generate a title/summary for each message during the synchronous `/message` call? If yes, the fake provider fallback must make that harmless.
|
|
- What is the most stable way to choose a free opencode port in CI?
|
|
|
|
## Verification
|
|
|
|
After implementation, run:
|
|
|
|
```sh
|
|
npx tsx --test test-integration/opencode-fake-provider.test.ts
|
|
npx tsx --test test-integration/ai-cli.test.ts
|
|
npm run check
|
|
just check
|
|
```
|
|
|
|
If the full test is too slow for the default integration suite, keep it as a separately named test command or document why it is excluded from `npm run test:integration`.
|