Files
makelore/.project-docs/30-worklog/tasks/20260823-pi-extension-host-7e4c91a2.md

13 KiB

Task: Implement PI-070 managed extension host interactions and write lease

Identity

  • Task ID: 20260823-pi-extension-host-7e4c91a2
  • Mode: Feature
  • Branch: codex/20260823-pi-extension-host-7e4c91a2-pi-extension-host
  • Worktree: D:\Datas\OthersProjects\makelore-pi-extension-host-7e4c91a2
  • Base commit: 47159b3cbd
  • Owner: codex
  • Status: Completed — planner Pass

Scope

  • Implement PI-070 — Managed extension host, interactions, and write lease from the 【架构】opencode2pi Spec/ticket graph on cumulative baseline 47159b3cbdf06ea66db9a4425e0a9c13bcd73f7f.
  • Own the Main-private versioned Makelore Pi extension entry, authenticated worker bridge/registry, interaction lifecycle, project mutation write lease, and the smallest PI-060 projector/runtime integration required to expose safe product state.
  • Add focused real-bridge, stale-token/generation, interaction lifecycle, and lease concurrency/cancellation tests. Do not wire Renderer Host routes, subagents, product browser/tools, or final packaging owned by later tickets.

Intent And Constraints

  • Follow planner task 20260822-pi-runtime-spec-b6e2c9a4, ticket PI-070, and Spec LEASE-001 through LEASE-006, EXT-001 through EXT-006, and section 9.3 interaction semantics.
  • Load exactly one explicit versioned Makelore extension bundle. Project/user Pi extension discovery remains disabled; no generic plugin platform, permission engine, compatibility layer, signature/hash framework, or remote authorization scaffold is in scope.
  • Electron Main owns bridge tokens, worker identity, project identity, interactions, leases, and diagnostics. Every bridge request must match the registered conversation, worker generation, run, and short-lived token; disposed/recovered workers and old generations fail closed without affecting the current worker.
  • ask_user supports select/confirm/input/editor and correlates responses only by the pending interaction ID. Worker abort/crash/dispose cancels pending interactions. Unknown UI/widget/details are bounded diagnostics, never raw product state or logs.
  • Mutation write/edit/bash work uses one cancellable FIFO project lease; reads and pure reasoning bypass it, different projects may mutate concurrently, and complete/error/abort/timeout/crash/dispose always release ownership.
  • Draft/editor suggestions are revision-conditional and must not overwrite a newer user draft. Host routes and Renderer consumption remain for PI-100/ PI-130; this ticket records the Main-side contract only.
  • Real external Provider validation remains Explicitly Waived / Accepted Risk with realTurnVerified=false; macOS x64/arm64 remains deferred to mandatory PI-150 validation. Neither is a Pass.
  • Do not create subagents. Keep changes surgical and rooted in this isolated worktree.

Plan

  1. Verify the locked Pi 0.84.2 extension/tool interface and the existing PI-040/050/060 seams; define the smallest product-owned bridge interface.
  2. Implement the versioned managed extension bundle plus authenticated worker registry/bridge and prove real bridge round trips and stale identity rejection.
  3. Implement interaction storage/projection and the cancellable project write lease, then wire generation/run cleanup into the runtime without widening Host/Renderer interfaces.
  4. Run focused tests, all Pi tests, typecheck, lint, build, and relevant Electron/package checks; update this task record, pass documentation drift, commit, and hand the exact implementation HEAD to the planner for review.

