Skip to content

Feat/opencode plugin tsc noemit#84

Merged
josealekhine merged 8 commits into
mainfrom
feat/opencode-plugin-tsc-noemit
May 12, 2026
Merged

Feat/opencode plugin tsc noemit#84
josealekhine merged 8 commits into
mainfrom
feat/opencode-plugin-tsc-noemit

Conversation

@josealekhine
Copy link
Copy Markdown
Member

No description provided.

The OpenCode plugin source at
`internal/assets/integrations/opencode/plugin/index.ts` is embedded
into the ctx binary as raw bytes (//go:embed) and deployed to the
user's `.opencode/plugins/ctx.ts` at install time. Without this gate,
a typo or a drift from the @opencode-ai/plugin SDK would ship as
bytes and fail only when Bun loads the plugin on a user's machine.

Implementation honors the embed contract from internal/assets/README.md:
the dev tooling lives outside the embed tree so it cannot pollute the
shipped payload.

Changes:

- tools/typecheck/opencode/: new dev-tooling directory (sibling to
  internal/assets/, not nested). Contains:
  - package.json -- devDependencies on @opencode-ai/plugin (Plugin
    type), @types/bun (BunShell globals), typescript.
  - tsconfig.json -- noEmit:true, strict, baseUrl/paths workaround
    for the cross-tree `include` so tsc resolves modules from this
    directory rather than from the embedded source file's location.
  - package-lock.json -- committed for reproducible CI installs
    (npm convention, matches editors/vscode/).
  - README.md -- documents the gate, what it catches, what it does
    not catch (runtime behavior, non-TS embedded assets, embed
    coverage which is gated separately by embed_test.go).

- .github/workflows/ci.yml: new job typecheck-opencode-plugin that
  runs `npm ci` then `npx tsc --noEmit`. Chose npm over Bun in CI
  to match the existing editors/vscode/ convention and to use the
  committed package-lock.json; tsc is the same compiler under
  either runner.

- .gitignore: tools/typecheck/opencode/node_modules/.

- .context/TASKS.md: original Phase 0 line-30 task marked [x]
  complete; the duplicate "spawned" task added in the previous
  commit marked [-] as duplicate of the now-completed original.
  The previous commit's "redirect by spawning four tasks"
  framing was thin deferral; this commit finishes the real
  work. Three of the four genuinely-new gap tasks (shellcheck,
  PSScriptAnalyzer, skill frontmatter) stay open.

- specs/internal-assets-readme.md: extended with an
  "Implementation Outcome" section recording what landed.

Spec: specs/internal-assets-readme.md
Signed-off-by: Jose Alekhinne <jose@ctx.ist>
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). Hit this setting up the OpenCode plugin typecheck gate
in commit b2f49bf. Fix is explicit baseUrl + paths in the
tsconfig; details in LEARNINGS.md.

Spec: specs/internal-assets-readme.md
Signed-off-by: Jose Alekhinne <jose@ctx.ist>
The VS Code extension at editors/vscode/ is a separately-
published deliverable: it ships as a .vsix package to the VS Code
Marketplace under publisher `activememory`, manually via
`vsce publish`. It is NOT embedded into the ctx Go binary and
does NOT ride along with release.yml. Until this commit, nothing
in CI exercised its TypeScript surface.

A typo in src/extension.ts would have shipped to marketplace and
broken end-user installs. This commit adds CI guardrails for the
manual publish pipeline and clarifies the embedded-vs-separately-
published distinction in the docs that previously elided it.

Changes:

- .github/workflows/ci.yml: new job `vscode-extension` runs
  `npm ci`, `npm run build` (esbuild bundle), and
  `npx tsc --noEmit -p tsconfig.ci.json` against the production
  source on every PR and push to main.

- editors/vscode/tsconfig.json: add `include: ["src/**/*"]`.
  The existing config declared `rootDir: src` but no `include`,
  so default `**/*` swept in `vitest.config.ts` outside rootDir
  and tsc errored. Latent because nothing previously ran tsc
  against this tsconfig.

- editors/vscode/tsconfig.ci.json: new CI-only config extending
  tsconfig.json that also excludes `**/*.test.ts`. The test file
  has unrelated type errors (handler imports for symbols no
  longer exported by extension.ts; CancellationToken mock with
  a stale signature) -- gating on those would block this guardrail
  on a separate test-rot fix. The CI carve-out lets production
  code be gated today; the test rot is filed as a discrete task.

- internal/assets/README.md: new section "Embedded vs.
  Separately-Published: At a Glance" with a side-by-side table
  comparing carrier, build pipeline, release pipeline, versioning,
  and CI gate. Extended the "What does not belong" list to call
  out separately-published deliverables and where they live.

