Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .context/DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<!-- INDEX:START -->
| Date | Decision |
|----|--------|
| 2026-05-11 | Embedded and separately-published harnesses use distinct CI and release pipelines |
| 2026-05-11 | Embedded foreign-language assets under internal/assets/ are intentional, not a smell |
| 2026-05-10 | Placeholder overrides use EXTEND not REPLACE semantics |
| 2026-05-10 | Editorial constitution at .context/ingest/KB-RULES.md, not CONSTITUTION.md |
Expand Down Expand Up @@ -139,6 +140,20 @@ For significant decisions:

-->

## [2026-05-11-211246] Embedded and separately-published harnesses use distinct CI and release pipelines

**Status**: Accepted

**Context**: ctx ships two kinds of artifact. Embedded harnesses (OpenCode plugin, Copilot CLI scripts, Claude/OpenCode/Copilot CLI skills, git trace hooks, etc.) live under internal/assets/, are //go:embed'd into the ctx Go binary, and reach users via 'ctx setup' writing their bytes to disk. Separately-published harnesses (currently just the VS Code extension under editors/vscode/) build to their own artifact (.vsix), publish to a third-party channel (VS Code Marketplace under publisher 'activememory'), version independently, and reach users via that channel's update mechanism. Until this session, the boundary was implicit: doc.go and embed_test.go talked only about the embedded tree; release.yml only built the Go binary; nothing in CI exercised the vscode extension at all. A reviewer's first read of internal/assets/integrations/ was 'this is a dumping ground' precisely because the contract was not documented.

**Decision**: Embedded and separately-published harnesses use distinct CI and release pipelines

**Rationale**: Conflating the two would have one of two consequences: (a) shoehorning vscode into //go:embed, which means baking a .vsix or its sources into the Go binary and writing them out at setup time -- bloating the binary with bytes most users never use, and forcing the Go release cadence onto something with its own marketplace cadence; or (b) leaving the vscode harness ungated 'because it's different' -- which is what we had, and which is how typos ship. The right move is to acknowledge the two patterns are first-class peers, give each a documented home (internal/assets/ vs. editors/<editor>/), and gate each in CI with the toolchain appropriate to its release pipeline (Go test/build/vet for embedded; npm ci + esbuild + tsc for vscode). Future harnesses pick a pattern explicitly at placement time rather than drifting.

**Consequence**: internal/assets/README.md now carries the 'Embedded vs. Separately-Published: At a Glance' table as the canonical reference. .github/workflows/ci.yml gained a vscode-extension job that gates the marketplace publish path. editors/vscode/README.md gained a 'Release' section with checklist and explicit notes on which CI gates protect the manual vsce publish. The two patterns are now first-class: a new harness must declare which it follows before placing files. Open implications: (1) anyone proposing to lift integrations/ out of internal/assets/ should re-read this decision -- the no-../ //go:embed constraint plus the pattern-asymmetry are the load-bearing reasons against; (2) the embedded-only quality gaps tracked in TASKS.md (shellcheck, PSScriptAnalyzer, skill frontmatter validity) and the separately-published quality gaps (vscode test rot, lint, vsce package dry-run) live in distinct gap-task clusters and should not be merged. Spec: specs/internal-assets-readme.md.

---

## [2026-05-11-000000] Embedded foreign-language assets under internal/assets/ are intentional, not a smell

**Status**: Accepted
Expand Down
11 changes: 11 additions & 0 deletions .context/LEARNINGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ DO NOT UPDATE FOR:
<!-- INDEX:START -->
| Date | Learning |
|----|--------|
| 2026-05-11 | tsc cross-tree include resolves node_modules from source file, not tsconfig |
| 2026-05-10 | Go compile/tool version mismatch comes from the cached toolchain, not the system Go |
| 2026-05-10 | An ongoing user's concrete workaround tax is the strongest validation evidence |
| 2026-05-10 | Lift renames alongside features when borrowing from battle-tested external designs |
Expand Down Expand Up @@ -140,6 +141,16 @@ DO NOT UPDATE FOR:

---

## [2026-05-11-202124] tsc cross-tree include resolves node_modules from source file, not tsconfig

