fix: 修复 OpenCode 运行时启动与本地打包
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
# Task: Fix installed OpenCode ServeError and package runtime locally
|
||||
|
||||
## Identity
|
||||
|
||||
- Task ID: 20260808-opencode-serve-error-b71c
|
||||
- Mode: Feature
|
||||
- Branch: main
|
||||
- Worktree: D:\Datas\OthersProjects\makelore
|
||||
- Base commit: d092132d86b8366c948a76cc659a787bb10a65a3
|
||||
- Owner: codex
|
||||
- Status: Ready for Integration
|
||||
|
||||
## Scope
|
||||
|
||||
- Diagnose and fix the installed Makelore 1.0.0 OpenCode runtime startup failure on Windows in the current 2.0.0 source tree.
|
||||
- Verify the packaged-runtime requirement that OpenCode and its required runtime dependencies resolve from the Makelore installation directory.
|
||||
- Correlate Makelore/OpenCode logs, live process and TCP state, an isolated command-line reproduction, and the repository runtime-manager implementation.
|
||||
- Add regression coverage for an unhealthy occupied preferred port and for process-exit/port-release ordering.
|
||||
- Make packaged builds fail verification if OpenCode or Playwright MCP cannot execute from installation-local resources; do not introduce a system `PATH`, npm, or npx fallback.
|
||||
- Do not terminate the user's Makelore, project preview, or background development processes, and do not mutate user runtime data.
|
||||
|
||||
## Intent And Constraints
|
||||
|
||||
- Keep confirmed facts separate from likely mechanisms and unverified assumptions.
|
||||
- Do not expose provider tokens or other secrets while inspecting runtime diagnostics.
|
||||
- Preserve the product boundary: Electron Main owns OpenCode startup, runtime paths, configuration, and lifecycle.
|
||||
- Treat the installed 1.0.0 artifact and the 2.0.0 repository as distinct builds; verify shared lifecycle behavior against the installed minified Main bundle before attributing repository code.
|
||||
|
||||
## Outcome
|
||||
|
||||
- Confirmed that the installed runtime is `D:\Tools\泥土\niancode\Makelore\resources\opencode-ai\bin\opencode.exe` (`opencode-ai` 1.18.9, Windows x64 baseline) and that it runs successfully from the Unicode installation path without external Node or Bun on `PATH`.
|
||||
- Confirmed that the incident is not a missing executable or Unicode-path failure. The old artifact already launched OpenCode from its installation tree, but its packaging contract still allowed an `npx` MCP fallback, a packaged-Python override, and a system/missing uv path.
|
||||
- Reconstructed the failure: the old runtime PID 33188 stopped at 20:54:45 local time, provider-triggered restart reported that port 4096 had not been released at 20:54:48, and retries at 20:55:02 and 20:55:05 exited with `Unexpected error / ServeError`.
|
||||
- Confirmed live that `127.0.0.1:4096` remains in `LISTEN` with recorded owner PID 33188 even though that PID is absent from Process, CIM, and tasklist enumeration. TCP connects but the endpoint does not answer HTTP, so it is not a healthy attachable OpenCode server.
|
||||
- Reproduced the exact `Unexpected error / ServeError` and exit code 1 by occupying an isolated port before launching the same installed binary; the same binary and Makelore XDG data start successfully on a free isolated port.
|
||||
- Confirmed in both repository source and the installed minified Main bundle that the child `exit` handler clears `proc` and publishes `stopped` before `stop()` has established port release. A release timeout then leaves the manager in a stopped/no-proc state, and a later start retries the fixed occupied port.
|
||||
- A background `node.exe dev-server.js` process created through OpenCode at 20:13:04 remains alive after its parent disappeared. Inherited socket ownership is a high-confidence explanation for the ghost listener, but handle inheritance was not directly proven and remains an inference.
|
||||
- Changed the manager to probe the preferred port before launch, use OpenCode's `--port=0` fallback for an unhealthy occupied listener, parse and publish the actual listening URL/port, and use the actual port for health, stop, restart, API, CORS, and renderer status.
|
||||
- Changed stop/restart ordering so a managed child is not reported stopped until both process exit and port release are established. If an inherited ghost listener remains, restart records the release failure and starts a replacement on an OS-selected loopback port.
|
||||
- Serialized start/stop/restart in FIFO order, made queued stops cancel older starts, isolated late callbacks by runtime generation, and retained every known unreleased port across generations. This prevents late exits, startup timeouts, or a dynamic-port replacement from losing ownership of an older ghost listener.
|
||||
- Removed the production `npx` Playwright MCP fallback, made packaged Python and uv resolve from `resources`, injects their absolute paths at the front of the runtime environment, and makes missing packaged resources fail closed. The inherited project tool `PATH` remains available after the managed directories.
|
||||
- Pinned `opencode-ai` to 1.18.9, staged only the selected self-contained executable, removed duplicate Python/OpenCode payloads, and extended packaged-artifact verification across OpenCode, MCP, Python, and uv.
|
||||
- Made the Windows packaging path stage OpenCode explicitly for win32/x64 and added PE Machine checks for Makelore, OpenCode, Python, and uv so an ARM64 build host cannot silently produce a mixed-architecture x64 installer.
|
||||
- Built `release\Makelore-2.0.0-win-x64.exe`; the installed 1.0.0 client was intentionally not overwritten while it or its project preview may be active.
|
||||
|
||||
## Verification
|
||||
|
||||
- The regression tests first failed on fixed-port startup and premature `stopped`, then passed after the implementation. Final focused run: 5 files / 147 tests passed, including FIFO lifecycle ordering, start cancellation, late/stale exits, attached-process termination failure, and cross-generation ghost ports.
|
||||
- `pnpm run typecheck`: passed.
|
||||
- Scoped ESLint on every changed TypeScript/JavaScript file: passed.
|
||||
- `pnpm run build:vite`: passed.
|
||||
- `pnpm install --frozen-lockfile`: passed.
|
||||
- `pnpm run bundle:opencode`: passed; staged OpenCode reports exactly 1.18.9 with a sanitized system-only `PATH`.
|
||||
- Windows packaging via `node scripts/run-electron-builder.mjs --win --publish never`: passed.
|
||||
- Packaged-artifact verifier: passed for Electron-as-Node MCP execution, OpenCode version/hash/path, isolated Python module origins, and local uv 0.10.0.
|
||||
- New unpacked layout contains `resources\opencode-ai\bin\opencode.exe`, `resources\python`, and `resources\bin\uv.exe`; it has no nested OpenCode `node_modules`, duplicate Python tree, or unpacked OpenCode architecture copies.
|
||||
- Real packaged-runtime smoke test used isolated XDG directories, listened on OS-selected port 60604, listed sessions, and created a session successfully; the process stopped and the port was confirmed released.
|
||||
- Installer: 219,859,508 bytes; SHA-256 `95E4A644E5BCB584D4C9EB6127F00626CA0AB096FC4E36DB7126CE715E46599C`.
|
||||
- Full repository lint remains red only in pre-existing unrelated `MainLayout.tsx` and `chat-command-dialogs.test.tsx` findings. Full tests remain red in 19 unrelated environment/baseline cases (`zip` unavailable, missing test fixture, project-progress baseline, and image-canvas auth baseline); all changed focused suites pass.
|
||||
|
||||
## Follow-ups
|
||||
|
||||
- Install the newly built package only after saving work and fully exiting the old Makelore client. The fix no longer requires clearing the ghost 4096 listener, but a reboot remains the cleanest way to remove that inherited Windows listener if it persists.
|
||||
- The verified locality contract covers Makelore's built-in OpenCode runtime chain: OpenCode, Electron-as-Node Playwright MCP code, Python, and uv. User-selected browsers and arbitrary tools launched by a project or Agent remain explicit external prerequisites and are not claimed as bundled runtime dependencies.
|
||||
- Only Windows x64 packaging was built and smoke-tested in this task. Cross-platform and architecture-specific staging should receive separate artifact verification before making an equivalent macOS or Linux claim.
|
||||
|
||||
## Promotion Candidates
|
||||
|
||||
- Target: canonical OpenCode runtime lifecycle architecture and verification guidance.
|
||||
- Proposal: define `stopped` as both process-exited and managed-port-released; require a Windows ghost-listener regression and packaged-runtime path verification for every release.
|
||||
- Evidence: installed-client timeline, live TCP/process mismatch, exact occupied-port reproduction, and the matching manager exit/stop ordering.
|
||||
- Future impact: prevents provider changes or runtime restarts from permanently wedging AI programming on fixed port 4096.
|
||||
- Semantic conflicts: none identified.
|
||||
- Human confirmation required: no; the user requested the runtime fix and local packaging behavior.
|
||||
Reference in New Issue
Block a user