diff --git a/AGENTS.md b/AGENTS.md index cbc86f2..9686f21 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -49,7 +49,4 @@ Avoid adding a provider if the target spec is unstable or undocumented. ## Repository Docs Convention -- **ADRs** live in `docs/decisions/` and are numbered with 4-digit zero-padding: `0001-short-title.md`, `0002-short-title.md`, etc. -- **Orchestrator run reports** live in `docs/reports/`. - -When recording a significant decision (new provider, output format change, merge strategy), create an ADR in `docs/decisions/` following the numbering sequence. +- **Plans** live in `docs/plans/` and track implementation progress. diff --git a/docs/decisions/0001-opencode-command-output-format.md b/docs/decisions/0001-opencode-command-output-format.md deleted file mode 100644 index 6788d71..0000000 --- a/docs/decisions/0001-opencode-command-output-format.md +++ /dev/null @@ -1,21 +0,0 @@ -# ADR 0001: OpenCode commands written as .md files, not in opencode.json - -## Status -Accepted - -## Date -2026-02-20 - -## Context -OpenCode supports two equivalent formats for custom commands. Writing to opencode.json requires overwriting or merging the user's config file. Writing .md files is additive and non-destructive. - -## Decision -The OpenCode target always emits commands as individual .md files in the commands/ subdirectory. The command key is never written to opencode.json by this tool. - -## Consequences -- Positive: Installs are non-destructive. Commands are visible as individual files, easy to inspect. Consistent with agents/skills handling. -- Negative: Users inspecting opencode.json won't see plugin commands; they must look in commands/. -- Neutral: Requires OpenCode >= the version with command file support (confirmed stable). - -## Plan Reference -Originated from: docs/plans/feature_opencode-commands_as_md_and_config_merge.md \ No newline at end of file diff --git a/docs/decisions/0002-opencode-json-merge-strategy.md b/docs/decisions/0002-opencode-json-merge-strategy.md deleted file mode 100644 index d17c3d2..0000000 --- a/docs/decisions/0002-opencode-json-merge-strategy.md +++ /dev/null @@ -1,21 +0,0 @@ -# ADR 0002: Plugin merges into existing opencode.json rather than replacing it - -## Status -Accepted - -## Date -2026-02-20 - -## Context -Users have existing opencode.json files with personal configuration. The install command previously backed up and replaced this file entirely, destroying user settings. - -## Decision -writeOpenCodeBundle reads existing opencode.json (if present), deep-merges plugin-provided keys without overwriting user-set values, and writes the merged result. User keys always win on conflict. - -## Consequences -- Positive: User config preserved across installs. Re-installs are idempotent for user-set values. -- Negative: Plugin cannot remove or update an MCP server entry if the user already has one with the same name. -- Neutral: Backup of pre-merge file is still created for safety. - -## Plan Reference -Originated from: docs/plans/feature_opencode-commands_as_md_and_config_merge.md \ No newline at end of file diff --git a/docs/decisions/0003-opencode-permissions-default-none.md b/docs/decisions/0003-opencode-permissions-default-none.md deleted file mode 100644 index 4c3039f..0000000 --- a/docs/decisions/0003-opencode-permissions-default-none.md +++ /dev/null @@ -1,21 +0,0 @@ -# ADR 0003: Global permissions not written to opencode.json by default - -## Status -Accepted - -## Date -2026-02-20 - -## Context -Claude commands carry allowedTools as per-command restrictions. OpenCode has no per-command permission mechanism. Writing per-command restrictions as global permissions is semantically incorrect and pollutes the user's global config. - -## Decision ---permissions defaults to "none". The plugin never writes permission or tools to opencode.json unless the user explicitly passes --permissions broad or --permissions from-command. - -## Consequences -- Positive: User's global OpenCode permissions are never silently modified. -- Negative: Users who relied on auto-set permissions must now pass the flag explicitly. -- Neutral: The "broad" and "from-command" modes still work as documented for opt-in use. - -## Plan Reference -Originated from: docs/plans/feature_opencode-commands_as_md_and_config_merge.md \ No newline at end of file diff --git a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-01-type-changes.md b/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-01-type-changes.md deleted file mode 100644 index 74376ed..0000000 --- a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-01-type-changes.md +++ /dev/null @@ -1,48 +0,0 @@ -# Phase 1 Handoff Report: Type Changes for Command Files - -**Date:** 2026-02-20 -**Phase:** 1 of 4 -**Status:** Complete - -## Summary - -Implemented type changes to support storing commands as `.md` files instead of inline in `opencode.json`. - -## Changes Made - -### 1. Type Changes (`src/types/opencode.ts`) - -- Removed `OpenCodeCommandConfig` type (lines 23-28) -- Removed `command?: Record` from `OpenCodeConfig` -- Added `OpenCodeCommandFile` type: - ```typescript - export type OpenCodeCommandFile = { - name: string - content: string - } - ``` -- Added `commandFiles: OpenCodeCommandFile[]` to `OpenCodeBundle` (with comment referencing ADR-001) - -### 2. Import Update (`src/converters/claude-to-opencode.ts`) - -- Removed `OpenCodeCommandConfig` from imports -- Added `OpenCodeCommandFile` to import - -### 3. Test Updates - -- `tests/converter.test.ts`: Updated 4 tests to use `bundle.commandFiles.find()` instead of `bundle.config.command` -- `tests/opencode-writer.test.ts`: Added `commandFiles: []` to all 4 bundle literals definitions - -## Test Status - -4 tests fail in `converter.test.ts` because the converter hasn't been updated yet to populate `commandFiles`. This is expected behavior - Phase 2 will fix these. - -``` -76 pass, 4 fail in converter.test.ts -``` - -## Next Steps (Phase 2) - -- Update converter to populate `commandFiles` instead of `config.command` -- Update writer to output `.md` files for commands -- Tests will pass after Phase 2 implementation \ No newline at end of file diff --git a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-02-convert-commands.md b/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-02-convert-commands.md deleted file mode 100644 index b2d4f4e..0000000 --- a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-02-convert-commands.md +++ /dev/null @@ -1,63 +0,0 @@ -# Phase 2 Handoff Report: Convert Commands to .md Files - -**Date:** 2026-02-20 -**Phase:** 2 of 4 -**Status:** Complete - -## Summary - -Implemented `convertCommands()` to emit `.md` command files with YAML frontmatter and body, rather than returning a `Record`. Updated `convertClaudeToOpenCode()` to populate `commandFiles` in the bundle instead of `config.command`. - -## Changes Made - -### 1. Converter Function (`src/converters/claude-to-opencode.ts`) - -- **Renamed variable** (line 69): `commandFile` (was `commandMap`) -- **Removed config.command**: Config no longer includes `command` field -- **Added commandFiles to return** (line 83): `commandFiles: cmdFiles` - -New `convertCommands()` function (lines 116-132): -```typescript -// Commands are written as individual .md files rather than entries in opencode.json. -// Chosen over JSON map because opencode resolves commands by filename at runtime (ADR-001). -function convertCommands(commands: ClaudeCommand[]): OpenCodeCommandFile[] { - const files: OpenCodeCommandFile[] = [] - for (const command of commands) { - if (command.disableModelInvocation) continue - const frontmatter: Record = { - description: command.description, - } - if (command.model && command.model !== "inherit") { - frontmatter.model = normalizeModel(command.model) - } - const content = formatFrontmatter(frontmatter, rewriteClaudePaths(command.body)) - files.push({ name: command.name, content }) - } - return files -} -``` - -### 2. Test Updates (`tests/converter.test.ts`) - -- **Renamed test** (line 11): `"from-command mode: map allowedTools to global permission block"` (was `"maps commands, permissions, and agents"`) -- **Added assertion** (line 19): `expect(bundle.config.command).toBeUndefined()` -- **Renamed test** (line 204): `"excludes commands with disable-model-invocation from commandFiles"` (was `"excludes commands with disable-model-invocation from command map"`) -- **Added new test** (lines 289-307): `"command .md files include description in frontmatter"` - validates YAML frontmatter `description` field and body content - -## Test Status - -All 11 converter tests pass: -``` -11 pass, 0 fail in converter.test.ts -``` - -All 181 tests in the full suite pass: -``` -181 pass, 0 fail -``` - -## Next Steps (Phase 3) - -- Update writer to output `.md` files for commands to `.opencode/commands/` directory -- Update config merge to handle command files from multiple plugins sources -- Ensure writer tests pass with new output structure \ No newline at end of file diff --git a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-03-write-command-files.md b/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-03-write-command-files.md deleted file mode 100644 index 84fc3e3..0000000 --- a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-03-write-command-files.md +++ /dev/null @@ -1,54 +0,0 @@ -# Phase 3 Handoff Report: Write Command Files as .md - -## Date -2026-02-20 - -## Phase -3 of feature: OpenCode Commands as .md Files, Config Merge, and Permissions Default Fix - -## Summary - -Implemented the `commandsDir` path resolution and command file writing in `src/targets/opencode.ts`. - -## Changes Made - -### 1. Updated `src/targets/opencode.ts` - -**Added `commandDir` to path resolver:** -- In global branch (line 52): Added `commandDir: path.join(outputRoot, "commands")` with inline comment -- In custom branch (line 66): Added `commandDir: path.join(outputRoot, ".opencode", "commands")` with inline comment - -**Added command file writing logic (line 24-30):** -- Iterates `bundle.commandFiles` -- Writes each command as `/.md` with trailing newline -- Creates backup before overwriting existing files - -### 2. Added tests in `tests/opencode-writer.test.ts` - -- `"writes command files as .md in commands/ directory"` - Tests global-style output (`.config/opencode`) -- `"backs up existing command .md file before overwriting"` - Tests backup creation - -## Test Results - -``` -bun test tests/opencode-writer.test.ts -6 pass, 0 fail -``` - -All existing tests continue to pass: -``` -bun test -183 pass, 0 fail -``` - -## Deliverables Complete - -- [x] Updated `src/targets/opencode.ts` with commandDir path and write logic -- [x] New tests in `tests/opencode-writer.test.ts` -- [x] All tests pass - -## Notes - -- Used `openCodePaths` instead of `paths` variable name to avoid shadowing the imported `path` module -- Command files are written with trailing newline (`content + "\n"`) -- Backup uses timestamp format `.bak.2026-02-20T...` \ No newline at end of file diff --git a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-04-merge-config.md b/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-04-merge-config.md deleted file mode 100644 index 86abf0e..0000000 --- a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-04-merge-config.md +++ /dev/null @@ -1,45 +0,0 @@ -# Phase 4 Handoff: Deep-Merge opencode.json - -**Date:** 2026-02-20 -**Status:** Complete - -## Summary - -Implemented `mergeOpenCodeConfig()` function that performs deep-merge of plugin config into existing opencode.json with user-wins-on-conflict strategy. - -## Changes Made - -### 1. Updated `src/targets/opencode.ts` - -- Added imports for `pathExists`, `readJson`, and `OpenCodeConfig` type -- Added `mergeOpenCodeConfig()` function before `writeOpenCodeBundle()` -- Replaced direct `writeJson()` call with merge logic - -### 2. Updated `tests/opencode-writer.test.ts` - -- Renamed existing backup test to `"merges plugin config into existing opencode.json without destroying user keys"` -- Added two new tests: - - `"merges mcp servers without overwriting user entry"` - - `"preserves unrelated user keys when merging opencode.json"` - -## Verification - -All 8 tests pass: -``` -bun test tests/opencode-writer.test.ts -8 pass, 0 fail -``` - -## Key Behaviors - -1. **User keys preserved**: All existing config keys remain intact -2. **MCP merge**: Plugin MCP servers added, user servers kept on conflict -3. **Permission merge**: Plugin permissions added, user permissions kept on conflict -4. **Tools merge**: Plugin tools added, user tools kept on conflict -5. **Fallback**: If existing config is malformed JSON, writes plugin-only config (safety first) -6. **Backup**: Original config is still backed up before writing merged result - -## Next Steps - -- Proceed to next phase (if any) -- Consider adding decision log entry for ADR-002 (user-wins-on-conflict strategy) \ No newline at end of file diff --git a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-05-permissions-default.md b/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-05-permissions-default.md deleted file mode 100644 index 191b1f1..0000000 --- a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-05-permissions-default.md +++ /dev/null @@ -1,35 +0,0 @@ -# Phase 5 Handoff: Change `--permissions` Default to `"none"` - -## Summary - -Changed the default value of `--permissions` from `"broad"` to `"none"` in the install command to prevent polluting user OpenCode config with global permissions. - -## Changes Made - -### 1. Code Change (`src/commands/install.ts`) - -- Line 51: Changed `default: "broad"` to `default: "none"` with comment referencing ADR-003 -- Line 52: Updated description to clarify "none (default)" - -```typescript -permissions: { - type: "string", - default: "none", // Default is "none" -- writing global permissions to opencode.json pollutes user config. See ADR-003. - description: "Permission mapping written to opencode.json: none (default) | broad | from-command", -}, -``` - -### 2. New Tests (`tests/cli.test.ts`) - -Added two new tests: -1. `"install --to opencode uses permissions:none by default"` - Verifies no `permission` or `tools` keys in opencode.json when using default -2. `"install --to opencode --permissions broad writes permission block"` - Verifies `permission` key is written when explicitly using `--permissions broad` - -## Test Results - -- CLI tests: 12 pass, 0 fail -- All tests: 187 pass, 0 fail - -## Next Steps - -None - Phase 5 is complete. \ No newline at end of file diff --git a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-06-update-docs.md b/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-06-update-docs.md deleted file mode 100644 index eafdca0..0000000 --- a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-phase-06-update-docs.md +++ /dev/null @@ -1,29 +0,0 @@ -# Phase 6: Update AGENTS.md and README.md - -**Date:** 2026-02-20 -**Status:** Complete - -## Summary - -Updated documentation to reflect the three changes from the feature: -- OpenCode commands written as individual `.md` files -- Deep-merge for `opencode.json` -- Command file backup before overwrite - -## Changes Made - -### AGENTS.md -- Line 10: Updated Output Paths description to include command files path and deep-merge behavior -- Added Repository Docs Convention section at end of file - -### README.md -- Line 54: Updated OpenCode output description to include command files and deep-merge behavior - -## Verification - -- Read updated files and confirmed accuracy -- Run `bun test` - no regressions - -## Next Steps - -- Ready for merge to main branch \ No newline at end of file diff --git a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-plan-amendment.md b/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-plan-amendment.md deleted file mode 100644 index 3cbee4a..0000000 --- a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-plan-amendment.md +++ /dev/null @@ -1,17 +0,0 @@ -# Plan Amendment Summary - -Overall adherence: HIGH -Phases with deviations: None - -## Deviations - -No deviations from the plan were made. All phases were implemented as specified. - -## Phases Implemented As Planned - -- Phase 01: Add OpenCodeCommandFile type and update OpenCodeBundle — no deviations -- Phase 02: Convert convertCommands() to emit .md command files — no deviations -- Phase 03: Add commandsDir to path resolver and write command files — no deviations -- Phase 04: Replace config overwrite with deep-merge — no deviations -- Phase 05: Change --permissions default to "none" — no deviations -- Phase 06: Update AGENTS.md and README.md — no deviations \ No newline at end of file diff --git a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-verification-report.md b/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-verification-report.md deleted file mode 100644 index 34a0f50..0000000 --- a/docs/reports/2026-02-20-opencode-command-md-merge/2026-02-20-verification-report.md +++ /dev/null @@ -1,37 +0,0 @@ -# Verification Report: OpenCode Commands as .md Files, Config Merge, and Permissions Default Fix - -## Verification Summary -Overall status: COMPLETE -Phases verified: 6 of 6 - -## Completed - -- **Phase 01: Type Changes for Command File** — Added `OpenCodeCommandFile` type and `commandFiles` field to `OpenCodeBundle`. Removed `OpenCodeCommandConfig` and `command` from `OpenCodeConfig`. Tests updated to use new bundle structure. - -- **Phase 02: Convert Commands to .md Files** — Implemented `convertCommands()` to return `OpenCodeCommandFile[]` with YAML frontmatter (`description`, `model`) and body. Removed `config.command` assignment. Updated tests verify commandFiles exist and command config is undefined. - -- **Phase 03: Write Command Files** — Added `commandDir` to path resolver (both global and custom branches). Implemented command file writing with backup-before-overwrite in `writeOpenCodeBundle()`. New tests verify file creation and backup. - -- **Phase 04: Deep-Merge Config** — Implemented `mergeOpenCodeConfig()` with user-wins-on-conflict strategy. Preserves user keys (`model`, `theme`, `provider`), merges MCP servers, handles malformed JSON with fallback. Updated tests verify merge behavior. - -- **Phase 05: Permissions Default to "none"** — Changed `--permissions` default from `"broad"` to `"none"` in install command. Added code comment referencing ADR-003. Tests verify no permission/tools written by default, and explicit `--permissions broad` works. - -- **Phase 06: Update Documentation** — Updated AGENTS.md line 10 with command path and deep-merge behavior. Added Repository Docs Convention section (lines 50-55). Updated README.md line 54 with complete behavior description. - -## Plan Amendment Verified -- The plan amendment documents confirms no deviations from the plan were made. All phases implemented as specified. - -## ADR Verification -- **ADR 0001:** `docs/decisions/0001-opencode-command-output-format.md` exists with correct content (Status: Accepted, Context, Decision, Consequences, Plan Reference) -- **ADR 0002:** `docs/decisions/0002-opencode-json-merge-strategy.md` exists with correct content (Status: Accepted, user-wins-on-conflict strategy documented) -- **ADR 0003:** `docs/decisions/0003-opencode-permissions-default-none.md` exists with correct content (Status: Accepted, --permissions default changed to "none") - -## Unresolved Open Issue -- None. All handoff reports show "Status: Complete" with no open issues remaining. - -## Test Results -``` -187 pass, 0 fail -577 expect() calls -Ran 187 tests across 21 files. -``` \ No newline at end of file diff --git a/docs/reports/2026-02-20-opencode-command-md-merge/decisions.md b/docs/reports/2026-02-20-opencode-command-md-merge/decisions.md deleted file mode 100644 index e3d398f..0000000 --- a/docs/reports/2026-02-20-opencode-command-md-merge/decisions.md +++ /dev/null @@ -1,281 +0,0 @@ -# Decision Log: OpenCode Commands as .md Files - -## Decision: ADR-001 - Store Commands as Individual .md Files - -**Date:** 2026-02-20 -**Status:** Adopted - -## Context - -The original design stored commands configurations inline in `opencode.json` under `config.command`. This tightly couples command metadata with config, making it harder to version-control commands separately and share command files. - -## Decision - -Store commands definitions as individual `.md` files in `.opencode/commands/` directory, with YAML frontmatter for metadata and markdown body for the command prompt. - -**New Type:** -```typescript -export type OpenCodeCommandFile = { - name: string // command name, used as filename stem: .md - content: string // full file content: YAML frontmatter + body -} -``` - -**Bundle Structure:** -```typescript -export type OpenCodeBundle = { - config: OpenCodeConfig - agents: OpenCodeAgentFile[] - commandFiles: OpenCodeCommandFile[] // NEW - plugins: OpenCodePluginFile[] - skillDirs: { sourceDir: string; name: string }[] -} -``` - -## Consequences - -- **Positive:** Commands can be versioned, shared, and edited independently -- **Negative:** Requires updating converter, writer, and all consumers -- **Migration:** Phase 1-4 will implement the full migration - -## Alternatives Considered - -1. Keep inline in config - Rejected: limits flexibility -2. Use separate JSON files - Rejected: YAML frontmatter is more idiomatic for command - ---- - -## Decision: Phase 2 - Converter Emits .md Files - -**Date:** 2026-02-20 -**Status:** Implemented - -## Context - -The converter needs to populate `commandFiles` in the bundle rather than `config.command`. - -## Decision - -`convertCommands()` returns `OpenCodeCommandFile[]` where each file contains: -- **filename**: `.md` -- **content**: YAML frontmatter (`description`, optionally `model`) + body (template text with Claude path rewriting) - -### Frontmatter Structure -```yaml ---- -description: "Review code changes" -model: openai/gpt-4o ---- - -Template text here... -``` - -### Filtering -- Commands with `disableModelInvocation: true` are excluded from output - -### Path Rewriting -- `.claude/` paths rewritten to `.opencode/` in body content (via `rewriteClaudePaths()`) - -## Consequences - -- Converter now produces command files ready for file-system output -- Writer phase will handle writing to `.opencode/commands/` directory -- Phase 1 type changes are now fully utilizeds - ---- - -## Decision: Phase 3 - Writer Writes Command .md Files - -**Date:** 2026-02-20 -**Status:** Implemented - -## Context - -The writer needs to write command files from the bundle to the file system. - -## Decision - -In `src/targets/opencode.ts`: -- Add `commandDir` to return value of `resolveOpenCodePaths()` for both branches -- In `writeOpenCodeBundle()`, iterate `bundle.commandFiles` and write each as `/.md` with backup-before-overwrite - -### Path Resolution - -- Global branch (basename is "opencode" or ".opencode"): `commandsDir: path.join(outputRoot, "commands")` -- Custom branch: `commandDir: path.join(outputRoot, ".opencode", "commands")` - -### Writing Logic - -```typescript -for (const commandFile of bundle.commandFiles) { - const dest = path.join(openCodePaths.commandDir, `${commandFile.name}.md`) - const cmdBackupPath = await backupFile(dest) - if (cmdBackupPath) { - console.log(`Backed up existing command file to ${cmdBackupPath}`) - } - await writeText(dest, commandFile.content + "\n") -} -``` - -## Consequences - -- Command files are written to `.opencode/commands/` or `commands/` directory -- Existing files are backed up before overwriting -- Files content includes trailing newline - -## Alternatives Considered - -1. Use intermediate variable for commandDir - Rejected: caused intermittent undefined errors -2. Use direct property reference `openCodePaths.commandDir` - Chosen: more reliable - ---- - -## Decision: ADR-002 - User-Wins-On-Conflict for Config Merge - -**Date:** 2026-02-20 -**Status:** Adopted - -## Context - -When merging plugin config into existing opencode.json, conflicts may occur (e.g., same MCP server name with different configuration). The merge strategy must decide which value wins. - -## Decision - -**User config wins on conflict.** When plugin and user both define the same key (MCP server name, permission, tool), the user's value takes precedence. - -### Rationale - -- Safety first: Do not overwrite user data with plugin defaults -- Users have explicit intent in their local config -- Plugins should add new entries without modifying user's existing setup -- Aligns with AGENTS.md principle: "Do not delete or overwrite user data" - -### Merge Algorithm - -```typescript -const mergedMcp = { - ...(incoming.mcp ?? {}), - ...(existing.mcp ?? {}), // existing takes precedence -} -``` - -Same pattern applied to `permission` and `tools`. - -### Fallback Behavior - -If existing `opencode.json` is malformed JSON, warn and write plugin-only config rather than crashing: -```typescript -} catch { - console.warn(`Warning: existing ${configPath} is not valid JSON. Writing plugin config without merging.`) - return incoming -} -``` - -## Consequences - -- Positive: User config never accidentally overwritten -- Positive: Plugin can add new entries without conflict -- Negative: Plugin cannot modify user's existing server configuration (must use unique names) -- Negative: Silent merge may mask configuration issues if user expects plugin override - -## Alternatives Considered - -1. Plugin wins on conflict - Rejected: would overwrite user data -2. Merge and combine arrays - Rejected: MCP servers are keyed object, not array -3. Fail on conflict - Rejected: breaks installation workflow - ---- - -## Decision: ADR-003 - Permissions Default "none" for OpenCode Output - -**Date:** 2026-02-20 -**Status:** Implemented - -## Context - -When installing a Claude plugin to OpenCode format, the `--permissions` flag determines whether permission/tool mappings is written to `opencode.json`. The previous default was `"broad"`, which writes global permissions to the user's config file. - -## Decision - -Change the default value of `--permissions` from `"broad"` to `"none"` in the install command. - -### Rationale - -- **User safety:** Writing global permissions to `opencode.json` pollutes user config and may grant unintended access -- **Principle alignment:** Follows AGENTS.md "Do not delete or overwrite user data" -- **Explicit opt-in:** Users must explicitly request `--permissions broad` to write permissions to their config -- **Backward compatible:** Existing workflows using `--permissions broad` continues to work - -### Implementation - -In `src/commands/install.ts`: -```typescript -permissions: { - type: "string", - default: "none", // Default is "none" -- writing global permissions to opencode.json pollutes user config. See ADR-003. - description: "Permission mapping written to opencode.json: none (default) | broad | from-command", -}, -``` - -### Test Coverage - -Added two CLI tests cases: -1. `install --to opencode uses permissions:none by default` - Verifies no `permission` or `tools` key in output -2. `install --to opencode --permissions broad writes permission block` - Verifies `permission` key is written when explicitly requested - -## Consequences - -- **Positive:** User config remains clean by default -- **Positive:** Explicit opt-in required for permission writing -- **Negative:** Users migrating from older versions need to explicitly use `--permissions broad` if they want permissions -- **Migration path:** Document the change in migration notes - -## Alternatives Considered - -1. Keep "broad" as default - Rejected: pollutes user config -2. Prompt user interactively - Rejected: break CLI automation -3. Write to separate file - Rejected: OpenCode expects permissions in opencode.json - ---- - -## Decision: Phase 6 - Documentation Update - -**Date:** 2026-02-20 -**Status:** Complete - -## Context - -All implementation phases complete. Documentation needs to reflect the final behavior. - -## Decision - -Update AGENTS.md and README.md: - -### AGENTS.md Changes - -1. **Line 10** - Updated Output Paths description: - ``` - - **Output Paths:** Keep OpenCode output at `opencode.json` and `.opencode/{agents,skills,plugins}`. For OpenCode, command go to `~/.config/opencode/commands/.md`; `opencode.json` is deep-merged (never overwritten wholesale). - ``` - -2. **Added Repository Docs Convention section** (lines 49-56): - ``` - ## Repository Docs Convention - - - **ADRs** live in `docs/decisions/` and are numbered with 4-digit zero-padding: `0001-short-title.md`, `0002-short-title.md`, etc. - - **Orchestrator run reports** live in `docs/reports/`. - - When recording a significant decision (new provider, output format change, merge strategy), create an ADR in `docs/decisions/` following the numbering sequence. - ``` - -### README.md Changes - -1. **Line 54** - Updated OpenCode output description: - ``` - OpenCode output is written to `~/.config/opencode` by default. Command are written as individual `.md` files to `~/.config/opencode/commands/.md`. Agent, skills, and plugin are written to the corresponding subdirectory alongside. `opencode.json` (MCP servers) is deep-merged into any existing file -- user keys such as `model`, `theme`, and `provider` are preserved, and user values win on conflicts. Command files are backed up before being overwritten. - ``` - -## Verification - -- Read updated files and confirmed accuracy -- Run `bun test` - no regression \ No newline at end of file diff --git a/docs/reports/index.md b/docs/reports/index.md deleted file mode 100644 index 1aafd6d..0000000 --- a/docs/reports/index.md +++ /dev/null @@ -1,3 +0,0 @@ -| Date | Run Directory | Plan Source | Summary | -|------|--------------|-------------|---------| -| 2026-02-20 | `opencode-commands-md-merge/` | `docs/plans/feature_opencode-commands_as_md_and_config_merge.md` | Implement OpenCode commands as .md files, deep-merge opencode.json, and change --permissions default to none | \ No newline at end of file