Outcome

  • Implemented a Main-private, versioned makelore-runtime-v1.mjs bundle and changed Pi startup from --no-tools to an explicit built-in plus ask_user allowlist. Discovery remains disabled with --no-extensions, while the managed opener appends exactly one product-owned --extension.
  • Added PiManagedExtensionHost, a loopback-only HTTP bridge with one random bearer token per worker generation. Every request must match token, Conversation, generation, and active run; worker invalidation/dispose makes the token unusable and releases all owned or waiting resources. Active run binding is inherited synchronously by a replacement generation before its child process starts, closing the stale-rebuild race.
  • Added the self-contained extension ask_user tool for select, confirm, input, and editor requests. Pi's fire-and-forget extension_ui_response records now use a dedicated one-way transport seam rather than pretending to be request/response commands.
  • Added a Host-side PiInteractionStore with exact interaction/option correlation, current generation/run validation, terminal status projection, and generation-scoped abort/crash/dispose cancellation. Runtime dialog events pass through the store before entering product patches.
  • Added a FIFO PiProjectWriteLeaseCoordinator and extension hooks that make write, edit, and bash share one mutation lease per project. Reads and reasoning bypass it; different projects proceed in parallel. Tool result, agent end, session shutdown, abort, crash, recovery, dispose, and Host shutdown all reach an idempotent release path; waiting bridge requests are cancellable.
  • Added safe projection for notify/status/registered widget/title/editor-text events. Unknown widget/UI payloads become bounded method-only diagnostics; editor text is emitted only when the current draft revision still equals the run-start revision.
  • The Pi 0.84.2 real-child smoke now loads the materialized managed extension through Electron Node and confirms RPC readiness without extension-load or stdout-protocol failure. No real external Provider was contacted.
  • Planner review of initial candidate 3861c32 returned Needs Fix / Not Done with four deterministic supported-path findings. The correction closes each finding without changing the PI DAG: recover clears the old run before worker replacement and replacement only continues a run still active in the pool; interaction response ownership is atomic across double-submit and generation invalidation; Host close stops new connections, waits tracked request handlers, and terminates stale lease waiters; UI diagnostics retain only the newest 256 bounded entries.
  • Added exact regressions for active-run recover, delayed interaction send plus generation cancellation, holder+waiter Host shutdown, and 1,000 unknown UI events. All four planner reproductions now pass locally; PI-070 remains the sole frontier until planner re-review marks the correction Done.
  • Planner independent re-review of cumulative code HEAD 31de325cd8d41b9e0e46df2cb9759f6a5086c10c returned Pass with no remaining Standards or Spec finding. PI-070 is Done; the unchanged 18-node/31-edge graph and 134 unique requirements now expose the parallel Ready Frontier {PI-080, PI-090, PI-100}.
  • Real Provider validation remains Explicitly Waived / Accepted Risk with realTurnVerified=false; provider concurrency, credential isolation, and protocol compatibility are not Pass. macOS x64/arm64 remains deferred to PI-150 and is not Pass.

Verification

  • corepack pnpm run typecheck — passed.
  • corepack pnpm run lint:check — passed with 0 errors; the repository's 6 pre-existing React warnings remain outside PI-070.
  • Focused PI-070 plus predecessor regression suite — 9 files / 41 tests passed, covering worker transport/pool/runtime, exact interaction response, stale identity, loopback bridge, lease FIFO/cancellation, draft revision, and managed opener arguments.
  • corepack pnpm vitest run tests/unit/pi-extension-bundle.test.ts — 1/1 passed by loading the actual materialized bundle, executing its mutation hooks, and observing real bridge lease blocking/release; a read hook bypassed the lease.
  • corepack pnpm vitest run tests/unit/pi-worker-process-real.test.ts — 1/1 passed against locked @earendil-works/pi-coding-agent@0.84.2 through the Electron Node child process with the managed extension explicitly loaded.
  • corepack pnpm test — 199 files / 2192 tests passed before the final bundle integration test was added; that new test then passed independently, making all 200 current test files green across the two recorded runs.
  • Planner correction focused suite — 4 files / 9 tests passed, including all four deterministic review regressions.
  • Post-correction all-Pi run — 19 files / 91 tests passed; the existing pi-conversation-runtime Windows temporary JSON rename EPERM occurred in the aggregate run, then the same test passed 1/1 in isolation. No Pi behavior assertion failed.
  • Post-correction full suite — 199 files / 2194 tests passed; only that same pre-existing Windows temporary-file rename EPERM prevented a single green aggregate result. The affected runtime test passed immediately in isolation, so all 200 files / 2195 tests are green across the recorded aggregate plus isolated rerun. The failure is not in a PI-070-owned path and no retry or filesystem workaround was added.
  • Post-correction corepack pnpm run typecheck and lint:check — passed; lint remains 0 errors with the same 6 unrelated warnings.
  • Post-correction corepack pnpm run build:vite — passed for all four build targets with unchanged existing warnings.
  • Planner independent re-review — passed. It replayed all four original failures successfully, ran the complete correction regression at 4 files / 9 tests, and passed typecheck, scoped ESLint, build:vite, diff whitespace, project-doc, and drift checks. Source worktree and cumulative code HEAD were verified clean.
  • corepack pnpm run build:vite — passed for Renderer, Electron Main, Preload, and release utility output. Existing dynamic-import and chunk-size warnings remain unchanged.
  • git diff --check — passed.
  • Electron E2E was not applicable: PI-070 intentionally adds no Renderer or Host API route; PI-100/PI-130 own that user-visible wiring. macOS and real Provider checks were intentionally not run under the explicit decisions above.

