mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-03 16:56:33 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ec7c7a17ad |
@@ -110,6 +110,8 @@ async function writeConfig(dir: string, config: object, name = "opencode.json")
|
|||||||
|
|
||||||
const writeConfigEffect = (dir: string, config: object, name = "opencode.json") =>
|
const writeConfigEffect = (dir: string, config: object, name = "opencode.json") =>
|
||||||
Effect.promise(() => writeConfig(dir, config, name))
|
Effect.promise(() => writeConfig(dir, config, name))
|
||||||
|
const mkdirEffect = (dir: string) => Effect.promise(() => fs.mkdir(dir, { recursive: true }))
|
||||||
|
const writeTextEffect = (file: string, content: string) => Effect.promise(() => Filesystem.write(file, content))
|
||||||
|
|
||||||
function withProcessEnv<A, E, R>(key: string, value: string, effect: Effect.Effect<A, E, R>) {
|
function withProcessEnv<A, E, R>(key: string, value: string, effect: Effect.Effect<A, E, R>) {
|
||||||
return Effect.acquireUseRelease(
|
return Effect.acquireUseRelease(
|
||||||
@@ -671,27 +673,19 @@ it.instance("migrates mode field to agent field", () =>
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
test("loads config from .opencode directory", async () => {
|
it.instance("loads config from .opencode directory", () =>
|
||||||
await using tmp = await tmpdir({
|
Effect.gen(function* () {
|
||||||
init: async (dir) => {
|
const test = yield* TestInstance
|
||||||
const opencodeDir = path.join(dir, ".opencode")
|
yield* mkdirEffect(path.join(test.directory, ".opencode", "agent"))
|
||||||
await fs.mkdir(opencodeDir, { recursive: true })
|
yield* writeTextEffect(
|
||||||
const agentDir = path.join(opencodeDir, "agent")
|
path.join(test.directory, ".opencode", "agent", "test.md"),
|
||||||
await fs.mkdir(agentDir, { recursive: true })
|
|
||||||
|
|
||||||
await Filesystem.write(
|
|
||||||
path.join(agentDir, "test.md"),
|
|
||||||
`---
|
`---
|
||||||
model: test/model
|
model: test/model
|
||||||
---
|
---
|
||||||
Test agent prompt`,
|
Test agent prompt`,
|
||||||
)
|
)
|
||||||
},
|
|
||||||
})
|
const config = yield* Config.Service.use((svc) => svc.get())
|
||||||
await withTestInstance({
|
|
||||||
directory: tmp.path,
|
|
||||||
fn: async (ctx) => {
|
|
||||||
const config = await load(ctx)
|
|
||||||
expect(config.agent?.["test"]).toEqual(
|
expect(config.agent?.["test"]).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
name: "test",
|
name: "test",
|
||||||
@@ -699,18 +693,15 @@ Test agent prompt`,
|
|||||||
prompt: "Test agent prompt",
|
prompt: "Test agent prompt",
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
},
|
}),
|
||||||
})
|
)
|
||||||
})
|
|
||||||
|
|
||||||
test("agent markdown permission config preserves user key order", async () => {
|
it.instance("agent markdown permission config preserves user key order", () =>
|
||||||
await using tmp = await tmpdir({
|
Effect.gen(function* () {
|
||||||
init: async (dir) => {
|
const test = yield* TestInstance
|
||||||
const agentDir = path.join(dir, ".opencode", "agent")
|
yield* mkdirEffect(path.join(test.directory, ".opencode", "agent"))
|
||||||
await fs.mkdir(agentDir, { recursive: true })
|
yield* writeTextEffect(
|
||||||
|
path.join(test.directory, ".opencode", "agent", "ordered.md"),
|
||||||
await Filesystem.write(
|
|
||||||
path.join(agentDir, "ordered.md"),
|
|
||||||
`---
|
`---
|
||||||
permission:
|
permission:
|
||||||
bash: allow
|
bash: allow
|
||||||
@@ -719,28 +710,18 @@ permission:
|
|||||||
---
|
---
|
||||||
Ordered permissions`,
|
Ordered permissions`,
|
||||||
)
|
)
|
||||||
},
|
|
||||||
})
|
const config = yield* Config.Service.use((svc) => svc.get())
|
||||||
await withTestInstance({
|
|
||||||
directory: tmp.path,
|
|
||||||
fn: async (ctx) => {
|
|
||||||
const config = await load(ctx)
|
|
||||||
expect(Object.keys(config.agent?.ordered?.permission ?? {})).toEqual(["bash", "*", "edit"])
|
expect(Object.keys(config.agent?.ordered?.permission ?? {})).toEqual(["bash", "*", "edit"])
|
||||||
},
|
}),
|
||||||
})
|
)
|
||||||
})
|
|
||||||
|
|
||||||
test("loads agents from .opencode/agents (plural)", async () => {
|
it.instance("loads agents from .opencode/agents (plural)", () =>
|
||||||
await using tmp = await tmpdir({
|
Effect.gen(function* () {
|
||||||
init: async (dir) => {
|
const test = yield* TestInstance
|
||||||
const opencodeDir = path.join(dir, ".opencode")
|
yield* mkdirEffect(path.join(test.directory, ".opencode", "agents", "nested"))
|
||||||
await fs.mkdir(opencodeDir, { recursive: true })
|
yield* writeTextEffect(
|
||||||
|
path.join(test.directory, ".opencode", "agents", "helper.md"),
|
||||||
const agentsDir = path.join(opencodeDir, "agents")
|
|
||||||
await fs.mkdir(path.join(agentsDir, "nested"), { recursive: true })
|
|
||||||
|
|
||||||
await Filesystem.write(
|
|
||||||
path.join(agentsDir, "helper.md"),
|
|
||||||
`---
|
`---
|
||||||
model: test/model
|
model: test/model
|
||||||
mode: subagent
|
mode: subagent
|
||||||
@@ -748,21 +729,16 @@ mode: subagent
|
|||||||
Helper agent prompt`,
|
Helper agent prompt`,
|
||||||
)
|
)
|
||||||
|
|
||||||
await Filesystem.write(
|
yield* writeTextEffect(
|
||||||
path.join(agentsDir, "nested", "child.md"),
|
path.join(test.directory, ".opencode", "agents", "nested", "child.md"),
|
||||||
`---
|
`---
|
||||||
model: test/model
|
model: test/model
|
||||||
mode: subagent
|
mode: subagent
|
||||||
---
|
---
|
||||||
Nested agent prompt`,
|
Nested agent prompt`,
|
||||||
)
|
)
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
await withTestInstance({
|
const config = yield* Config.Service.use((svc) => svc.get())
|
||||||
directory: tmp.path,
|
|
||||||
fn: async (ctx) => {
|
|
||||||
const config = await load(ctx)
|
|
||||||
|
|
||||||
expect(config.agent?.["helper"]).toMatchObject({
|
expect(config.agent?.["helper"]).toMatchObject({
|
||||||
name: "helper",
|
name: "helper",
|
||||||
@@ -777,41 +753,30 @@ Nested agent prompt`,
|
|||||||
mode: "subagent",
|
mode: "subagent",
|
||||||
prompt: "Nested agent prompt",
|
prompt: "Nested agent prompt",
|
||||||
})
|
})
|
||||||
},
|
}),
|
||||||
})
|
)
|
||||||
})
|
|
||||||
|
|
||||||
test("loads commands from .opencode/command (singular)", async () => {
|
it.instance("loads commands from .opencode/command (singular)", () =>
|
||||||
await using tmp = await tmpdir({
|
Effect.gen(function* () {
|
||||||
init: async (dir) => {
|
const test = yield* TestInstance
|
||||||
const opencodeDir = path.join(dir, ".opencode")
|
yield* mkdirEffect(path.join(test.directory, ".opencode", "command", "nested"))
|
||||||
await fs.mkdir(opencodeDir, { recursive: true })
|
yield* writeTextEffect(
|
||||||
|
path.join(test.directory, ".opencode", "command", "hello.md"),
|
||||||
const commandDir = path.join(opencodeDir, "command")
|
|
||||||
await fs.mkdir(path.join(commandDir, "nested"), { recursive: true })
|
|
||||||
|
|
||||||
await Filesystem.write(
|
|
||||||
path.join(commandDir, "hello.md"),
|
|
||||||
`---
|
`---
|
||||||
description: Test command
|
description: Test command
|
||||||
---
|
---
|
||||||
Hello from singular command`,
|
Hello from singular command`,
|
||||||
)
|
)
|
||||||
|
|
||||||
await Filesystem.write(
|
yield* writeTextEffect(
|
||||||
path.join(commandDir, "nested", "child.md"),
|
path.join(test.directory, ".opencode", "command", "nested", "child.md"),
|
||||||
`---
|
`---
|
||||||
description: Nested command
|
description: Nested command
|
||||||
---
|
---
|
||||||
Nested command template`,
|
Nested command template`,
|
||||||
)
|
)
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
await withTestInstance({
|
const config = yield* Config.Service.use((svc) => svc.get())
|
||||||
directory: tmp.path,
|
|
||||||
fn: async (ctx) => {
|
|
||||||
const config = await load(ctx)
|
|
||||||
|
|
||||||
expect(config.command?.["hello"]).toEqual({
|
expect(config.command?.["hello"]).toEqual({
|
||||||
description: "Test command",
|
description: "Test command",
|
||||||
@@ -822,41 +787,30 @@ Nested command template`,
|
|||||||
description: "Nested command",
|
description: "Nested command",
|
||||||
template: "Nested command template",
|
template: "Nested command template",
|
||||||
})
|
})
|
||||||
},
|
}),
|
||||||
})
|
)
|
||||||
})
|
|
||||||
|
|
||||||
test("loads commands from .opencode/commands (plural)", async () => {
|
it.instance("loads commands from .opencode/commands (plural)", () =>
|
||||||
await using tmp = await tmpdir({
|
Effect.gen(function* () {
|
||||||
init: async (dir) => {
|
const test = yield* TestInstance
|
||||||
const opencodeDir = path.join(dir, ".opencode")
|
yield* mkdirEffect(path.join(test.directory, ".opencode", "commands", "nested"))
|
||||||
await fs.mkdir(opencodeDir, { recursive: true })
|
yield* writeTextEffect(
|
||||||
|
path.join(test.directory, ".opencode", "commands", "hello.md"),
|
||||||
const commandsDir = path.join(opencodeDir, "commands")
|
|
||||||
await fs.mkdir(path.join(commandsDir, "nested"), { recursive: true })
|
|
||||||
|
|
||||||
await Filesystem.write(
|
|
||||||
path.join(commandsDir, "hello.md"),
|
|
||||||
`---
|
`---
|
||||||
description: Test command
|
description: Test command
|
||||||
---
|
---
|
||||||
Hello from plural commands`,
|
Hello from plural commands`,
|
||||||
)
|
)
|
||||||
|
|
||||||
await Filesystem.write(
|
yield* writeTextEffect(
|
||||||
path.join(commandsDir, "nested", "child.md"),
|
path.join(test.directory, ".opencode", "commands", "nested", "child.md"),
|
||||||
`---
|
`---
|
||||||
description: Nested command
|
description: Nested command
|
||||||
---
|
---
|
||||||
Nested command template`,
|
Nested command template`,
|
||||||
)
|
)
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
await withTestInstance({
|
const config = yield* Config.Service.use((svc) => svc.get())
|
||||||
directory: tmp.path,
|
|
||||||
fn: async (ctx) => {
|
|
||||||
const config = await load(ctx)
|
|
||||||
|
|
||||||
expect(config.command?.["hello"]).toEqual({
|
expect(config.command?.["hello"]).toEqual({
|
||||||
description: "Test command",
|
description: "Test command",
|
||||||
@@ -867,9 +821,8 @@ Nested command template`,
|
|||||||
description: "Nested command",
|
description: "Nested command",
|
||||||
template: "Nested command template",
|
template: "Nested command template",
|
||||||
})
|
})
|
||||||
},
|
}),
|
||||||
})
|
)
|
||||||
})
|
|
||||||
|
|
||||||
it.instance("updates config and writes to file", () =>
|
it.instance("updates config and writes to file", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
|
|||||||
+2
-1
@@ -52,7 +52,7 @@ Repeated setup work, long sleeps/timeouts, serial integration tests, filesystem/
|
|||||||
## Hypothesis Loop
|
## Hypothesis Loop
|
||||||
|
|
||||||
| Hypothesis | Change | Before | After | Decision | Notes |
|
| Hypothesis | Change | Before | After | Decision | Notes |
|
||||||
| --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | --------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
| --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | --------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| Repeated full-suite runs are too expensive for discovery | Switched full-suite benchmark to one run and added per-file profiler | ~250s/run | pending | keep | Bun has no slowest-test reporter in this version; profile files directly. |
|
| Repeated full-suite runs are too expensive for discovery | Switched full-suite benchmark to one run and added per-file profiler | ~250s/run | pending | keep | Bun has no slowest-test reporter in this version; profile files directly. |
|
||||||
| Plugin install concurrency test spends time spawning more workers than needed to exercise lock contention | Reduced worker counts from 12/10/8 to 6/6/5; kept `holdMs: 30` | 7.800s | 6.204s | keep | Median from 3 targeted runs; still covers concurrent cross-process writes to server, server+tui, and existing json config. |
|
| Plugin install concurrency test spends time spawning more workers than needed to exercise lock contention | Reduced worker counts from 12/10/8 to 6/6/5; kept `holdMs: 30` | 7.800s | 6.204s | keep | Median from 3 targeted runs; still covers concurrent cross-process writes to server, server+tui, and existing json config. |
|
||||||
| `httpapi-listen` PTY route tests pay for git repositories they do not assert on | Removed `git: true` from temp dirs while keeping config setup | 10.554s | 7.818s | keep | Median from 3 targeted runs; HTTP routes, tickets, websocket upgrade, restart, and no-auth paths still pass. |
|
| `httpapi-listen` PTY route tests pay for git repositories they do not assert on | Removed `git: true` from temp dirs while keeping config setup | 10.554s | 7.818s | keep | Median from 3 targeted runs; HTTP routes, tickets, websocket upgrade, restart, and no-auth paths still pass. |
|
||||||
@@ -75,6 +75,7 @@ Repeated setup work, long sleeps/timeouts, serial integration tests, filesystem/
|
|||||||
| Config template, file include, and simple agent cases can use Effect-aware instance fixtures | Migrated JSONC, env/file substitution, invalid config, and agent config cases to `it.instance` | 1.87s | 1.90s | keep | Stacked on the first config slice; neutral timing but removes more manual `tmpdir` + instance plumbing. |
|
| Config template, file include, and simple agent cases can use Effect-aware instance fixtures | Migrated JSONC, env/file substitution, invalid config, and agent config cases to `it.instance` | 1.87s | 1.90s | keep | Stacked on the first config slice; neutral timing but removes more manual `tmpdir` + instance plumbing. |
|
||||||
| Agent option, command, and legacy migration config cases can use Effect-aware instance fixtures | Migrated agent variant, command, autoshare, and mode migration cases to `it.instance` | 1.90s | 1.83s | keep | Stacked on the config template slice; small neutral-to-positive timing and less manual setup. |
|
| Agent option, command, and legacy migration config cases can use Effect-aware instance fixtures | Migrated agent variant, command, autoshare, and mode migration cases to `it.instance` | 1.90s | 1.83s | keep | Stacked on the config template slice; small neutral-to-positive timing and less manual setup. |
|
||||||
| Local config update and directory cases can use Effect-aware instance fixtures | Migrated local `update` and `directories` cases to `it.instance` | 1.77s | 1.71s | keep | Three-run medians; small positive/neutral timing, removes manual instance plumbing, and eliminates one existing unsafe cast. |
|
| Local config update and directory cases can use Effect-aware instance fixtures | Migrated local `update` and `directories` cases to `it.instance` | 1.77s | 1.71s | keep | Three-run medians; small positive/neutral timing, removes manual instance plumbing, and eliminates one existing unsafe cast. |
|
||||||
|
| `.opencode` agent and command file-loading cases can use Effect-aware instance fixtures | Migrated singular/plural agent and command markdown fixture cases to `it.instance` | 7.21s | 1.87s | keep | Parent baseline was noisy (7.42, 7.21, 2.83); after runs were stable at 1.87, 1.98, 1.83. Keep as cleanup with no broad claim. |
|
||||||
|
|
||||||
## Profiling Results
|
## Profiling Results
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user