Files
kilocode/packages/opencode/test/server/experimental-session-list.test.ts
T
Mark IJbema 5d5fab36bb fix(cli): repair broken imports and typecheck after opencode v1.14.29 merge
Fixes 257 typecheck errors surfaced after the upstream merge:

- Update imports to new module paths after upstream PR #24554 removed
  module barrel files (@/config, @/session, @/util, etc.) and PR #24309
  renamed @opencode-ai/shared to @opencode-ai/core.
- Migrate loadMode to use Info.zod.safeParse for consistency with
  loadAgents and ConfigCommand (unblocks KilocodeConfig.handleInvalid).
- Drop removed Npm.outdated mock from tests.
- Add missing Config.defaultLayer to bash-permission-metadata test runtime.
- Fix Tips component signature (kilocode drops upstream's 'connected' prop).
- Fix toast.tsx undefined 'duration' reference (should be toastOptions.duration).
- Move filesystem-containment test from deleted shared package to core.
2026-04-30 17:16:31 +02:00

159 lines
5.9 KiB
TypeScript

// kilocode_change - new file
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test"
import { $ } from "bun"
import path from "path"
import * as Config from "../../src/config/config"
import { Instance } from "../../src/project/instance"
import * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture"
import { RemoteSender } from "../../src/kilo-sessions/remote-sender"
beforeEach(() => {
spyOn(RemoteSender, "create").mockReturnValue({ handle() {}, dispose() {} })
})
Log.init({ print: false })
afterEach(async () => {
mock.restore()
await resetDatabase()
})
describe("experimental.session.list", () => {
test("filters sessions by repo worktree family even when project IDs drift", async () => {
await using first = await tmpdir({ git: true })
await using second = await tmpdir({ git: true })
const worktree = path.join(first.path, "..", path.basename(first.path) + "-worktree")
try {
await $`git worktree add ${worktree} -b test-branch-${Date.now()}`.cwd(first.path).quiet()
spyOn(Config, "get").mockImplementation(
async () => ({ share: "manual" }) as Awaited<ReturnType<typeof Config.get>>,
)
try {
const { Server } = await import("../../src/server/server")
const { Session } = await import("../../src/session/session")
// Create worktree session first so it computes its own project ID via rev-list
const branch = await Instance.provide({
directory: worktree,
fn: async () => Session.create({ title: "worktree-session" }),
})
// Now write a stale project ID to .git/kilo — this overrides the root's cached ID
await Bun.write(path.join(first.path, ".git", "kilo"), "stale-project-id")
const root = await Instance.provide({
directory: first.path,
fn: async () => ({
app: Server.Default().app,
project: await Server.Default().app.request("/project/current", {
headers: { "x-kilo-directory": first.path },
}),
session: await Session.create({ title: "root-session" }),
}),
})
await Bun.file(path.join(first.path, ".git", "kilo")).delete()
await Instance.provide({
directory: second.path,
fn: async () => Session.create({ title: "other-project-session" }),
})
const app = root.app
const project = await root.project.json()
const response = await app.request(
`/experimental/session?projectID=${encodeURIComponent(project.id)}&roots=true&worktrees=true`,
{
headers: { "x-kilo-directory": first.path },
},
)
expect(response.status).toBe(200)
const body = await response.json()
const ids = body.map((item: { id: string }) => item.id)
const dirs = body.map((item: { directory: string }) => item.directory)
expect(root.session.projectID).not.toBe(branch.projectID)
expect(project.id).toBe(root.session.projectID)
expect(ids).toContain(root.session.id)
expect(ids).toContain(branch.id)
expect(dirs).toContain(worktree)
expect(body.some((item: { title: string }) => item.title === "other-project-session")).toBe(false)
} finally {
mock.restore()
}
} finally {
await $`git worktree remove ${worktree}`.cwd(first.path).quiet().nothrow()
}
})
test("worktrees=true ignores SDK-injected directory query param", async () => {
await using first = await tmpdir({ git: true })
await using second = await tmpdir({ git: true })
const worktree = path.join(first.path, "..", path.basename(first.path) + "-worktree")
try {
await $`git worktree add ${worktree} -b test-branch-sdk-${Date.now()}`.cwd(first.path).quiet()
spyOn(Config, "get").mockImplementation(
async () => ({ share: "manual" }) as Awaited<ReturnType<typeof Config.get>>,
)
try {
const { Server } = await import("../../src/server/server")
const { Session } = await import("../../src/session/session")
const branch = await Instance.provide({
directory: worktree,
fn: async () => Session.create({ title: "worktree-session" }),
})
const root = await Instance.provide({
directory: first.path,
fn: async () => ({
app: Server.Default().app,
project: await Server.Default().app.request("/project/current", {
headers: { "x-kilo-directory": first.path },
}),
session: await Session.create({ title: "root-session" }),
}),
})
await Instance.provide({
directory: second.path,
fn: async () => Session.create({ title: "other-project-session" }),
})
const app = root.app
const project = await root.project.json()
// Include directory in query params — mimics what the SDK rewrite interceptor does.
// Without the server fix, this would restrict results to only first.path sessions.
const response = await app.request(
`/experimental/session?projectID=${encodeURIComponent(project.id)}&roots=true&worktrees=true&directory=${encodeURIComponent(first.path)}`,
{
headers: { "x-kilo-directory": first.path },
},
)
expect(response.status).toBe(200)
const body = await response.json()
const ids = body.map((item: { id: string }) => item.id)
// Both root and worktree sessions must be returned despite directory= in query
expect(ids).toContain(root.session.id)
expect(ids).toContain(branch.id)
expect(body.some((item: { title: string }) => item.title === "other-project-session")).toBe(false)
} finally {
mock.restore()
}
} finally {
await $`git worktree remove ${worktree}`.cwd(first.path).quiet().nothrow()
}
})
})