- editors/vscode/README.md: new "Release" section documenting
  the manual `vsce publish` flow, the CI gates that protect it,
  the known gaps (test-rot, lint, vsce package dry-run), and a
  5-step release checklist. Also notes the test-rot caveat in
  the "Testing" subsection.

- .context/TASKS.md: marked the vscode CI guardrails task [x]
  complete; added a new [ ] task for the test-file rot fix with
  the specific error inventory (missing handler exports,
  CancellationToken mock signature) so the next session can pick
  it up without re-investigating.

Spec: specs/internal-assets-readme.md
Signed-off-by: Jose Alekhinne <jose@ctx.ist>
Records the architectural distinction surfaced this session:
embedded harnesses (//go:embed into the ctx binary, shipped via
'ctx setup') and separately-published harnesses (VS Code
extension to Marketplace, manual vsce publish) are first-class
peers with distinct CI and release pipelines. Future harnesses
declare their pattern at placement time. Load-bearing reasons
against ever lifting integrations/ out of internal/assets/ are
captured.

Spec: specs/internal-assets-readme.md
Signed-off-by: Jose Alekhinne <jose@ctx.ist>
Until this commit, the VS Code Chat extension had no dedicated
home page in ctx's documentation site. OpenCode had
docs/home/opencode.md (185 lines, published at site/home/opencode/);
VS Code was reduced to a 24-line install snippet inside
docs/operations/integrations.md and the marketplace package README.
A docs-site reader had no path to day-to-day usage — they had to
guess.

Changes:

- docs/home/vscode.md: new dedicated page mirroring the opencode
  page shape -- The Problem (with/without ctx contrast), Setup,
  What Gets Created, How You Use It, What Happens Automatically
  (file save, git commit, .context/ change, dependency-file edit,
  heartbeat, activate/deactivate), Status Bar, Slash Commands
  (core context, session lifecycle, discovery & planning, with a
  link to the README for the full 45-command list), Natural
  Language routing, Auto-Bootstrap, Prerequisites, Configuration,
  Refreshing the Integration (no `ctx setup` step needed -- the
  extension carries its own runtime), Troubleshooting,
  Verify It Works, What's Next.

- zensical.toml: registered the new page under the "Get Started"
  nav, adjacent to home/opencode.md, so both first-class
  harnesses appear in the sidebar.

- docs/operations/integrations.md: replaced the old slash-command
  table (divergent maintenance risk vs. the home page) with a
  prominent "Full guide" tip pointing at docs/home/vscode.md,
  expanded the install instructions to mention the Marketplace
  channel first and the source build as the fallback, and added a
  "What Gets Created" + "How It Works" pair that parallels the
  OpenCode subsection's depth.

- docs/recipes/multi-tool-setup.md: added a VS Code subsection
  between OpenCode and Cursor, parallel to the others. Includes
  the "VS Code Is a First-Class Citizen" tip block, modeled on
  the existing Claude Code and OpenCode equivalents.

- .context/TASKS.md: closed the parity-gap task [x] with the
  full inventory of changes so a future drift check can verify
  it.

- site/: regenerated via `make site` (zensical build + ctx site
  feed). The nav change touches every page's sidebar, so every
  page's HTML rebuilds; that's a static-site-generator artifact,
  not separate edits. site/home/vscode/ is the new published
  page; site/feed.xml and site/search.json updated to include
  it.

Spec: specs/internal-assets-readme.md
Signed-off-by: Jose Alekhinne <jose@ctx.ist>
The hack/detect-ai-typography.sh detector flagged em-dashes in
docs/ that I introduced this session. Each one re-evaluated in
context; no blanket replacement. Replacements chosen per the
function the em-dash was performing in the sentence:

- Definition-list / bullet "term — explanation":
  → colon (`**term:** explanation`). 11 cases.

- Joined declarative clauses where the second states a
  consequence:
  → period (sentence break). 4 cases.

- "Quoted phrase — its description" in a table cell
  (problematic because `?":` glyph cluster is awkward):
  → restructured: `Description (trigger: "phrase") ...`. 1 case.

- "If X, then Y" instruction:
  → colon. 1 case.

Kept (1 case): `*ctx — Persistent Context for AI*` in both
docs/home/vscode.md and docs/operations/integrations.md. This
is the literal VS Code Marketplace `displayName` field (verified
in editors/vscode/package.json:3). The em-dash is part of the
brand string, not authorial choice.

Out of scope for this commit (flagged separately for your call):
- Pre-existing em-dashes in docs/home/opencode.md (8) and
  the OpenCode subsection of integrations.md (7) and the
  OpenCode tip in multi-tool-setup.md (1). These pre-date this
  branch.
