feat: 品牌替换 + 启动优化 + AGENTS.md 模板定制
- 品牌替换:OpenCode/opencode → AirCoding/aircoding(16+ 文件) - Logo ASCII art:修复 left/right 行数不匹配导致的启动崩溃 - 启动诊断:添加 OPENCODE_PRINT_TIMING 计时探针 - dev 模式默认 --pure 跳过外部插件加载 - AGENTS.md 模板:追加 AirCoding 多 Agent 专项段落 - architect prompt + plugin:强化 AGENTS.md 产出验证
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import { afterEach, describe, expect, test } from "bun:test"
|
||||
import { ConfigProvider, Layer } from "effect"
|
||||
import { HttpRouter } from "effect/unstable/http"
|
||||
import { EventPaths } from "../../src/server/routes/instance/httpapi/groups/event"
|
||||
import { PtyPaths } from "../../src/server/routes/instance/httpapi/groups/pty"
|
||||
import { HttpApiApp } from "../../src/server/routes/instance/httpapi/server"
|
||||
import { ServerAuth } from "../../src/server/auth"
|
||||
import { PtyID } from "@opencode-ai/core/pty/schema"
|
||||
import { resetDatabase } from "../fixture/db"
|
||||
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
|
||||
|
||||
function app(input: { password?: string; username?: string }) {
|
||||
const handler = HttpRouter.toWebHandler(
|
||||
HttpApiApp.routes.pipe(
|
||||
Layer.provide(
|
||||
ConfigProvider.layer(
|
||||
ConfigProvider.fromUnknown({
|
||||
OPENCODE_SERVER_PASSWORD: input.password,
|
||||
OPENCODE_SERVER_USERNAME: input.username,
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
{ disableLogger: true },
|
||||
).handler
|
||||
|
||||
return {
|
||||
fetch: (request: Request) => handler(request, HttpApiApp.context),
|
||||
request(input: string | URL | Request, init?: RequestInit) {
|
||||
return this.fetch(input instanceof Request ? input : new Request(new URL(input, "http://localhost"), init))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function basic(username: string, password: string) {
|
||||
return ServerAuth.header({ username, password }) ?? ""
|
||||
}
|
||||
|
||||
async function cancelBody(response: Response) {
|
||||
await response.body?.cancel().catch(() => {})
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
await disposeAllInstances()
|
||||
await resetDatabase()
|
||||
})
|
||||
|
||||
describe("HttpApi instance route authorization", () => {
|
||||
test("requires configured auth before opening the instance event stream", async () => {
|
||||
await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } })
|
||||
const server = app({ password: "secret" })
|
||||
const headers = { "x-opencode-directory": tmp.path }
|
||||
|
||||
const missing = await server.request(EventPaths.event, { headers })
|
||||
await cancelBody(missing)
|
||||
expect(missing.status).toBe(401)
|
||||
|
||||
const authed = await server.request(EventPaths.event, {
|
||||
headers: { ...headers, authorization: basic("opencode", "secret") },
|
||||
})
|
||||
await cancelBody(authed)
|
||||
expect(authed.status).toBe(200)
|
||||
})
|
||||
|
||||
test("requires configured auth before resolving the PTY websocket route", async () => {
|
||||
await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } })
|
||||
const server = app({ password: "secret" })
|
||||
const route = PtyPaths.connect.replace(":ptyID", PtyID.ascending())
|
||||
const headers = { "x-opencode-directory": tmp.path }
|
||||
|
||||
const missing = await server.request(route, { headers })
|
||||
await cancelBody(missing)
|
||||
expect(missing.status).toBe(401)
|
||||
|
||||
const authed = await server.request(route, {
|
||||
headers: { ...headers, authorization: basic("opencode", "secret") },
|
||||
})
|
||||
await cancelBody(authed)
|
||||
expect(authed.status).toBe(404)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user