Follow-ups

  • PI-080, PI-090, and PI-100 are now simultaneously Ready and may proceed in separate owned worktrees; the DAG imposes no order among them.
  • PI-100 must construct one shared PiManagedExtensionHost for the managed opener and PiConversationRuntime, expose sanitized interaction methods through Host API, and keep bridge tokens/leases Main-private.
  • PI-130 must consume safe UI projections, supply the actual per-Conversation draft revision, register only product-owned widget keys, and render terminal interaction states without exposing Pi wire payloads.
  • PI-080/PI-120 child workers must use this same project lease and worker-run identity model; they must not introduce a second per-child mutation lock.
  • PI-150 owns staging the managed extension in final packaged closures and the deferred macOS x64/arm64 matrix.
  • Real Provider concurrency, credential isolation, authentication, abort, image/model/session behavior, and protocol variation remain accepted unverified risks with realTurnVerified=false.

Promotion Candidates

  • Target: Pi runtime extension and process architecture. Proposal: retain discovery-disabled startup and load exactly one explicitly materialized, versioned Makelore extension; keep its loopback endpoint, bearer token registry, run context, interactions, and diagnostics inside Electron Main. Evidence: managed opener assertions, the locked Pi 0.84.2 real-child smoke, stale-token/generation bridge tests, and the actual-bundle integration test all pass. Future impact: PI-100 and PI-150 can wire Host routes and packaging without creating a project/user plugin surface or moving Pi protocol objects into Renderer. Semantic conflicts: canonical product-state documents still describe the active OpenCode product and must not claim Pi is live before the later cutover ticket is integrated. Human confirmation required: no for the internal architecture; yes before canonical product-state text claims the Pi cutover is released.
  • Target: Pi mutation concurrency architecture. Proposal: all parent and future child write/edit/bash executions for a project share one cancellable FIFO Main-owned lease; read-only tools and other projects bypass that queue. Evidence: coordinator and real HTTP/bundle tests prove same-project serialization, cross-project parallelism, cancellation, terminal release, and current-worker survival after stale identity rejection. Future impact: PI-080/PI-120 can add subagents without inventing competing locks or weakening project isolation. Semantic conflicts: none found. Human confirmation required: no.
  • Target: PI-130 draft and extension UI projection. Proposal: capture draft revision at run start and apply set_editor_text only if the revision is unchanged; accept status/widget projections only for registered product keys and retain bounded method-only diagnostics for unknown payloads. Evidence: focused projector tests prove accepted and stale draft paths plus unknown-widget suppression without raw details. Future impact: prevents asynchronous agent UI events from overwriting newer user edits and keeps extension detail schemas product-owned. Semantic conflicts: none found. Human confirmation required: no.