**Context**: Set up tsc --noEmit gate for the embedded OpenCode plugin. tsconfig lived in tools/typecheck/opencode/; include pointed at internal/assets/integrations/opencode/plugin/index.ts via relative path. First run failed with 'Cannot find module @opencode-ai/plugin' even though node_modules was correctly populated in tools/typecheck/opencode/.

**Lesson**: When tsconfig.json sits in dir A but its 'include' points at .ts files in dir B, tsc resolves node_modules by walking up from each source file's location (dir B), NOT from the tsconfig's location (dir A). With moduleResolution: bundler the behavior is the same. The 'node_modules' that ships in dir A is invisible to a source file in a distant dir B.

**Application**: For any cross-tree tsc setup (typecheck gate for embedded source elsewhere in the repo, monorepo-style references, etc.), add explicit baseUrl + paths to the tsconfig. Example: baseUrl: '.', paths: { '@opencode-ai/plugin': ['./node_modules/@opencode-ai/plugin/dist/index.d.ts'], '@opencode-ai/plugin/*': ['./node_modules/@opencode-ai/plugin/dist/*'] }. Add typeRoots ['./node_modules/@types', './node_modules'] for good measure. The cost is some manual path mapping; the benefit is that node_modules can live wherever the tooling does, not next to the source.

---

## [2026-05-10-181418] Go compile/tool version mismatch comes from the cached toolchain, not the system Go

**Context**: Hit 'compile: version "go1.26.1" does not match go tool version "go1.26.2"' on every go build / go test / make lint, even with my changes stashed out. System Go was 1.26.2 (healthy); go.mod pinned 1.26.1, so Go's auto-toolchain feature had downloaded 1.26.1 to ~/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.26.1.darwin-arm64/. That cached toolchain was internally inconsistent: its compile binary and stdlib export data disagreed on version.
Expand Down
72 changes: 62 additions & 10 deletions .context/TASKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,31 @@ TASK STATUS LABELS:

## Phase 0 Grounding

- [-] Add TypeScript type-check step (bunx tsc --noEmit) for embedded
- [x] Add TypeScript type-check step (`tsc --noEmit`) for embedded
editor-plugin assets to CI; nothing currently
checks .opencode/plugins/ctx/index.ts before embedding
#priority:low #added:2026-04-26-152912 #skipped:2026-05-11 reason:
scope redirected — investigation produced
specs/internal-assets-readme.md and `internal/assets/README.md`
documenting the embed contract; original work respawned into four
discrete gap tasks below (TS type-check, shellcheck,
PSScriptAnalyzer, skill frontmatter validation).

- [ ] Add TypeScript `tsc --noEmit` gate for the embedded OpenCode
checks `.opencode/plugins/ctx/index.ts` before embedding
#priority:low #added:2026-04-26-152912 #completed:2026-05-11
Implementation: `tools/typecheck/opencode/` (package.json,
tsconfig.json, README, package-lock.json); CI job
`typecheck-opencode-plugin` in `.github/workflows/ci.yml`; embed
contract documented in `internal/assets/README.md` and decision
recorded 2026-05-11. Investigation also surfaced three
related-but-distinct gap tasks (shellcheck, PSScriptAnalyzer,
skill frontmatter validation) listed below.

- [-] Add TypeScript `tsc --noEmit` gate for the embedded OpenCode
plugin (`internal/assets/integrations/opencode/plugin/index.ts`).
Place tooling (`package.json`, `tsconfig.json`) in a sibling
directory outside `internal/assets/` so it does not pollute the
embed surface; wire a CI step that installs Bun, `bun install`,
then `bunx tsc --noEmit`. Spec: respawn from
`specs/internal-assets-readme.md` open work.
#priority:low #added:2026-05-11 #grounding-gap
#skipped:2026-05-11 reason: duplicate of original line-30 task
above, which has now been completed end-to-end. CI uses `npm ci`
+ `npx tsc --noEmit` (matching the existing `editors/vscode/`
convention) rather than Bun; `tsc` is the same compiler either
way and `@types/bun` provides Bun globals to the type-checker.

