cc-libs/.plans/opencode-ai-cli-full-integration-plan.md
2026-06-12 00:20:57 +02:00

4.8 KiB

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

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:

[
  { "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:

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:

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.