- Em-dashes in docs/recipes/hub-team.md and docs/reference/skills.md.
  Pre-existing.
- Em-dashes I introduced this session in non-docs files:
  internal/assets/README.md (3), editors/vscode/README.md (3),
  tools/typecheck/opencode/README.md (7). Same author, same
  pattern; awaiting your nod on scope.

site/ regenerated via `make site`.

Spec: specs/internal-assets-readme.md
Signed-off-by: Jose Alekhinne <jose@ctx.ist>
Companion to 28d428e. Same author, same pattern, same per-dash
semantic treatment, broader scope: the three READMEs outside
docs/ where I introduced em-dashes this session.

Per-file decisions:

- editors/vscode/README.md (3): definition-list em-dashes in the
  Release-section CI guardrails -> colon. `npm ci`, `npm run build`,
  `npx tsc --noEmit -p tsconfig.ci.json` each get `term:` framing.

- internal/assets/README.md (3):
  * "it does **not** belong here -- or, more precisely, only its
    post-transformation output does" was self-correction; split
    into "...does **not** belong here. More precisely: only its
    post-transformation output does."
  * "...the Go struct that consumes them -- drift in either
    direction fails CI" was observation+consequence; sentence
    break.
  * "Generated documentation, transient build artifacts, or
    caches -- these have no business in source control here"
    used em-dash to introduce a backwards-pointing "these";
    folded the resumptive pronoun away and made it one positive
    declaration ("...and caches have no business...").

- tools/typecheck/opencode/README.md (7):
  * Definition lists (3): `package.json`, `tsconfig.json`,
    `package-lock.json` get colon.
  * "What this does not check" bullets (3): same colon
    treatment.
  * Trailing em-dash after wrapped sentence ("...own header
    comment -- keep that comment and this dependency in sync")
    was observation+instruction; sentence break.

Total em-dashes I introduced this session and resolved (across
both this commit and 28d428e): 32. Kept (2): the literal VS Code
Marketplace `displayName` field `*ctx -- Persistent Context for
AI*` in docs/home/vscode.md and docs/operations/integrations.md.

Pre-existing em-dashes in files I did not author this session
remain untouched (docs/home/opencode.md, docs/recipes/hub-team.md,
docs/reference/skills.md, OpenCode sections of integrations.md
and multi-tool-setup.md). Those are out of scope for this branch.

Spec: specs/internal-assets-readme.md
Signed-off-by: Jose Alekhinne <jose@ctx.ist>
@josealekhine josealekhine self-assigned this May 12, 2026
@josealekhine josealekhine requested a review from bilersan as a code owner May 12, 2026 04:54
…aint

CI failure surfaced by the new vscode-extension job (commit
118ccb4): `npm ci` errored with "Missing: esbuild@0.28.0 from
lock file" on a fresh Ubuntu runner with Node 20. Local installs
on this machine had silently masked the inconsistency.

Root cause: a Dependabot bump in 275e14b brought vitest 4.x in,
whose bundled vite peer-depends on `esbuild: "^0.27.0 || ^0.28.0"`.
The repo's direct devDependency was still pinned at `^0.25.12`,
incompatible with the transitive constraint. `npm install` had
been resolving the conflict locally by deduping to 0.25.12, but
`npm ci` (which requires the lockfile to fully satisfy all
constraints with no resolution work) refused to proceed.

The mismatch slipped through Dependabot review because no CI step
was actually running `npm ci` against this lockfile until the
vscode-extension job landed. That's exactly the kind of latent
defect the guardrail is for; surfacing it on the first run is the
gate doing its job, not a false positive.

Fix:

- editors/vscode/package.json: bump `esbuild` devDep from
  `^0.25.12` to `^0.28.0`. esbuild 0.x version bumps are
  formally breaking, but the project uses esbuild only as a
  bundler with `--bundle --outfile --external:vscode --format=cjs
  --platform=node --minify` -- flag set is stable across these
  releases.

- editors/vscode/package-lock.json: regenerated via `npm install`.
  346 packages resolved cleanly; bundle output is 29.2kb (same
  shape as before); `npx tsc --noEmit -p tsconfig.ci.json`
  passes.

Spec: specs/internal-assets-readme.md
Signed-off-by: Jose Alekhinne <jose@ctx.ist>
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 12, 2026

Deploying ctx with  Cloudflare Pages  Cloudflare Pages

Latest commit: f1c69da
Status: ✅  Deploy successful!
Preview URL: https://51b5ebae.ctx-bhl.pages.dev
Branch Preview URL: https://feat-opencode-plugin-tsc-noe.ctx-bhl.pages.dev

View logs

@josealekhine josealekhine merged commit f096094 into main May 12, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant