Park remaining local WIP on main. TUI archived, CLI/kernel edits, glass. Sort later. Broken is fine.
Neuron Soul CI / build (push) Failing after 4m34s
Neuron Soul CI / deploy (push) Failing after 12m13s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-24 14:07:23 -05:00
parent 2b8c89f097
commit e58cdd124c
278 changed files with 4326 additions and 1067 deletions
+3 -3
View File
@@ -3,8 +3,8 @@ import { Spec } from "../framework/spec"
declare const OPENCODE_CLI_NAME: string | undefined
export const Commands = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME : "opencode", {
description: "OpenCode 2.0 preview command line interface",
export const Commands = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME : "neuron", {
description: "Neuron command line interface",
commands: [
Spec.make("api", {
description: "Make a request to the running server",
@@ -41,7 +41,7 @@ export const Commands = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCO
],
}),
Spec.make("serve", {
description: "Start the v2 API server",
description: "Start the Neuron engine",
params: {
hostname: Flag.string("hostname").pipe(Flag.withDefault("127.0.0.1")),
port: Flag.integer("port").pipe(Flag.optional),
@@ -5,8 +5,10 @@ import { Daemon } from "../../services/daemon"
export default Runtime.handler(Commands, () =>
Effect.gen(function* () {
const daemon = yield* Daemon.Service
const transport = yield* daemon.transport()
const existing = process.env.NEURON_URL
const transport = existing
? { url: existing, headers: {} }
: yield* (yield* Daemon.Service).transport()
const { runTui } = yield* Effect.promise(() => import("../../tui"))
yield* runTui(transport)
}),
+14 -30
View File
@@ -1,13 +1,7 @@
import { NodeHttpServer } from "@effect/platform-node"
import { Credential } from "@opencode-ai/core/credential"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { PermissionSaved } from "@opencode-ai/core/permission/saved"
import { Context, Layer, Option } from "effect"
import { Option } from "effect"
import * as Effect from "effect/Effect"
import { HttpRouter, HttpServer } from "effect/unstable/http"
import { createServer } from "node:http"
import { createRoutes } from "@opencode-ai/server/routes"
import { boot } from "neuron/boot"
import { Server } from "neuron/server"
import { Commands } from "../commands"
import { Runtime } from "../../framework/runtime"
import { Daemon } from "../../services/daemon"
@@ -18,29 +12,19 @@ export default Runtime.handler(
return yield* Effect.scoped(
Effect.gen(function* () {
const daemon = yield* Daemon.Service
const address = yield* listen(input.hostname, input.port, yield* daemon.password())
if (input.register) yield* daemon.register(address)
console.log(`server listening on ${HttpServer.formatAddress(address)}`)
const hostname = input.hostname
const port = Option.getOrElse(input.port, () => 4096)
const { graph, sessions } = yield* Effect.promise(() => boot({ cwd: process.cwd() }))
const { server } = Server.serve({
port,
hostname,
deps: { graph, sessions, cwd: process.cwd() },
})
const url = `http://${hostname}:${server.port}`
if (input.register) yield* daemon.register(url)
console.log(`neuron engine · ${url}`)
return yield* Effect.never
}),
)
}),
)
function listen(hostname: string, port: Option.Option<number>, password: string) {
if (Option.isSome(port)) return bind(hostname, port.value, password)
const next = (port: number): ReturnType<typeof bind> =>
bind(hostname, port, password).pipe(
Effect.catch((error) => (port === 65_535 ? Effect.fail(error) : next(port + 1))),
)
return next(4096)
}
function bind(hostname: string, port: number, password: string) {
return Layer.build(
HttpRouter.serve(createRoutes(password), { disableListenLog: true, disableLogger: true }).pipe(
Layer.provideMerge(NodeHttpServer.layer(() => createServer(), { port, host: hostname })),
Layer.provide(AppNodeBuilder.build(LayerNode.group([Credential.node, PermissionSaved.node]))),
),
).pipe(Effect.map((context) => Context.get(context, HttpServer.HttpServer).address))
}
+32 -36
View File
@@ -1,24 +1,22 @@
import { Global } from "@opencode-ai/core/global"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import { createOpencodeClient } from "@opencode-ai/sdk/v2/client"
import { ServerAuth } from "@opencode-ai/server/auth"
import { Context, Effect, FileSystem, Layer, Option, Schedule, Schema, Scope } from "effect"
import { HttpServer } from "effect/unstable/http"
import { randomBytes, randomUUID } from "crypto"
import { spawn } from "node:child_process"
import os from "node:os"
import path from "path"
const VERSION = "0.1.0"
export interface Interface {
readonly client: () => Effect.Effect<ReturnType<typeof createOpencodeClient>, unknown>
readonly client: () => Effect.Effect<{ url: string }, unknown>
readonly transport: () => Effect.Effect<{ url: string; headers: RequestInit["headers"] }, unknown>
readonly start: () => Effect.Effect<string, Error>
readonly status: () => Effect.Effect<string | undefined>
readonly stop: () => Effect.Effect<void, unknown>
readonly password: (value?: string) => Effect.Effect<string, unknown>
readonly register: (address: HttpServer.Address) => Effect.Effect<void, unknown, Scope.Scope>
readonly register: (url: string) => Effect.Effect<void, unknown, Scope.Scope>
}
export class Service extends Context.Service<Service, Interface>()("@opencode/cli/Daemon") {}
export class Service extends Context.Service<Service, Interface>()("@neuron/cli/Daemon") {}
const Registration = Schema.Struct({
id: Schema.optional(Schema.String),
@@ -36,7 +34,7 @@ export const layer = Layer.effect(
Service,
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem
const directory = Global.Path.state
const directory = path.join(os.homedir(), ".neuron")
const file = path.join(directory, "server.json")
const passwordFile = path.join(directory, "password")
const decodeRegistration = Schema.decodeUnknownEffect(Schema.fromJsonString(Registration))
@@ -44,9 +42,6 @@ export const layer = Layer.effect(
const password = Effect.fn("cli.daemon.password")(function* (value?: string) {
const existing = yield* fs.readFileString(passwordFile).pipe(Effect.catch(() => Effect.succeed(undefined)))
if (value === undefined && existing) return existing
// Keep one private credential across server restarts so discovered clients
// can reconnect without exposing a password flag or environment variable.
const generated = value ?? randomBytes(32).toString("base64url")
const temp = passwordFile + ".tmp"
yield* fs.makeDirectory(directory, { recursive: true })
@@ -55,26 +50,26 @@ export const layer = Layer.effect(
return generated
})
const defaultUrl = () => process.env.NEURON_URL ?? `http://127.0.0.1:${process.env.NEURON_PORT ?? 4096}`
const registration = Effect.fnUntraced(function* () {
return yield* fs.readFileString(file).pipe(Effect.flatMap(decodeRegistration))
})
const createClient = Effect.fnUntraced(function* (url: string) {
return createOpencodeClient({ baseUrl: url, headers: ServerAuth.headers({ password: yield* password() }) })
const probe = Effect.fnUntraced(function* (url: string) {
const response = yield* Effect.tryPromise(() =>
fetch(new URL("/global/health", url), { signal: AbortSignal.timeout(2_000) }),
)
if (!response.ok) return yield* Effect.fail(new Error("Server is not healthy"))
const body = (yield* Effect.tryPromise(() => response.json())) as { ok?: boolean; healthy?: boolean }
if (body.ok === true || body.healthy === true) return url
return yield* Effect.fail(new Error("Server is not healthy"))
})
const healthy = Effect.fnUntraced(function* () {
const info = yield* registration()
const client = yield* createClient(info.url)
const response = yield* Effect.tryPromise(() => client.v2.health.get({ signal: AbortSignal.timeout(2_000) }))
if (response.data?.healthy === true) return info
return yield* Effect.fail(new Error("Registered server is not healthy"))
})
const compatible = Effect.fnUntraced(function* () {
const info = yield* healthy()
if (info.version === InstallationVersion) return info
return yield* Effect.fail(new Error("Registered server version does not match the client"))
yield* probe(info.url)
return info
})
const signal = (pid: number, signal: NodeJS.Signals) =>
@@ -110,10 +105,14 @@ export const layer = Layer.effect(
const start = Effect.fn("cli.daemon.start")(function* () {
const existing = yield* healthy().pipe(Effect.option)
const found = Option.getOrUndefined(existing)
const compiled = path.basename(process.execPath).replace(/\.exe$/, "") !== "bun"
if (found?.version === InstallationVersion && compiled) return found.url
if (found?.version === VERSION) return found.url
const live = yield* probe(defaultUrl()).pipe(Effect.option)
if (Option.isSome(live)) return live.value
if (found) yield* stopProcess(found).pipe(Effect.ignore)
const compiled = path.basename(process.execPath).replace(/\.exe$/, "") !== "bun"
const entrypoint = compiled ? undefined : process.argv[1]
if (!compiled && entrypoint === undefined)
return yield* Effect.fail(new Error("Failed to resolve CLI entrypoint"))
@@ -127,26 +126,25 @@ export const layer = Layer.effect(
catch: (cause) => new Error("Failed to start server", { cause }),
})
return yield* compatible().pipe(
return yield* probe(defaultUrl()).pipe(
Effect.retry(Schedule.spaced("50 millis").pipe(Schedule.both(Schedule.recurs(100)))),
Effect.map((info) => info.url),
Effect.mapError(() => new Error("Failed to start server")),
Effect.mapError(() => new Error(`Failed to start engine at ${defaultUrl()}`)),
)
})
const transport = Effect.fn("cli.daemon.transport")(function* () {
return { url: yield* start(), headers: ServerAuth.headers({ password: yield* password() }) }
return { url: yield* start(), headers: {} }
})
const client = Effect.fn("cli.daemon.client")(function* () {
const connection = yield* transport()
return createOpencodeClient({ baseUrl: connection.url, headers: connection.headers })
return { url: connection.url }
})
const status = Effect.fn("cli.daemon.status")(function* () {
const existing = yield* healthy().pipe(Effect.option)
const found = Option.getOrUndefined(existing)
if (found?.version === InstallationVersion) return found.url
if (found?.version === VERSION) return found.url
if (found) return undefined
yield* fs.remove(file).pipe(Effect.ignore)
return undefined
@@ -154,20 +152,18 @@ export const layer = Layer.effect(
const stop = Effect.fn("cli.daemon.stop")(function* () {
const existing = yield* healthy().pipe(Effect.option)
// A stale registration may point at a PID that has since been reused by
// another process. Only signal the PID after authenticating the server.
if (Option.isNone(existing)) return yield* fs.remove(file).pipe(Effect.ignore)
yield* stopProcess(existing.value)
yield* fs.remove(file).pipe(Effect.ignore)
})
const register = Effect.fn("cli.daemon.register")(function* (address: HttpServer.Address) {
const register = Effect.fn("cli.daemon.register")(function* (url: string) {
const id = randomUUID()
const temp = file + "." + id + ".tmp"
yield* fs.makeDirectory(directory, { recursive: true })
yield* fs.writeFileString(
temp,
JSON.stringify({ id, version: InstallationVersion, url: HttpServer.formatAddress(address), pid: process.pid }),
JSON.stringify({ id, version: VERSION, url, pid: process.pid }),
{ mode: 0o600 },
)
yield* fs.rename(temp, file)
+12 -5
View File
@@ -4,6 +4,7 @@ import { Effect } from "effect"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { Global } from "@opencode-ai/core/global"
/** TUI talks HTTP to the Neuron engine. Core is only used here for local TUI host paths. */
export function runTui(transport: { url: string; headers: RequestInit["headers"] }) {
const config = TuiConfig.resolve({}, { terminalSuspend: false })
return run({
@@ -27,11 +28,17 @@ const legacyDefaults: Record<string, unknown> = {
const gracefulFetch = Object.assign(
async (input: RequestInfo | URL, init?: RequestInit) => {
const response = await fetch(input, init)
if (response.status !== 404) return response
const fallback = legacyDefaults[new URL(input instanceof Request ? input.url : input).pathname]
if (fallback === undefined) return response
return Response.json(fallback)
try {
const response = await fetch(input, init)
if (response.status !== 404) return response
const fallback = legacyDefaults[new URL(input instanceof Request ? input.url : input).pathname]
if (fallback === undefined) return response
return Response.json(fallback)
} catch {
const path = new URL(input instanceof Request ? input.url : input).pathname
const fallback = legacyDefaults[path]
return Response.json(fallback ?? { error: "engine unreachable", path }, { status: 503 })
}
},
{ preconnect: fetch.preconnect },
)