- [ ] Add `shellcheck` gate for embedded shell scripts
(`internal/assets/integrations/copilot-cli/scripts/*.sh` and
Expand All @@ -65,6 +72,51 @@ TASK STATUS LABELS:
`internal/assets/read/skill/`. #priority:medium #added:2026-05-11
#grounding-gap

- [x] Add CI guardrails for the VS Code extension at
`editors/vscode/` (separately-published deliverable, ships via
VS Code Marketplace under publisher `activememory`, not embedded
into the ctx binary). CI job `vscode-extension` runs `npm ci`,
`npm run build` (esbuild bundle), and `npx tsc --noEmit
-p tsconfig.ci.json` (production code only; test file excluded
pending separate fix). README docs added: `internal/assets/README.md`
gained an "Embedded vs. Separately-Published" comparison; the
extension's own README gained a "Release" section documenting
the manual `vsce publish` flow and the CI gates that protect it.
#priority:medium #added:2026-05-11 #completed:2026-05-11
#grounding-gap

- [x] Close VS Code documentation parity gap: ctx had a dedicated
`docs/home/opencode.md` (185 lines) and `site/home/opencode/`
published page, but no equivalent for VS Code — the extension
was reduced to a 24-line install snippet inside
`docs/operations/integrations.md` plus the marketplace README.
A docs-site reader had no path to day-to-day usage. Created
`docs/home/vscode.md` mirroring the opencode page shape
(problem, setup, what gets created, automatic hooks,
status bar, slash commands by category, natural language,
auto-bootstrap, prerequisites, configuration, troubleshooting,
verification, what's next). Registered in `zensical.toml`'s
"Get Started" nav. Expanded the integrations.md VS Code
subsection to point at the new home page and added a
parallel "First-Class Citizen" block in
`docs/recipes/multi-tool-setup.md`. #priority:medium
#added:2026-05-11 #completed:2026-05-11 #grounding-gap

- [ ] Fix `editors/vscode/src/extension.test.ts` type errors and
re-enable test-file type-checking + vitest in CI. Two distinct
bugs: (1) tests import handlers (`handleComplete`, `handleTasks`,
`handleRemind`, `handlePad`, `handleNotify`, `handleSystem`,
`handleSpec`) that are no longer exported from `extension.ts`
(only `activate` and `deactivate` are exported now) — the test
suite is rotting against the actual extension surface; (2) the
`fakeToken` helper's `onCancellationRequested` mock signature
is `(cb: () => void) => …` but the VS Code API expects
`(e: any) => any` with at least one argument. Once fixed,
remove the `tsconfig.ci.json` carve-out and add `npm test` to
the `vscode-extension` CI job. Also worth adding `npm run lint`
(eslint) and a `vsce package` dry-run step.
#priority:medium #added:2026-05-11 #grounding-gap

- [ ] The target project (to be given to the Agent) has a good "phasing"
mechanism for tasks; implement that; maybe `ctx task add` can have a
`--phase` flag too, and we can have a auditor/normalizer for the current
Expand Down
48 changes: 48 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,51 @@ jobs:
with:
version: v2.11.4
args: --timeout=5m

typecheck-opencode-plugin:
name: Typecheck OpenCode plugin
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: tools/typecheck/opencode/package-lock.json

- name: Install dependencies
working-directory: tools/typecheck/opencode
run: npm ci

- name: Type-check embedded plugin
working-directory: tools/typecheck/opencode
run: npx tsc --noEmit

vscode-extension:
name: VS Code extension build + typecheck
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: editors/vscode/package-lock.json

- name: Install dependencies
working-directory: editors/vscode
run: npm ci

- name: Bundle (esbuild)
working-directory: editors/vscode
run: npm run build

- name: Type-check production code
working-directory: editors/vscode
run: npx tsc --noEmit -p tsconfig.ci.json
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ editors/vscode/node_modules/
editors/vscode/dist/
editors/vscode/*.vsix

# Type-check tooling for embedded plugins
tools/typecheck/opencode/node_modules/

# Some ideas are best kept hidden.
ideas
.context/.ctx.key
Expand Down
Loading
Loading