Skip to content

Commit 19bf6db

Browse files
authored
Merge branch 'dev' into feature/simplify-skill
2 parents 79ecda5 + ca354f8 commit 19bf6db

46 files changed

Lines changed: 3178 additions & 951 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bun.lock

Lines changed: 5 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

infra/stage.ts

Lines changed: 3 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,50 +5,9 @@ export const domain = (() => {
55
})()
66

77
export const zoneID = "430ba34c138cfb5360826c4909f99be8"
8-
export const deployAws = $app.stage === "production" || $app.stage === "dev" || $app.stage === "adam"
9-
10-
const githubActionsDeployRole = (() => {
11-
if ($app.stage !== "dev" && $app.stage !== "production") return
12-
13-
const provider = new aws.iam.OpenIdConnectProvider("GithubActionsOidcProvider", {
14-
url: "https://token.actions.githubusercontent.com",
15-
clientIdLists: ["sts.amazonaws.com"],
16-
})
17-
const role = new aws.iam.Role("GithubActionsDeployRole", {
18-
name: `opencode-${$app.stage}-github-actions-deploy`,
19-
maxSessionDuration: 3600,
20-
assumeRolePolicy: aws.iam.getPolicyDocumentOutput({
21-
statements: [
22-
{
23-
effect: "Allow",
24-
actions: ["sts:AssumeRoleWithWebIdentity"],
25-
principals: [{ type: "Federated", identifiers: [provider.arn] }],
26-
conditions: [
27-
{
28-
test: "StringEquals",
29-
variable: "token.actions.githubusercontent.com:aud",
30-
values: ["sts.amazonaws.com"],
31-
},
32-
{
33-
test: "StringEquals",
34-
variable: "token.actions.githubusercontent.com:sub",
35-
values: [`repo:anomalyco/opencode:environment:${$app.stage}`],
36-
},
37-
],
38-
},
39-
],
40-
}).json,
41-
})
42-
43-
new aws.iam.RolePolicyAttachment("GithubActionsDeployRoleAdmin", {
44-
role: role.name,
45-
policyArn: "arn:aws:iam::aws:policy/AdministratorAccess",
46-
})
47-
48-
return role
49-
})()
50-
51-
export const githubActionsDeployRoleArn = githubActionsDeployRole?.arn
8+
// Dev owns the shared AWS lake/stats infra for all non-production stages.
9+
export const awsStage = $app.stage === "production" ? "production" : "dev"
10+
export const deployAws = $app.stage === awsStage
5211

