chore: save plan

This commit is contained in:
Guillaume ARM 2026-06-12 00:20:57 +02:00
parent 835f1ff4a7
commit 4eb1b468ea
2 changed files with 278 additions and 0 deletions

View File

@ -0,0 +1,157 @@
# 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`.

View File

@ -0,0 +1,121 @@
# Plan: Direct Fake Provider Integration
## Goal
Prove that a real `opencode serve` process can run with a deterministic fake provider/model and answer HTTP API requests without calling an external LLM.
This plan deliberately stops before CraftOS, the WebSocket bridge, or `/programs/ai.lua`. It validates only the opencode-side fixture that the full integration test will reuse.
## Desired Boundary
Real:
- `opencode serve`
- opencode config validation and loading
- opencode session/message HTTP endpoints
- opencode model/provider selection
- opencode agent/title/summary plumbing as far as it is triggered by simple messages
Fake:
- The provider/model response behavior only
## Proposed Test Fixture
Create a test-only temporary opencode workspace during the test. Do not modify the project `.opencode/opencode.json` for this.
Files generated under a temp directory:
- `opencode.json`
- `fake-provider.ts` or `fake-provider.js`
- `fake-responses.json`
Example response mapping:
```json
[
{ "match": "reply with exactly: pong", "reply": "pong" },
{ "match": "fresh start", "reply": "new reply" },
{ "match": "continue please", "reply": "plain reply" }
]
```
The fake provider should return the first response whose `match` appears in the final model prompt. Unknown prompts should return a deterministic fallback such as `ok` or `unhandled fake prompt`, not fail immediately, because opencode may issue title/summary/internal prompts.
## Config Shape To Validate
Use the published schema as the source of truth before finalizing fields.
Candidate config:
```json
{
"$schema": "https://opencode.ai/config.json",
"model": "traptest/fake",
"small_model": "traptest/fake",
"enabled_providers": ["traptest"],
"plugin": ["./fake-provider.ts"],
"provider": {
"traptest": {
"name": "Trap Test",
"models": {
"fake": {
"id": "fake",
"name": "Trap Test Fake Model",
"limit": { "context": 100000, "output": 10000 },
"cost": { "input": 0, "output": 0 },
"status": "active"
}
}
}
},
"agent": {
"build": { "model": "traptest/fake" },
"title": { "model": "traptest/fake" },
"summary": { "model": "traptest/fake" }
}
}
```
Open question: the exact plugin provider hook shape must be verified against opencode's runtime/plugin API. Do not guess this implementation from the config schema alone.
## Test Implementation
Add a Node integration test, likely under:
- `tools/mcp-bridge/test-integration/opencode-fake-provider.test.ts`
Test steps:
1. Create a temp directory.
2. Write the test `opencode.json`.
3. Write `fake-responses.json`.
4. Write the fake provider plugin.
5. Start `opencode serve` on `127.0.0.1` with a random free port.
6. Wait for readiness by polling an HTTP endpoint such as `GET /session`.
7. Call opencode HTTP directly:
- `POST /session`
- `POST /session/:id/message` with `reply with exactly: pong`
- `POST /session/:id/message` with `fresh start`
8. Assert the responses contain `pong` and `new reply`.
9. Stop the opencode process and clean up the temp directory.
## Useful Assertions
- `opencode serve` starts successfully with the generated config.
- `POST /session` returns a usable session ID.
- `POST /session/:id/message` returns text from the fake mapping.
- Unknown/internal prompts do not break the test fixture.
- No external provider credentials are required.
## Result To Capture For Plan 2
After this plan is run, record:
- Exact working fake provider plugin API shape.
- Exact command/env used to start `opencode serve` reliably.
- Confirmed readiness endpoint and polling logic.
- Whether title/summary/internal model calls happen during simple message requests.
- Any required config fields not listed above.
Plan 2 should be updated with these facts before implementation.