feat: scaffold OpenCode V2 toolkit with safe project installer

This commit is contained in:
sargatxet committed 2026-10-08 12:14:43 +02:00
commit aac5627e98
30 files changed
+7533

No files matched your search

+187
View File
@@ -0,0 +1,187 @@
# Implementation plan: OpenCode Toolkit
## Objective
Create an independent, small OpenCode V2-native project using selected and
reviewed ECC skills, agent prompts, and workflows. The ECC fork remains a source
of reference, not a runtime dependency. The new package must be reproducible,
installable in a project, testable without a model provider, and explicit about
unverified behavior.
## Starting assumptions and decisions
- ECC source: `https://github.com/sargatxet/ECC`, commit
`ef648e01899ba3e8dc6371642deaaf64b4477775`, version 2.2.3, MIT.
- Runtime baseline: OpenCode 2.0.24, `@opencode/plugin` 2.0.24, Node.js
24.21.0 in the development environment; declared minimum Node.js 20.
- Scope: OpenCode V2 only for the initial release. No attempt to retain ECC's
Claude Code, Codex, or other harness installers.
- Distribution: one ESM package; project-local install first. Global/XDG
installation and npm publication are deferred.
- Provider and model selection remains user-owned. No credentials, model
defaults, or paid model calls are configured by this package.
- Content is selected and adapted, not copied wholesale. Preserve upstream
license text and per-file provenance.
## Initial scope
### Included
- Skills: `coding-standards`, `security-review`, `tdd-workflow`.
- Agents: planner, code reviewer, security reviewer.
- V2 plugin: `toolkit_project_status`, a read-only wrapper over OpenCode's VCS
context and status APIs.
- Project installer/uninstaller: copy the selected content, register the npm
plugin with a JSONC-preserving edit, track file ownership with SHA-256, reject
collisions and symlinks, and preserve modified files during uninstall.
- Unit tests, installer integration tests, coverage threshold, provenance,
operating documentation, FIXME and TODO tracking.
### Explicitly deferred
- ECC's V1 hook runtime, Claude-specific session discovery, continuous-learning
storage, instincts, memory vault, shell automation profiles, global installs,
multiple OpenCode config-layer reconciliation, npm publication, and
provider-backed E2E flows.
- Duplicating native OpenCode file, shell, search, delegation, and VCS tools when
a native API already satisfies the use case.
## Architecture
- `src/plugin.ts`: stable V2 `Plugin.define` entry point and namespaced tool.
- `src/installer/config.ts`: JSONC-safe plugin registration edits.
- `src/installer/project.ts`: project-local file staging, ownership manifest,
safe update, and conservative uninstall.
- `src/cli.ts`: `install` and `uninstall` commands.
- `content/skills/` and `content/agents/`: versioned content distributed with
the package.
- `test/`: Node test-runner tests for plugin API shape, config edits, install
idempotency, collisions, local edits, and symlink protection.
- `docs/PROVENANCE.md`: origin, commit, license, adaptations, and hashes.
## Work phases and acceptance criteria
### Phase 0 — Establish project and contract (complete)
- Create the separate repository without changing the ECC fork.
- Pin OpenCode SDK version 2.0.24 and establish a test/build baseline.
- Record package identity as provisional and document scope.
**Acceptance:** independent project builds; ECC source remains unchanged.
### Phase 1 — Select and import content (initial subset complete)
- Review each workflow for Claude-only paths, unavailable scripts, models, and
cross-references.
- Include supporting files, adapt frontmatter to native OpenCode agent format,
and record source SHA and file hashes.
- Confirm IDs are unique and are installed under `toolkit-*` names.
**Acceptance:** OpenCode discovers installed skills and agents; resources are
present; imported files have provenance and license attribution.
### Phase 2 — Prove V2 runtime (unit contract complete; real-runtime smoke open)
- Use `Plugin.define({ id, setup(ctx) })`, V2 transforms and documented VCS APIs.
- Avoid the V1 plugin callback, V1 event names, and module-global session state.
- Verify namespaced tool registration and output through contract tests.
- Test loading and unloading under an actual OpenCode 2.0.24 runtime.
**Acceptance:** installed package appears as one active plugin and the tool runs
in a real OpenCode session without a provider call to exercise the tool itself.
### Phase 3 — Implement project installer (initial behavior complete)
- Preflight all content and paths; reject collisions, non-regular files, and
symlinked install paths.
- Refuse simultaneous direct and `.opencode/` project config files until their
V2 merge behavior is handled safely.
- Preserve existing JSONC and unrelated settings.
- Write an ownership manifest with hashes; allow repeat installation only when
previously managed files remain unchanged.
- On updates, remove stale package-owned files only when their stored hash still
matches; keep locally edited stale files tracked and report them.
- Remove only package-owned, unmodified assets and a plugin entry the installer
originally added.
- Test clean install, re-run, collision, user-edited files, malformed config,
and symlink cases.
**Acceptance:** project install is idempotent; user files are not overwritten;
uninstall preserves locally modified content.
### Phase 4 — Validate distribution artifact (open)
- Build and pack the real package.
- Install its tarball into a clean project outside this repository.
- Check all imports/content/license files and load the plugin with OpenCode.
- Verify behavior in a project with pre-existing config and skills.
**Progress:** package tarball installs outside the checkout; the CLI is
idempotent and OpenCode discovers the three packaged agents. OpenCode 2.0.24's
standalone plugin API reports an empty active-plugin list, so the custom tool's
runtime activation still needs diagnosis.
**Acceptance:** no checkout symlink or development dependency is needed at
runtime; config collisions are handled or reported before writes; the V2 plugin
and its custom tool are confirmed active.
### Phase 5 — Document and release (documentation baseline complete)
- Document scope, installation, update/uninstall, compatibility, provenance,
and known limitations.
- Run deterministic checks and security review before release.
- Confirm package/repository names and get explicit approval before publishing.
**Acceptance:** another user can install from documented instructions and
verify the deterministic behavior without credentials.
### Phase 6 — Optional memory and learning features (not started)
- Design persistent memory and session-learning APIs separately.
- Prefer V2 public APIs over assumptions about OpenCode's storage layout.
- Add opt-in, scope controls, retention behavior, and isolation tests.
**Acceptance:** explicit consent and tests prove project/session/user data
cannot be mixed or silently uploaded.
## Verification strategy
### Deterministic, no-model checks
- `npm run typecheck`, `npm test`, coverage threshold, package dry-run.
- Plugin API contract tests using V2 types and V2-shaped context.
- Installer tests using isolated temporary projects.
- Real OpenCode config parse and plugin load smoke test.
- Tarball install test outside the repository.
### Provider-backed checks
- Load the three workflows; delegate to planner/reviewer; invoke skills; verify
model-visible permissions and agent behavior.
- These tests need a configured provider and may incur cost. They require an
explicit budget and must not be represented by mocks as passed.
## Risks and mitigations
- **OpenCode config precedence:** direct and `.opencode/` config files have
layered precedence. Test the actual 2.0.24 behavior before supporting complex
multi-file layouts; fail safely rather than silently hide user plugins.
- **Package dependency resolution:** tests against the source checkout can hide
missing package files. Validate an installed tarball.
- **Content drift:** selective copying creates manual sync work. Compare source
SHAs and hashes during updates; never auto-sync all of ECC.
- **Session data leaks:** do not use module-global mutable maps for session
state; add isolation tests before adding tracking or memory.
- **Permission weakening:** do not inherit ECC's auto-approval behavior without
an explicit V2 permission design and security review.
- **Uninstall partial failures:** file operations can fail mid-run; preserve the
manifest and report recovery instructions. Transactional rollback remains a
follow-up.
## Change management
For each ECC refresh, compare the pinned upstream revision, select changes
component-by-component, inspect dependencies and licensing, update hashes, and
run the full deterministic and runtime checks. Maintain a compatibility matrix
for OpenCode versions actually tested. Do not publish or push without explicit
authorization.
+28
View File
@@ -0,0 +1,28 @@
# ECC content provenance
## Source
- Repository: <https://github.com/affaan-m/ECC>
- Personal fork used for review: <https://github.com/sargatxet/ECC>
- Source revision: `ef648e01899ba3e8dc6371642deaaf64b4477775`
- ECC version: `2.2.3`
- License: MIT; original text preserved in [`../LICENSE-ECC`](../LICENSE-ECC).
- Adaptation policy: manually selected, reviewed, and adapted per component;
no runtime dependency on ECC and no automatic synchronization.
## Imported content and SHA-256
| Local path | ECC source path | Local SHA-256 | Adaptation |
|---|---|---|---|
| `content/skills/coding-standards/SKILL.md` | `.agents/skills/coding-standards/SKILL.md` | `c95acda94ff1d0f09795277f13953a054b61f090c563c6620ab56ef4d3caab73` | Removed pointers to skills not included in this curated package. |
| `content/skills/coding-standards/agents/openai.yaml` | `.agents/skills/coding-standards/agents/openai.yaml` | `647a4e888d750eb11e3c2b54190b68ea9eb7155f4f5dceb128e27221e4202d10` | Kept source metadata as provenance/supporting content; OpenCode ignores it. |
| `content/skills/security-review/SKILL.md` | `.agents/skills/security-review/SKILL.md` | `81d7a4cbf8509963539cbe2e3d3ecbde33077d9fa63bc7c8f6d09e7eb7531743` | Curated without upstream runtime code. |
| `content/skills/security-review/agents/openai.yaml` | `.agents/skills/security-review/agents/openai.yaml` | `40a07bb9a3933a13d4403e59d72426d5cc25ddd67a91f6fabee6f03c0721266b` | Kept source metadata as provenance/supporting content; OpenCode ignores it. |
| `content/skills/tdd-workflow/SKILL.md` | `.agents/skills/tdd-workflow/SKILL.md` | `cdeffd2636d59175c5146b2af43f314d986ef88542738e6f305e584122cf1f45` | Removed the ECC-only package-manager detector and Claude-specific environment assumptions. |
| `content/skills/tdd-workflow/agents/openai.yaml` | `.agents/skills/tdd-workflow/agents/openai.yaml` | `d68700053a6f3a4a65ec18e34bcef58e75986b5f8ae19f6e20e7412ccbd895a4` | Kept source metadata as provenance/supporting content; OpenCode ignores it. |
| `content/agents/toolkit-planner.md` | `.opencode/prompts/agents/planner.txt` | `ec8ed9b9c0d6f2d014ce77d59bb768562803cbdebdad4bd3c78166d097f15f21` | Added OpenCode agent frontmatter and toolkit-specific identity. |
| `content/agents/toolkit-code-reviewer.md` | `.opencode/prompts/agents/code-reviewer.txt` | `931ac839c2ab48a039798c4796fca01fd573e997b263df659f31ea49f19bd7a1` | Added native frontmatter and denied edit permissions for a read-only reviewer. |
| `content/agents/toolkit-security-reviewer.md` | `.opencode/prompts/agents/security-reviewer.txt` | `f0de5466b8422a8f6547c1760e6dc02ec3da3d69c2a7459ff0cc76bd56a021a4` | Added native frontmatter and denied edit permissions for a read-only reviewer. |
The source SHA is the reviewed ECC `main` revision at import time. Recompute
hashes after any local change and update this table in the same change.