Skip to content

Linux and/or Devcontainer Build: automated VSIX emission from Developer Tools #553

Description

@gennadiryan

Devcontainer Build: automated VSIX emission from Developer Tools

Important

Problem

The existing Developer Tools "Rebuild Locally" build path is broken for all
linux users
— not only devcontainers. The handler hardcodes darwin-only binary
resolution paths (opencode-darwin-arm64, opencode-darwin-x64), uses
bun run build which fails to resolve pnpm workspace scripts, targets
~/.vscode/extensions/ (wrong on Remote/devcontainer hosts), and calls
macOS-only codesign. Any linux machine — bare metal, VM, WSL, or
devcontainer — hits "binary not found" after a successful build. The darwin
path still needs its own fix (follow-up #7); this feature provides an
immediate working alternative for all linux users AND all devcontainer users
wanting convenience builds from the Developer Tools panel.

Approach

A new "Devcontainer mode (experimental)" toggle in Developer Tools that runs
the user's proven pnpm-based build workflow and emits a .vsix to a configurable
path — fully orthogonal to the existing developer mode (no eager actions, no
hot-reload, no window reload). Despite the "devcontainer" naming, the build
path is platform-agnostic and works on any host with bun + pnpm + node.

Approaches Considered

  • Existing "Rebuild Locally" hot-reload — fails on linux; darwin-biased binary search; fragile copy-into-installed-dir (rejected)
  • Fix the existing rebuild for linux — add linux candidates + fix bun→pnpm; still fragile hot-reload model (runner-up; deferred as item 7)
  • Emit a vsix via a dedicated button — uses the proven cross-platform workflow; no fragile hot-reload; manual install is a human checkpoint (chosen)

Scope

In: devcontainer toggle, VSIX output path field, "Build VSIX" button,
bridge handler executing the 5-step pnpm workflow, lane allowlist wiring,
AMICODE_OPENCODE_SRC env var for non-sibling layouts, NODE_OPTIONS
default-only semantics, decoupled eager-action guards.

Out: auto-install after build (follow-up #3), build log streaming (#4),
incremental builds (#6), replacing the existing rebuild path (#7), devcontainer
auto-detection (#8).

Assumptions

  • bun and pnpm are on PATH inside the container (the Dockerfile installs both)
  • The opencode repo is the harmoniqs/opencode fork (required by fetch_opencode.mjs)
  • vsce is available as a devDependency (resolved via pnpm exec)
  • The output directory is on a persistent volume

Note on applicability

While this feature was developed and primarily tested inside devcontainers, it
is not limited to devcontainer use. The underlying build workflow
(pnpm installpnpm --filter amicode buildopencode:buildvsce package)
is the standard cross-platform build path and works on any linux or macOS host
with bun + pnpm + node installed. The feature is a reliable alternative to the
existing developer build for any scenario where a specific pair of opencode and
amicode branches need to be test-driven live — whether inside a devcontainer,
on a remote host via SSH, or on a local machine where the darwin hot-reload
path is undesirable or broken. Until the existing developer build is generalized
to support all platforms natively, this feature fills the gap.


Acceptance Criteria

  • "Devcontainer mode" toggle is visible and usable WITHOUT enabling developer mode
  • "Build VSIX" button is visible at the top when devcontainer mode is ON
  • Clicking "Build VSIX" produces a .vsix at the configured output path
  • No eager actions fire on path blur when developer mode is OFF
  • The built vsix installs correctly via right-click → "Install Extension VSIX"
  • Non-sibling repo layouts work (AMICODE_OPENCODE_SRC propagated)
  • Existing NODE_OPTIONS are preserved (not overwritten)

Key Decisions

  • Paths are shared settings keys between developer mode and devcontainer mode;
    behavior differs (eager vs. inert on blur)
  • The handler sets AMICODE_OPENCODE_SRC in subprocess env, removing the
    implicit sibling-directory requirement
  • NODE_OPTIONS is set as a default only (process.env.NODE_OPTIONS ?? "...")
  • The vsix filename includes a timestamp to prevent collisions
  • No window reload, no server restart, no settings mutation — pure file emission

Constraints & Invariants

  • Devcontainer mode must NEVER set amicode.opencodeBinary or amicode.devAssetRoot
  • Devcontainer mode must NEVER trigger sendUpdate() on path blur
  • Devcontainer mode must NEVER trigger a window reload
  • The handler must not assume repos are siblings (must use AMICODE_OPENCODE_SRC)
Implementation Detail (feature checklist)

opencode repo (packages/app/src/)

  • context/settings.tsx — devcontainerMode + vsixOutputPath in type, defaults, accessors
  • components/settings-v2/developer-tools-controller.ts — signals, message handler, buildVsix action, blur guards
  • components/settings-v2/developer-tools.tsx — restructured UI: independent toggles, button placement, conditional visibility

amicode repo (packages/extension/src/)

  • chat_bridge.tsdev-tools-build-vsix handler (5-step build: install → build → package)
  • chat_panel.ts — lane-1 and lane-2 allowlist entries (4 insertions)

Follow-Up Items

# Item Priority Effort
1 Progress stages (per-step status messages) High ~10 lines
2 Pre-flight validation (bun/pnpm/node on PATH) High ~10 lines
3 Auto-install offer (code --install-extension) High ~15 lines
4 Build log streaming (stdout→OutputChannel) Medium ~20 lines
5 Clean repos toggle (optional git clean) Medium ~10 lines
6 Incremental build (skip install if lockfiles unchanged) Medium ~30 lines
7 Replace existing "Rebuild Locally" with vsix path Low Consensus needed
8 Auto-detect devcontainer environment Low UX decision
9 Fix isModelConfigured() to check env vars Low Separate concern
10 path.resolve() for relative paths in AMICODE_OPENCODE_SRC Low ~1 line

Source

  • Plan: plans/devcontainer-build-improvements.md
  • Research: notes/research/containers/devcontainer-builds.md, devcontainer-build-addendum.md
  • Bug analysis: notes/research/ui/eager-devtools-bug.md
  • ADR review: notes/reviews/devcontainer-build-adr-review.md

PR Status & Deferred Review Comments

PRs

Addressed CodeRabbit findings (committed)

Finding Severity PR Resolution
Shell injection via outputPath interpolation in exec() Critical #554 Replaced with execFile + separate args (no shell)
execFile imported in wrong IIFE scope (unused in dev-tools-update, undefined in dev-tools-build-vsix) Critical #554 Moved import to correct IIFE
vsixPath may be undefined on done state (empty success display) Minor harmoniqs/opencode#252 Added non-empty string validation before setting "rebuilt" state
string | undefined not assignable to string in JSX (typecheck) Minor harmoniqs/opencode#252 Added ?? "" fallback

Deferred CodeRabbit findings (rolled into follow-up)

The following out-of-diff suggestions from CodeRabbit are acknowledged and tracked
as part of the follow-up iteration (issue #553). They are of similar nature and
severity to the already-listed follow-up items (pre-flight validation, progress
stages, etc.) and do not block the initial merge:

Merge ordering

The opencode PR (harmoniqs/opencode#252) must land on local/amicode first — the amicode PR's
app-bundle-gate CI check verifies the committed app-bundle matches the fork's
state, which includes the new settings UI. Once harmoniqs/opencode#252 merges and the app-bundle
is re-derived, #554's gate will pass.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions