Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Work items

MOTIR-2212Done

11.5.4 The adapter module + the IDENTITY reads (`whoami`, `listProjects`) — and the test harness learns `/api/v1`

⚠️ SPLIT 2026-08-07 after three attempts. This card was "the six reads"; it is now the FIRST of three slices.

Each attempt finished the port and ran out of room in the ~40 test conversions the contract change obliges. The sizing was not the real problem — every intermediate state was RED, because porting six methods at once breaks every suite that drives any of them. There was no green increment to stop at.

The fix is to split by METHOD GROUP, so each card ports a few methods AND converts exactly the suites those methods break, and each lands green:

  • this card — the adapter module, the test harness's /api/v1 capability, whoami + listProjects
  • 11.5.21listReady + listSprints
  • 11.5.22getWorkItem + getWorkItemActivity, and the --json decision

The work is already written: scratchpad/11.5.4-wip.patch (1171 lines) carries all three slices plus a real bug fix. This card takes its share.

Introduce the adapter module, teach the test harness to serve /api/v1, and port the two IDENTITY reads.

What this card ports

methodv1 operation
whoamiGET /api/v1/me + GET /api/v1/workspaces — TWO reads, matched on workspaceId, never on position
listProjectsGET /api/v1/projects, walked to exhaustion (the view model is a whole list)

The three foundations it lays

1. packages/cli/src/adapters/reads.ts — the named module 11.5.1 Q4 pins: wire types in, the CLI's own view models out, no generated type visible to a renderer. It arrives with the two identity mappers; the later slices add theirs.

2. MotirClient gains the V1Transport, built in the constructor rather than on connect() — it holds no connection, only a base URL and a bearer, and a read must not require an MCP handshake it no longer uses. MotirClientOptions gains fetchImpl for tests. The two transports COEXIST until 11.5.6.

3. packages/cli/test/helpers/mcpTestServer.ts serves /api/v1 — a V1Script keyed `${METHOD} ${pathTemplate}` with {name} segments, a matcher where a literal beats a placeholder, v1Calls recording, scriptV1(), and a DEFAULT_V1 mirroring DEFAULT_TOOLS' data.

⚠️ The v1 fixtures are written as REAL v1 payloads, never derived from the MCP script. A translation helper would be a second adapter running backwards, and every read test would then assert that the harness and src/adapters/reads.ts agree with each other rather than that either agrees with the server.

⚠️ v1Calls accumulates exactly like calls — every suite that resets one must reset both, or assertions inherit the previous test's requests.

Scope BOUNDARY

The adapter module, the transport wiring, the harness capability, and the two identity methods. It MAY change a command file — but only a line that consumes a view-model field this card changed, and never a human-readable output string. It does NOT port listReady / listSprints (11.5.21) or getWorkItem / getWorkItemActivity (11.5.22). It does NOT touch --json, whose shape is 11.5.22's decision. It does NOT delete the MCP transport (11.5.6).

Acceptance criteria

  • whoami and listProjects call /api/v1 through the transport core; no MCP tool call remains on either path.
  • ProjectSummary drops id and slug — no file in packages/cli/src reads either, and both are deliberately off the v1 project resource (id by §7, slug because nothing addresses a project by it). The adapter DROPS them; it does not synthesise them.
  • whoami resolves its workspace by matching me.workspaceId against the /workspaces list — asserted with a list whose FIRST row is not the bound one, so a positional read fails.
  • listProjects walks every page — asserted against a two-page collection, with the second page's cursor echoed exactly as received.
  • A READ needs no connect() — asserted directly, and the existing "refuses to be used before connect()" re-aimed at a method that still speaks MCP. This is the point of the port, not an oversight.
  • motir auth, motir login, motir link and motir doctor produce output identical to the MCP-era implementation for the same data.
  • The whole packages/cli suite is GREEN at this commit — no suite is left red for a later slice.
  • No generated wire type is imported outside src/adapters/ and src/transport.tstests/cli/generated-api-freshness.test.ts already enforces this.
  • The per-file coverage floor (≥90%) holds on every new and modified file.

Context refs

  • scratchpad/11.5.4-wip.patch — the written work, including this slice.
  • 11.5.1 Q4 · 11.5.3 — the boundary rule and the transport.
  • lib/api/v1/identity/schema.ts · projects/schema.ts — the wire shapes.
  • packages/cli/test/clientCore.test.ts · login.test.ts · projectLink.test.ts · commands.interactive.test.ts · doctorCommand.test.ts — the suites this slice converts.
  • Story: 11.5.