mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-10-25 15:51:21 +00:00
## Summary This PR removes OpenCode compatibility code that nothing can reach any more: - Code that was already dead at the former 2.0.27 minimum, and is still dead at the current 2.1.0 minimum (#1029). - Handlers for events and data shapes that OpenCode V2 never produces. Each item was checked against the upstream 2.0.27 and 2.1.0 sources before removal. Kept on purpose: - Workarounds for upstream bugs or limits that are still present in 2.1.0. - Code that reads conversations written by older runtimes: V1-migrated tool names and metadata, `workspaceID` data, task summary titles, `session-legacy` replay. - Code that recognises and upgrades old CLIs and live older daemons: 1.x replacement, beta recognition, 2.0.11 service discovery, 2.0.15 native upgrade, `/api/status` and `/api/health` identification. ## Removed or changed **Server** - Negotiation: one "not modern → `canonical_api`" rule replaces the pre-2.0.4 legacy schema recognition, and runs before #1029's `native_contract` check. - The transport no longer rewrites `/api/status`. - Desktop skills no longer send the pre-2.0.4 `location` and `slash` fields. - The legacy `auth.json` usage fallback for daemons without `credential.list` (pre-2.0.20) is removed, along with its UI reason and the i18n key in 10 locales. A missing endpoint still fails safely. - Workspace selectors are rejected up front, without a native resolution request. - CLI service probes try `/api/info` first. An admitted daemon no longer costs two authenticated 404s on every check. **UI** - Remaining V1 `session.idle`/`session.status` branches: Missions store, pending discovery (UI and server), `eventAffectsMessages`. - `server.instance.disposed` and the now-unused `rehydrateInstance`. - The V1 `worktree.ready` envelope (the handler now reads the V2 shape). - V1 tool-state titles and the `success` status alias. - Part `time.start` and `time.end`. - Text stored as objects or segment arrays. - `deriveMessageStatus`. - The V1 `error.data.message` shape. - `projectID` and `location` fallbacks on `session.created`. - The replay-only `session.message.content.updated`. - The unreachable `output.answers` fallback. **Fixtures, Missions and docs** - Legacy branches removed from the location, fork, families, pruning and automation native fixtures. The WSL setup fixture now compares against the reported version instead of 2.0.11. - Unused 2.0.21 launch helpers removed. - The Missions native and trajectory fixtures also run on the minimum lane. - The capability proof checks the reported version. - Stale 2.0.2x labels now say "as of the 2.1.0 minimum". **Follow-ups from the #1029 post-merge review** - Test fixtures no longer send the ignored `recent: ""` compaction field (18 sites). - The manual compaction-isolation fixture accepts any published version at or above the minimum. - `CONTRIBUTING.md` wording updated. 114 files, +319 / −1117: source +90 / −487, tests/fixtures/CI +214 / −604, i18n −10, docs +15 / −16. ## Validation (rebased on dev with #1029) **Typechecks:** server and UI pass. **Server tests** - Touched areas: 480/480. - Full server CI step: 2430 pass, 0 fail, 7 skipped, 1 cancelled. The cancelled test is the `index.test.ts` real-process shutdown test; it hit its 5 s timeout under load. It passes alone (4/4), and that file is unchanged versus dev. **UI unit tests** - Touched files: 230/230. - CI steps: 574/574, 200/200 and 519/519. **Browser suites**, one at a time: - Provider and service usage: provider-usage 13/13, service-usage 3/3. - Missions: mission-visibility 3/3, mission-control-feedback 5/5, mission-lifecycle-revision 10/10, mission-lifecycle-navigation 10/10, mission-current-passage 1/1, mission-native-family 11/11. - Transcript and rendering: compaction-responsiveness 5/5, session-rendering 47/47, reasoning-collapse 3/3, render-cost 17/17, tool-images 4/4, system-messages 10/10. - Other: search-highlight 11 pass (1 skipped by its env gate), panel-extensions 13/13. **Native fixtures on an isolated 2.1.0 CLI:** location, session-fork, automation, session-pruning, missions native, missions trajectory, provider-usage, Missions capability proof and compaction-isolation all pass. The WSL setup fixture was not run (it needs a WSL distro with a Linux CLI). ## Left for later - `RuntimeIdentity.discovery` is now write-only. - `ownsLocation` has an unused `_client` parameter (about 30 callers). - A test-only V1 translation in `auto-accept-manager.test.ts`. - Out of scope: HTML-entity decoding (a product decision), the `MutableHashMap` loop, the pruning-UI import-order workaround, unused log-based Missions readers, and the unshipped managed-owner module with its 2.0.24-pinned test. Oversized source files touched: `stores/instances.ts` ~2,209, `message-block.tsx` ~1,601, `workspaces/manager.ts` ~1,104, `tool-call.css` ~1,047, `tool-call.tsx` ~865, `opencode-data.ts` ~865, `api-types.ts` ~784, `session-events.ts` ~606, `recurring-day-fixture.ts` ~535.
94 lines
5.7 KiB
JavaScript
94 lines
5.7 KiB
JavaScript
// Native location authority fixture. Invoke with an absolute CLI path, or call
|
|
// testNativeLocationIdentity from an already-isolated native test. No discovery,
|
|
// shared daemon, user config or non-fixture database is ever used.
|
|
import assert from "node:assert/strict"
|
|
import { spawn, execFileSync } from "node:child_process"
|
|
import { randomUUID } from "node:crypto"
|
|
import { mkdtemp, mkdir, writeFile } from "node:fs/promises"
|
|
import os from "node:os"
|
|
import path from "node:path"
|
|
import { fileURLToPath } from "node:url"
|
|
import { setTimeout as delay } from "node:timers/promises"
|
|
import { OpenCode } from "@opencode/client"
|
|
import { tsImport } from "tsx/esm/api"
|
|
import { testNativeWorktreeFamily } from "./test-worktree-families-native.mjs"
|
|
import { testNativeWorktreeManagement } from "./test-native-worktree-management.mjs"
|
|
import { testNativeEventRelay } from "./test-native-event-relay.mjs"
|
|
|
|
export async function testNativeLocationIdentity({ client, root, service }) {
|
|
const { locationRequestOptions } = await tsImport("../packages/server/src/opencode/compatibility/location.ts", import.meta.url)
|
|
const directory = path.join(root, `identity-project-${randomUUID()}`)
|
|
const worktree = path.join(root, `identity-worktree-${randomUUID()}`)
|
|
await mkdir(directory)
|
|
const git = (...args) => execFileSync("git", args, { cwd: directory, stdio: "pipe" })
|
|
git("init")
|
|
git("config", "user.name", "CodeNomad isolated fixture")
|
|
git("config", "user.email", "fixture@example.invalid")
|
|
await writeFile(path.join(directory, "fixture.txt"), "synthetic native identity fixture\n")
|
|
git("add", "fixture.txt")
|
|
git("commit", "-m", "Synthetic native identity fixture")
|
|
git("worktree", "add", "-b", "fixture-worktree", worktree)
|
|
const rootLocation = await client.location.get({ location: { directory } })
|
|
const worktreeLocation = await client.location.get({ location: { directory: worktree } })
|
|
assert.equal(rootLocation.project.id, worktreeLocation.project.id)
|
|
await testNativeEventRelay({ client, location: rootLocation, service })
|
|
await testNativeWorktreeFamily({ client, rootLocation, worktreeLocation })
|
|
await testNativeWorktreeManagement({ client, root })
|
|
await assert.rejects(client.location.get({ location: { directory } }, locationRequestOptions({ directory, workspaceID: "wrk_fixture_one" })))
|
|
console.log("PASS: native modern worktree location and obsolete-selector rejection")
|
|
}
|
|
|
|
export async function runIsolated(cli, run = testNativeLocationIdentity) {
|
|
if (!cli || !path.isAbsolute(cli)) throw new Error("Pass an absolute isolated CLI executable path")
|
|
const temporaryRoot = path.join(os.tmpdir(), "opencode")
|
|
await mkdir(temporaryRoot, { recursive: true })
|
|
const root = await mkdtemp(path.join(temporaryRoot, "codenomad-location-native-"))
|
|
const env = Object.fromEntries(Object.entries(process.env).filter(([key]) => !key.startsWith("OPENCODE_") && !key.startsWith("XDG_")))
|
|
for (const key of ["XDG_DATA_HOME", "XDG_CONFIG_HOME", "XDG_STATE_HOME", "XDG_CACHE_HOME"]) env[key] = path.join(root, key)
|
|
const password = randomUUID()
|
|
Object.assign(env, {
|
|
HOME: root, USERPROFILE: root, OPENCODE_TEST_HOME: root,
|
|
OPENCODE_DB: path.join(root, "fixture.db"), OPENCODE_CONFIG_DIR: path.join(root, "config"),
|
|
OPENCODE_SERVER_PASSWORD: password, OPENCODE_CONFIG_PROJECT_DISABLE: "1",
|
|
OPENCODE_DISABLE_MODELS_FETCH: "1", OPENCODE_DISABLE_FFF: "1", OPENCODE_CONFIG_CONTENT: "{}",
|
|
})
|
|
await mkdir(env.OPENCODE_CONFIG_DIR)
|
|
let output = ""
|
|
const child = spawn(cli, ["serve", "--hostname", "127.0.0.1", "--port", "0", "--log-level", "debug", "--print-logs"], {
|
|
cwd: root, env, windowsHide: true,
|
|
})
|
|
const stopped = new Promise(resolve => child.once("close", resolve))
|
|
child.stdout.on("data", data => { output += data })
|
|
child.stderr.on("data", data => { output += data })
|
|
console.log(`Isolated location fixture: ${root}`)
|
|
try {
|
|
const deadline = Date.now() + 30_000
|
|
while (!/http:\/\/127\.0\.0\.1:\d+/.test(output)) {
|
|
if (child.exitCode !== null || Date.now() > deadline) throw new Error(`Isolated daemon failed to start: ${output}`)
|
|
await delay(20)
|
|
}
|
|
const baseUrl = output.match(/http:\/\/127\.0\.0\.1:\d+/)[0]
|
|
const { OpenCodeCliService } = await tsImport("../packages/server/src/workspaces/opencode-cli-service.ts", import.meta.url)
|
|
const { runtimeIdentity } = await tsImport("../packages/server/src/opencode/compatibility/runtime.ts", import.meta.url)
|
|
// Replace only CLI discovery; exercise production authenticated health probes.
|
|
const lifecycle = new OpenCodeCliService({ label: "Fixture", timeoutMs: 30_000,
|
|
command: args => ({ command: cli, args, options: {} }),
|
|
}, { execFile: async (_file, args) => ({ stdout: args.at(-1) === "password" ? password : baseUrl, stderr: "" }) })
|
|
const endpoint = await lifecycle.discover()
|
|
const identity = runtimeIdentity(endpoint)
|
|
const { createRuntimeTransport } = await tsImport("../packages/server/src/opencode/compatibility/transport.ts", import.meta.url)
|
|
const transport = createRuntimeTransport(endpoint)
|
|
const client = OpenCode.make({ baseUrl, fetch: transport.fetch })
|
|
const connection = { endpoint, client, ...transport, assertCurrent() {}, invalidate() {} }
|
|
console.log(`Testing official runtime ${identity.version}`)
|
|
assert.equal((await client.server.info()).version, identity.version)
|
|
console.log(`PASS: production ${identity.discovery} discovery and canonical client.server.info()`)
|
|
await run({ client, connection, root })
|
|
} finally {
|
|
child.kill()
|
|
await stopped
|
|
await writeFile(path.join(root, "daemon.log"), output)
|
|
}
|
|
}
|
|
|
|
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) await runIsolated(process.argv[2])
|