5312
new cloudflare.RegionalHostname("RegionalHostname", {
5413
hostname: domain,

nix/hashes.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"nodeModules": {
3-
"x86_64-linux": "sha256-6s5msV+dYMHHt9Gc/CqvCrUj8K7ELjxoAe6ejHSJo4I=",
4-
"aarch64-linux": "sha256-SP94UPy5LePd7ZdC3eENIXiozc67blpg1SN9Ug5yiv8=",
5-
"aarch64-darwin": "sha256-jv3lffiAQ5kxDAbXNavsHD+tjjdgT0dT0JxN0bWMYTE=",
6-
"x86_64-darwin": "sha256-aYNtcarg516ZmqaO62mnUZYiSyWt8rJjUHQslhrhGHM="
3+
"x86_64-linux": "sha256-gqXxbi1OwLoDSDtlmYWcTTPT/fqhVGb53JXS/9a1vWw=",
4+
"aarch64-linux": "sha256-+ARbWtOUDx0J5k55mmre/2kPekUsQtWWS0QZnyX6NTo=",
5+
"aarch64-darwin": "sha256-Q6ioI6lFUhNKogbvbtGWsZcXJfbRgUAWS5X2X4mKdg4=",
6+
"x86_64-darwin": "sha256-8K/hmcvXi9FGqprNbTKzMB80h5zZhO2TjOQbtve3ltQ="
77
}
88
}

packages/app/e2e/regression/session-timeline-collapse-state.spec.ts

Lines changed: 9 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { expect, test, type Locator, type Page, type Route } from "@playwright/test"
1+
import { expect, test, type Locator, type Page } from "@playwright/test"
2+
import { mockOpenCodeServer } from "../utils/mock-server"
23

34
const directory = "C:/OpenCode/TimelineStateRegression"
45
const projectID = "proj_timeline_state_regression"
@@ -299,39 +300,13 @@ function readExpanded(element: Element) {
299300
}
300301

301302
async function mockServer(page: Page, events: EventPayload[]) {
302-
await page.route("**/*", async (route) => {
303-
const url = new URL(route.request().url())
304-
const targetPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096"
305-
if (url.port !== targetPort) return route.fallback()
306-
307-
const path = url.pathname
308-
if (path === "/global/event") return sse(route, events.splice(0))
309-
if (
310-
path === "/global/config" ||
311-
path === "/config" ||
312-
path === "/provider/auth" ||
313-
path === "/mcp" ||
314-
path === "/session/status"
315-
)
316-
return json(route, {})
317-
if (
318-
["/skill", "/command", "/lsp", "/formatter", "/permission", "/question", "/vcs/status", "/vcs/diff"].includes(
319-
path,
320-
)
321-
)
322-
return json(route, [])
323-
if (path === "/provider") return json(route, provider())
324-
if (path === "/path")
325-
return json(route, { state: directory, config: directory, worktree: directory, directory, home: "C:/OpenCode" })
326-
if (path === "/project") return json(route, [project()])
327-
if (path === "/project/current") return json(route, project())
328-
if (path === "/agent") return json(route, [{ name: "build", mode: "primary" }])
329-
if (path === "/vcs") return json(route, { branch: "main", default_branch: "main" })
330-
if (path === "/session") return json(route, [session()])
331-
if (path === `/session/${sessionID}`) return json(route, session())
332-
if (/^\/session\/[^/]+\/(children|todo|diff)$/.test(path)) return json(route, [])
333-
if (path === `/session/${sessionID}/message`) return json(route, [userMessage, assistantMessage])
334-
return json(route, {})
303+
await mockOpenCodeServer(page, {
304+
directory,
305+
project: project(),
306+
provider: provider(),
307+
sessions: [session()],
308+
pageMessages: () => ({ items: [userMessage, assistantMessage] }),
309+
events: () => events.splice(0),
335310
})
336311
}
337312

@@ -372,24 +347,6 @@ function provider() {
372347
}
373348
}
374349

375-
function json(route: Route, body: unknown, headers?: Record<string, string>) {
376-
return route.fulfill({
377-
status: 200,
378-
contentType: "application/json",
379-
headers: { "access-control-allow-origin": "*", "access-control-expose-headers": "x-next-cursor", ...headers },
380-
body: JSON.stringify(body ?? null),
381-
})
382-
}
383-
384-
function sse(route: Route, events: EventPayload[]) {
385-
return route.fulfill({
386-
status: 200,
387-
contentType: "text/event-stream",
388-
headers: { "access-control-allow-origin": "*" },
389-
body: events.map((event) => `data: ${JSON.stringify(event)}\n\n`).join(""),
390-
})
391-
}
392-
393350
function base64Encode(value: string) {
394351
return Buffer.from(value, "utf8").toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "")
395352
}

packages/app/e2e/regression/session-timeline-context-resize.spec.ts

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { expect, test, type Page, type Route } from "@playwright/test"
1+
import { expect, test, type Page } from "@playwright/test"
2+
import { mockOpenCodeServer } from "../utils/mock-server"
23

34
const directory = "C:/OpenCode/ContextResizeRegression"
45
const projectID = "proj_context_resize_regression"
@@ -207,33 +208,12 @@ function contextTool(partID: string, messageID: string, tool: string, input: Rec
207208
}
208209

209210
async function mockServer(page: Page) {
210-
await page.route("**/*", async (route) => {
211-
const url = new URL(route.request().url())
212-
const targetPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096"
213-
if (url.port !== targetPort) return route.fallback()
214-
215-
const path = url.pathname
216-
if (path === "/global/event" || path === "/event") return sse(route)
217-
if (["/global/config", "/config", "/provider/auth", "/mcp", "/session/status"].includes(path))
218-
return json(route, {})
219-
if (
220-
["/skill", "/command", "/lsp", "/formatter", "/permission", "/question", "/vcs/status", "/vcs/diff"].includes(
221-
path,
222-
)
223-
)
224-
return json(route, [])
225-
if (path === "/provider") return json(route, provider())
226-
if (path === "/path")
227-
return json(route, { state: directory, config: directory, worktree: directory, directory, home: "C:/OpenCode" })
228-
if (path === "/project") return json(route, [project()])
229-
if (path === "/project/current") return json(route, project())
230-
if (path === "/agent") return json(route, [{ name: "build", mode: "primary" }])
231-
if (path === "/vcs") return json(route, { branch: "main", default_branch: "main" })
232-
if (path === "/session") return json(route, [session()])
233-
if (path === `/session/${sessionID}`) return json(route, session())
234-
if (/^\/session\/[^/]+\/(children|todo|diff)$/.test(path)) return json(route, [])
235-
if (path === `/session/${sessionID}/message`) return json(route, messages)
236-
return json(route, {})
211+
await mockOpenCodeServer(page, {
212+
directory,
213+
project: project(),
214+
provider: provider(),
215+
sessions: [session()],
216+
pageMessages: () => ({ items: messages }),
237217
})
238218
}
239219

@@ -282,19 +262,6 @@ function provider() {
282262
}
283263
}
284264

285-
function json(route: Route, body: unknown, headers?: Record<string, string>) {
286-
return route.fulfill({
287-
status: 200,
288-
contentType: "application/json",
289-
headers: { "access-control-allow-origin": "*", "access-control-expose-headers": "x-next-cursor", ...headers },
290-
body: JSON.stringify(body ?? null),
291-
})
292-
}
293-
294-
function sse(route: Route) {
295-
return route.fulfill({ status: 200, contentType: "text/event-stream", body: ": ok\n\n" })
296-
}
297-
298265
function base64Encode(value: string) {
299266
return Buffer.from(value, "utf8").toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "")
300267
}

packages/app/e2e/utils/mock-server.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export interface MockServerConfig {
1818
project: unknown
1919
sessions: ({ id: string } & Record<string, unknown>)[]
2020
pageMessages: (sessionId: string, limit: number, before?: string) => { items: unknown[]; cursor?: string }
21+
events?: () => unknown[]
2122
}
2223

2324
export async function mockOpenCodeServer(page: Page, config: MockServerConfig) {
@@ -43,7 +44,8 @@ export async function mockOpenCodeServer(page: Page, config: MockServerConfig) {
4344
if (url.port !== targetPort) return route.fallback()
4445

4546
const path = url.pathname
46-
if (path === "/global/event" || path === "/event") return sse(route)
47+
if (path === "/global/event" || path === "/event") return sse(route, config.events?.())
48+
if (path === "/global/health") return json(route, { healthy: true })
4749
if (emptyObject.has(path)) return json(route, {})
4850
if (emptyList.has(path)) return json(route, [])
4951
if (path in staticRoutes) return json(route, staticRoutes[path])
@@ -81,6 +83,10 @@ function json(route: Route, body: unknown, headers?: Record<string, string>) {
8183
})
8284
}
8385

84-
function sse(route: Route) {
85-
return route.fulfill({ status: 200, contentType: "text/event-stream", body: ": ok\n\n" })
86+
function sse(route: Route, events?: unknown[]) {
87+
return route.fulfill({
88+
status: 200,
89+
contentType: "text/event-stream",
90+
body: events?.map((event) => `data: ${JSON.stringify(event)}\n\n`).join("") || ": ok\n\n",
91+
})
8692
}
854 KB
Binary file not shown.

packages/app/src/app.tsx

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ import DirectoryLayout from "@/pages/directory-layout"
4646
import Layout from "@/pages/layout"
4747
import { ErrorPage } from "./pages/error"
4848
import { useCheckServerHealth } from "./utils/server-health"
49+
import { ServersProvider } from "./context/servers"
50+
51+
if (import.meta.env.VITE_OPENCODE_CHANNEL !== "prod") {
52+
document.body.classList.remove("text-12-regular")
53+
document.body.classList.add("font-(family-name:--font-family-text)", "text-[13px]", "font-[440]")
54+
}
4955

5056
const HomeRoute = lazy(() => import("@/pages/home"))
5157
const Session = lazy(() => import("@/pages/session"))
@@ -296,31 +302,29 @@ export function AppInterface(props: {
296302
disableHealthCheck?: boolean
297303
}) {
298304
return (
299-
<ServerProvider
300-
defaultServer={props.defaultServer}
301-
disableHealthCheck={props.disableHealthCheck}
302-
servers={props.servers}
303-
>
304-
<ConnectionGate disableHealthCheck={props.disableHealthCheck}>
305-
<ServerKey>
306-
<QueryProvider>
307-
<ServerSDKProvider>
308-
<ServerSyncProvider>
309-
<Dynamic
310-
component={props.router ?? Router}
311-
root={(routerProps) => <RouterRoot appChildren={props.children}>{routerProps.children}</RouterRoot>}
312-
>
313-
<Route path="/" component={HomeRoute} />
314-
<Route path="/:dir" component={DirectoryLayout}>
315-
<Route path="/" component={() => <Navigate href="session" />} />
316-
<Route path="/session/:id?" component={SessionRoute} />
317-
</Route>
318-
</Dynamic>
319-
</ServerSyncProvider>
320-
</ServerSDKProvider>
321-
</QueryProvider>
322-
</ServerKey>
323-
</ConnectionGate>
305+
<ServerProvider defaultServer={props.defaultServer} servers={props.servers}>
306+
<ServersProvider>
307+
<ConnectionGate disableHealthCheck={props.disableHealthCheck}>
308+
<ServerKey>
309+
<QueryProvider>
310+
<ServerSDKProvider>
311+
<ServerSyncProvider>
312+
<Dynamic
313+
component={props.router ?? Router}
314+
root={(routerProps) => <RouterRoot appChildren={props.children}>{routerProps.children}</RouterRoot>}
315+
>
316+
<Route path="/" component={HomeRoute} />
317+
<Route path="/:dir" component={DirectoryLayout}>
318+
<Route path="/" component={() => <Navigate href="session" />} />
319+
<Route path="/session/:id?" component={SessionRoute} />
320+
</Route>
321+
</Dynamic>
322+
</ServerSyncProvider>
323+
</ServerSDKProvider>
324+
</QueryProvider>
325+
</ServerKey>
326+
</ConnectionGate>
327+
</ServersProvider>
324328
</ServerProvider>
325329
)
326330
}

0 commit comments

Comments
 (0)