Refine config schema to discriminated union, document OpenCode options passthrough

Config is now a discriminated union on source.type:
- FileSource: { type: 'file', tasksPath?: string }
- ApiSource (future): { type: 'api', url: string }
- No config → default FileSource('tasks'), silent if missing

OpenCode passes plugin options as raw Record<string, unknown> with
no validation — the plugin validates with TypeBox at startup. This
means no extra config files, everything in opencode.json.

Updated plugin entry code to show resolveConfig with TypeBox Check/
Cast, type-appropriate error handling, and source factory integration.
This commit is contained in:
2026-04-28 10:28:13 +00:00
parent 34d1802d30
commit f8b7a2fc1b
2 changed files with 99 additions and 54 deletions

View File

@@ -102,21 +102,34 @@ Operations map to `@alkdev/taskgraph` functions, reading tasks from a `TaskSourc
## Plugin Config
Optional config via `opencode.json`:
Optional config via `opencode.json`. OpenCode passes the raw options object to the plugin — the plugin validates with TypeBox at startup.
```jsonc
// No config = default FileSource("tasks"), silent if directory missing
{
"plugin": ["@alkdev/open-tasks"]
}
// Explicit file source with custom path
{
"plugin": [
["@alkdev/open-tasks", {
"tasksPath": "tasks" // relative to workspace root (default: "tasks")
"source": { "type": "file", "tasksPath": "docs/tasks" }
}]
]
}
// Future: API source (secrets via env vars, not config)
// {
// "plugin": [
// ["@alkdev/open-tasks", {
// "source": { "type": "api", "url": "https://api.example.com/tasks" }
// }]
// ]
// }
```
If no config is provided, defaults to `"tasks"` (a `tasks/` directory relative to workspace root). Config is validated at runtime using TypeBox + `Value.Check`.
The `TaskSource` abstraction means operations never touch the filesystem directly — they call `source.load()`. This makes future sources (API endpoints, databases) swappable without changing any operation logic.
The `source.type` field is a discriminated union — each source type has its own config shape. Defaults to `{ type: "file", tasksPath: "tasks" }` if no config is provided. Secrets (API keys) come from environment variables, not config files.
## Local Development & Testing