β.2: vendor + pin opencode (closes #2) - #8

Merged
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode
Jun 19, 2026
Merged

β.2: vendor + pin opencode (closes #2)#8
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Closes#2. Stacked on #7 (β.1 workspace layout) — base will retarget to main automatically when #7 merges.

Implements spec-20260610-155955-vendor-opencode (in amico#132): the extension no longer assumes opencode on $PATH.

What this is

  • opencode.lock.json — committed pin: opencode v1.17.3, per-platform SHA256 (darwin-arm64 + linux-x64). Bumping the pin = one-file PR, gated by CI.
  • scripts/fetch_opencode.mjs — zero-dep download-at-build: SHA256-verified against the manifest (hard fail, no retry/override on mismatch — supply-chain signal), unpack-to-temp + atomic rename, idempotent (.sha256 stamp → offline repeat builds), --record mode for pin bumps. vendor/ is gitignored.
  • src/opencode_binary.ts — resolution: config override (dev-only) → vendored path from the extension install dir → hard error with fetch/reinstall instructions. No $PATH fallback (§4 Assumption 4 stays dead). Config default "opencode""". On a missing binary the extension still activates (inspector/watcher/commands) with chat disabled.
  • test/boot_smoke.mjs — the S35 gate: synthesized project → vendored binary serveGET /event → 200 text/event-stream → clean SIGTERM exit. No LLM creds needed. Runs as a two-platform CI matrix (ubuntu-latest + macos-14) and as the named test:smoke script β.4's packaging step will call.
  • .vscodeignore — exists so vsce does NOT fall back to .gitignore (which would silently exclude the binary from the VSIX); !vendor/** negation makes the intent explicit.
  • Spike smoke tests deleted (smoke_cli, smoke_opencode_boot, opencode_boot_harness, vscode_shim); extension now has a real vitest unit suite (10 tests) in the fast CI job (pnpm -r run test).

AC → evidence

Issue ACEvidence
VSIX ships opencode at a fixed SHA; build fails unless /event SSE 200opencode.lock.json + fetcher mismatch tests; local smoke: GET /event → 200 (text/event-stream) … PASS on v1.17.3; CI boot-smoke matrix
ServerManager spawns the vendored binary, not $PATHopencode_binary.ts resolution tests; extension.ts wiring; config default ""

Notes

  • v1.17.3 passed the smoke on the first try — no walk-back needed despite the spike being written against 1.3.x. (β.5 owns any SSE payload drift; this PR guarantees boot + /event.)
  • Spec deviations (all noted in the plan): smoke file is boot_smoke.mjs (plain node) so vitest's glob can't pull a network test into the hermetic suite; the fetcher buffers the download in memory rather than a temp file (outcome-equivalent, nothing half-written); idempotent path prints up to date: instead of exiting silently.
  • For β.4: package with vsce package per platform after fetch:opencode --platform <target>; .vscodeignore already ships vendor/**.

🤖 Generated with Claude Code

Rchari1and others added 11 commits June 10, 2026 11:22
…ension
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ract enforcement
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ash spike (S31 grep green)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ontract end-to-end
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@jack-champagnejack-champagne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

β.2 looks solid — approving in spirit. Pulled the stacked branch locally and ran it end-to-end: build/typecheck green, fast tier 44 (amico-run) + 10 (extension) passing, fetch:opencode downloaded the real v1.17.3 linux-x64 and the committed SHA verified against the live GitHub release, and test:smoke drove the real binary to GET /event → 200 text/event-stream with a clean SIGTERM exit. CI is green on all three jobs, so the darwin-arm64 pin is machine-gated too. Supply-chain handling (archive-hash-before-unpack, hard-fail with no override, atomic temp→rename install, injectable download for hermetic tests) and graceful degradation (chat disabled but the extension still activates) are exactly right.

Two inline notes — one's a question for you on the leftover AMICO_* env wiring, the other a CI-cost suggestion. Neither blocks.

cwd: opencodeProject.projectDir,
env: {
PATH: `${binDir}:${process.env.PATH ?? ""}`,
AMICO_JULIA_SCRIPT: juliaScript,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rchari1 — this AMICO_* env + PATH=binDir:$PATH injection looks like leftover spike wiring, and it cuts against β.1's all-argv / no-AMICO_* contract (S37 / Q90 — amico-run takes everything via argv, nothing from env). I'm inclined to kill it. Before we rip it out: is there something the opencode server still needs these for (a tool the chat slice invokes that reads them), or can β.3 pass them through amico-run flags instead? Want your read.

- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- run: pnpm install --frozen-lockfile
- run: pnpm --filter amicode-v2 fetch:opencode

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both matrix legs re-download ~157MB on every run. Worth an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json'), restoring packages/extension/vendor/ before this step — the .sha256 idempotency stamp already makes fetch:opencode a no-op on a cache hit, so unchanged pins skip the download entirely.

Rchari1and others added 6 commits June 17, 2026 12:13
…xpected-throw→exit 64, updateLatest per-runId temp (concurrent-submit race), version single-sourced from package.json; solve_common.jl on Piccolo 1.19 via public Piccolo.Callbacks (no reach-through)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n hashes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ion (S35)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e spike smoke tests
v1.17.3 passes: GET /event → 200 text/event-stream against a synthesized
project, clean SIGTERM exit. No walk-back needed despite the 1.3.x-era spike.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e matrix; .vscodeignore ships vendor/
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/beta2-vendor-opencode branch from 4bb031b to 26d9018CompareJune 17, 2026 16:14
@Rchari1

Copy link
Copy Markdown
MemberAuthor

Thanks — on your two notes:

  • AMICO_* env + PATH=binDir:$PATH (extension.ts:88): you're right it's leftover spike wiring against β.1's all-argv/no-env contract (S37/Q90). Already removed in β.3+β.5: AGENTS.md + vetted template + chat→solve→inspector slice (closes #3) #9 (β.3 Task 4): the spawn env no longer carries AMICO_JULIA_SCRIPT/PROJECT/RUNS_ROOT — amico-run is argv-only, and chat→solve drives it purely via flags. PATH now carries only the amico-run launcher dir (so opencode's bash can resolve amico-run); the Julia project reaches the agent through AGENTS.md (substituted at session-copy), passed as --project. So nothing reads those env vars anymore.
  • CI cache for the 157MB opencode download: good call — I'll add an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json') restoring packages/extension/vendor/ before fetch:opencode (the .sha256 stamp already makes it a no-op on a cache hit). Tracking it as a fast-follow so it doesn't churn the stack mid-review; flag if you'd rather I fold it in now.

(Branch force-updated from the β.1 rebase — same content, just restacked on the #7 fixes.)

@jack-champagne
jack-champagne deleted the branch mainJune 18, 2026 06:29
@jack-champagne
jack-champagne changed the base branch from rchari/beta1-amico-run to mainJune 18, 2026 06:31
#7 was squash-merged (4415f02), flattening beta1's history; beta2 already
contains beta1's changes via its original commits, so this records main as an
ancestor without altering beta2's tree (-s ours). Lets #8 reach main with a
merge commit — no history rewrite, branch stays fast-forwardable.
@jack-champagne
jack-champagne merged commit eb978e2 into mainJun 19, 2026
3 checks passed
Sign up for freeto 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.

β.2 — Vendor + pin opencode in the VSIX

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

β.2: vendor + pin opencode (closes #2) - #8

Merged
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode
Jun 19, 2026
Merged

β.2: vendor + pin opencode (closes #2)#8
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Closes#2. Stacked on #7 (β.1 workspace layout) — base will retarget to main automatically when #7 merges.

Implements spec-20260610-155955-vendor-opencode (in amico#132): the extension no longer assumes opencode on $PATH.

What this is

  • opencode.lock.json — committed pin: opencode v1.17.3, per-platform SHA256 (darwin-arm64 + linux-x64). Bumping the pin = one-file PR, gated by CI.
  • scripts/fetch_opencode.mjs — zero-dep download-at-build: SHA256-verified against the manifest (hard fail, no retry/override on mismatch — supply-chain signal), unpack-to-temp + atomic rename, idempotent (.sha256 stamp → offline repeat builds), --record mode for pin bumps. vendor/ is gitignored.
  • src/opencode_binary.ts — resolution: config override (dev-only) → vendored path from the extension install dir → hard error with fetch/reinstall instructions. No $PATH fallback (§4 Assumption 4 stays dead). Config default "opencode""". On a missing binary the extension still activates (inspector/watcher/commands) with chat disabled.
  • test/boot_smoke.mjs — the S35 gate: synthesized project → vendored binary serveGET /event → 200 text/event-stream → clean SIGTERM exit. No LLM creds needed. Runs as a two-platform CI matrix (ubuntu-latest + macos-14) and as the named test:smoke script β.4's packaging step will call.
  • .vscodeignore — exists so vsce does NOT fall back to .gitignore (which would silently exclude the binary from the VSIX); !vendor/** negation makes the intent explicit.
  • Spike smoke tests deleted (smoke_cli, smoke_opencode_boot, opencode_boot_harness, vscode_shim); extension now has a real vitest unit suite (10 tests) in the fast CI job (pnpm -r run test).

AC → evidence

Issue ACEvidence
VSIX ships opencode at a fixed SHA; build fails unless /event SSE 200opencode.lock.json + fetcher mismatch tests; local smoke: GET /event → 200 (text/event-stream) … PASS on v1.17.3; CI boot-smoke matrix
ServerManager spawns the vendored binary, not $PATHopencode_binary.ts resolution tests; extension.ts wiring; config default ""

Notes

  • v1.17.3 passed the smoke on the first try — no walk-back needed despite the spike being written against 1.3.x. (β.5 owns any SSE payload drift; this PR guarantees boot + /event.)
  • Spec deviations (all noted in the plan): smoke file is boot_smoke.mjs (plain node) so vitest's glob can't pull a network test into the hermetic suite; the fetcher buffers the download in memory rather than a temp file (outcome-equivalent, nothing half-written); idempotent path prints up to date: instead of exiting silently.
  • For β.4: package with vsce package per platform after fetch:opencode --platform <target>; .vscodeignore already ships vendor/**.

🤖 Generated with Claude Code

Rchari1and others added 11 commits June 10, 2026 11:22
…ension
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ract enforcement
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ash spike (S31 grep green)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ontract end-to-end
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@jack-champagnejack-champagne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

β.2 looks solid — approving in spirit. Pulled the stacked branch locally and ran it end-to-end: build/typecheck green, fast tier 44 (amico-run) + 10 (extension) passing, fetch:opencode downloaded the real v1.17.3 linux-x64 and the committed SHA verified against the live GitHub release, and test:smoke drove the real binary to GET /event → 200 text/event-stream with a clean SIGTERM exit. CI is green on all three jobs, so the darwin-arm64 pin is machine-gated too. Supply-chain handling (archive-hash-before-unpack, hard-fail with no override, atomic temp→rename install, injectable download for hermetic tests) and graceful degradation (chat disabled but the extension still activates) are exactly right.

Two inline notes — one's a question for you on the leftover AMICO_* env wiring, the other a CI-cost suggestion. Neither blocks.

cwd: opencodeProject.projectDir,
env: {
PATH: `${binDir}:${process.env.PATH ?? ""}`,
AMICO_JULIA_SCRIPT: juliaScript,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rchari1 — this AMICO_* env + PATH=binDir:$PATH injection looks like leftover spike wiring, and it cuts against β.1's all-argv / no-AMICO_* contract (S37 / Q90 — amico-run takes everything via argv, nothing from env). I'm inclined to kill it. Before we rip it out: is there something the opencode server still needs these for (a tool the chat slice invokes that reads them), or can β.3 pass them through amico-run flags instead? Want your read.

- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- run: pnpm install --frozen-lockfile
- run: pnpm --filter amicode-v2 fetch:opencode

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both matrix legs re-download ~157MB on every run. Worth an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json'), restoring packages/extension/vendor/ before this step — the .sha256 idempotency stamp already makes fetch:opencode a no-op on a cache hit, so unchanged pins skip the download entirely.

Rchari1and others added 6 commits June 17, 2026 12:13
…xpected-throw→exit 64, updateLatest per-runId temp (concurrent-submit race), version single-sourced from package.json; solve_common.jl on Piccolo 1.19 via public Piccolo.Callbacks (no reach-through)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n hashes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ion (S35)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e spike smoke tests
v1.17.3 passes: GET /event → 200 text/event-stream against a synthesized
project, clean SIGTERM exit. No walk-back needed despite the 1.3.x-era spike.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e matrix; .vscodeignore ships vendor/
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/beta2-vendor-opencode branch from 4bb031b to 26d9018CompareJune 17, 2026 16:14
@Rchari1

Copy link
Copy Markdown
MemberAuthor

Thanks — on your two notes:

  • AMICO_* env + PATH=binDir:$PATH (extension.ts:88): you're right it's leftover spike wiring against β.1's all-argv/no-env contract (S37/Q90). Already removed in β.3+β.5: AGENTS.md + vetted template + chat→solve→inspector slice (closes #3) #9 (β.3 Task 4): the spawn env no longer carries AMICO_JULIA_SCRIPT/PROJECT/RUNS_ROOT — amico-run is argv-only, and chat→solve drives it purely via flags. PATH now carries only the amico-run launcher dir (so opencode's bash can resolve amico-run); the Julia project reaches the agent through AGENTS.md (substituted at session-copy), passed as --project. So nothing reads those env vars anymore.
  • CI cache for the 157MB opencode download: good call — I'll add an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json') restoring packages/extension/vendor/ before fetch:opencode (the .sha256 stamp already makes it a no-op on a cache hit). Tracking it as a fast-follow so it doesn't churn the stack mid-review; flag if you'd rather I fold it in now.

(Branch force-updated from the β.1 rebase — same content, just restacked on the #7 fixes.)

@jack-champagne
jack-champagne deleted the branch mainJune 18, 2026 06:29
@jack-champagne
jack-champagne changed the base branch from rchari/beta1-amico-run to mainJune 18, 2026 06:31
#7 was squash-merged (4415f02), flattening beta1's history; beta2 already
contains beta1's changes via its original commits, so this records main as an
ancestor without altering beta2's tree (-s ours). Lets #8 reach main with a
merge commit — no history rewrite, branch stays fast-forwardable.
@jack-champagne
jack-champagne merged commit eb978e2 into mainJun 19, 2026
3 checks passed
Sign up for freeto 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.

β.2 — Vendor + pin opencode in the VSIX

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

β.2: vendor + pin opencode (closes #2) - #8

Merged
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode
Jun 19, 2026
Merged

β.2: vendor + pin opencode (closes #2)#8
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Closes#2. Stacked on #7 (β.1 workspace layout) — base will retarget to main automatically when #7 merges.

Implements spec-20260610-155955-vendor-opencode (in amico#132): the extension no longer assumes opencode on $PATH.

What this is

  • opencode.lock.json — committed pin: opencode v1.17.3, per-platform SHA256 (darwin-arm64 + linux-x64). Bumping the pin = one-file PR, gated by CI.
  • scripts/fetch_opencode.mjs — zero-dep download-at-build: SHA256-verified against the manifest (hard fail, no retry/override on mismatch — supply-chain signal), unpack-to-temp + atomic rename, idempotent (.sha256 stamp → offline repeat builds), --record mode for pin bumps. vendor/ is gitignored.
  • src/opencode_binary.ts — resolution: config override (dev-only) → vendored path from the extension install dir → hard error with fetch/reinstall instructions. No $PATH fallback (§4 Assumption 4 stays dead). Config default "opencode""". On a missing binary the extension still activates (inspector/watcher/commands) with chat disabled.
  • test/boot_smoke.mjs — the S35 gate: synthesized project → vendored binary serveGET /event → 200 text/event-stream → clean SIGTERM exit. No LLM creds needed. Runs as a two-platform CI matrix (ubuntu-latest + macos-14) and as the named test:smoke script β.4's packaging step will call.
  • .vscodeignore — exists so vsce does NOT fall back to .gitignore (which would silently exclude the binary from the VSIX); !vendor/** negation makes the intent explicit.
  • Spike smoke tests deleted (smoke_cli, smoke_opencode_boot, opencode_boot_harness, vscode_shim); extension now has a real vitest unit suite (10 tests) in the fast CI job (pnpm -r run test).

AC → evidence

Issue ACEvidence
VSIX ships opencode at a fixed SHA; build fails unless /event SSE 200opencode.lock.json + fetcher mismatch tests; local smoke: GET /event → 200 (text/event-stream) … PASS on v1.17.3; CI boot-smoke matrix
ServerManager spawns the vendored binary, not $PATHopencode_binary.ts resolution tests; extension.ts wiring; config default ""

Notes

  • v1.17.3 passed the smoke on the first try — no walk-back needed despite the spike being written against 1.3.x. (β.5 owns any SSE payload drift; this PR guarantees boot + /event.)
  • Spec deviations (all noted in the plan): smoke file is boot_smoke.mjs (plain node) so vitest's glob can't pull a network test into the hermetic suite; the fetcher buffers the download in memory rather than a temp file (outcome-equivalent, nothing half-written); idempotent path prints up to date: instead of exiting silently.
  • For β.4: package with vsce package per platform after fetch:opencode --platform <target>; .vscodeignore already ships vendor/**.

🤖 Generated with Claude Code

Rchari1and others added 11 commits June 10, 2026 11:22
…ension
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ract enforcement
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ash spike (S31 grep green)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ontract end-to-end
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@jack-champagnejack-champagne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

β.2 looks solid — approving in spirit. Pulled the stacked branch locally and ran it end-to-end: build/typecheck green, fast tier 44 (amico-run) + 10 (extension) passing, fetch:opencode downloaded the real v1.17.3 linux-x64 and the committed SHA verified against the live GitHub release, and test:smoke drove the real binary to GET /event → 200 text/event-stream with a clean SIGTERM exit. CI is green on all three jobs, so the darwin-arm64 pin is machine-gated too. Supply-chain handling (archive-hash-before-unpack, hard-fail with no override, atomic temp→rename install, injectable download for hermetic tests) and graceful degradation (chat disabled but the extension still activates) are exactly right.

Two inline notes — one's a question for you on the leftover AMICO_* env wiring, the other a CI-cost suggestion. Neither blocks.

cwd: opencodeProject.projectDir,
env: {
PATH: `${binDir}:${process.env.PATH ?? ""}`,
AMICO_JULIA_SCRIPT: juliaScript,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rchari1 — this AMICO_* env + PATH=binDir:$PATH injection looks like leftover spike wiring, and it cuts against β.1's all-argv / no-AMICO_* contract (S37 / Q90 — amico-run takes everything via argv, nothing from env). I'm inclined to kill it. Before we rip it out: is there something the opencode server still needs these for (a tool the chat slice invokes that reads them), or can β.3 pass them through amico-run flags instead? Want your read.

- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- run: pnpm install --frozen-lockfile
- run: pnpm --filter amicode-v2 fetch:opencode

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both matrix legs re-download ~157MB on every run. Worth an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json'), restoring packages/extension/vendor/ before this step — the .sha256 idempotency stamp already makes fetch:opencode a no-op on a cache hit, so unchanged pins skip the download entirely.

Rchari1and others added 6 commits June 17, 2026 12:13
…xpected-throw→exit 64, updateLatest per-runId temp (concurrent-submit race), version single-sourced from package.json; solve_common.jl on Piccolo 1.19 via public Piccolo.Callbacks (no reach-through)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n hashes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ion (S35)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e spike smoke tests
v1.17.3 passes: GET /event → 200 text/event-stream against a synthesized
project, clean SIGTERM exit. No walk-back needed despite the 1.3.x-era spike.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e matrix; .vscodeignore ships vendor/
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/beta2-vendor-opencode branch from 4bb031b to 26d9018CompareJune 17, 2026 16:14
@Rchari1

Copy link
Copy Markdown
MemberAuthor

Thanks — on your two notes:

  • AMICO_* env + PATH=binDir:$PATH (extension.ts:88): you're right it's leftover spike wiring against β.1's all-argv/no-env contract (S37/Q90). Already removed in β.3+β.5: AGENTS.md + vetted template + chat→solve→inspector slice (closes #3) #9 (β.3 Task 4): the spawn env no longer carries AMICO_JULIA_SCRIPT/PROJECT/RUNS_ROOT — amico-run is argv-only, and chat→solve drives it purely via flags. PATH now carries only the amico-run launcher dir (so opencode's bash can resolve amico-run); the Julia project reaches the agent through AGENTS.md (substituted at session-copy), passed as --project. So nothing reads those env vars anymore.
  • CI cache for the 157MB opencode download: good call — I'll add an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json') restoring packages/extension/vendor/ before fetch:opencode (the .sha256 stamp already makes it a no-op on a cache hit). Tracking it as a fast-follow so it doesn't churn the stack mid-review; flag if you'd rather I fold it in now.

(Branch force-updated from the β.1 rebase — same content, just restacked on the #7 fixes.)

@jack-champagne
jack-champagne deleted the branch mainJune 18, 2026 06:29
@jack-champagne
jack-champagne changed the base branch from rchari/beta1-amico-run to mainJune 18, 2026 06:31
#7 was squash-merged (4415f02), flattening beta1's history; beta2 already
contains beta1's changes via its original commits, so this records main as an
ancestor without altering beta2's tree (-s ours). Lets #8 reach main with a
merge commit — no history rewrite, branch stays fast-forwardable.
@jack-champagne
jack-champagne merged commit eb978e2 into mainJun 19, 2026
3 checks passed
Sign up for freeto 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.

β.2 — Vendor + pin opencode in the VSIX

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

β.2: vendor + pin opencode (closes #2) - #8

Merged
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode
Jun 19, 2026
Merged

β.2: vendor + pin opencode (closes #2)#8
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Closes#2. Stacked on #7 (β.1 workspace layout) — base will retarget to main automatically when #7 merges.

Implements spec-20260610-155955-vendor-opencode (in amico#132): the extension no longer assumes opencode on $PATH.

What this is

  • opencode.lock.json — committed pin: opencode v1.17.3, per-platform SHA256 (darwin-arm64 + linux-x64). Bumping the pin = one-file PR, gated by CI.
  • scripts/fetch_opencode.mjs — zero-dep download-at-build: SHA256-verified against the manifest (hard fail, no retry/override on mismatch — supply-chain signal), unpack-to-temp + atomic rename, idempotent (.sha256 stamp → offline repeat builds), --record mode for pin bumps. vendor/ is gitignored.
  • src/opencode_binary.ts — resolution: config override (dev-only) → vendored path from the extension install dir → hard error with fetch/reinstall instructions. No $PATH fallback (§4 Assumption 4 stays dead). Config default "opencode""". On a missing binary the extension still activates (inspector/watcher/commands) with chat disabled.
  • test/boot_smoke.mjs — the S35 gate: synthesized project → vendored binary serveGET /event → 200 text/event-stream → clean SIGTERM exit. No LLM creds needed. Runs as a two-platform CI matrix (ubuntu-latest + macos-14) and as the named test:smoke script β.4's packaging step will call.
  • .vscodeignore — exists so vsce does NOT fall back to .gitignore (which would silently exclude the binary from the VSIX); !vendor/** negation makes the intent explicit.
  • Spike smoke tests deleted (smoke_cli, smoke_opencode_boot, opencode_boot_harness, vscode_shim); extension now has a real vitest unit suite (10 tests) in the fast CI job (pnpm -r run test).

AC → evidence

Issue ACEvidence
VSIX ships opencode at a fixed SHA; build fails unless /event SSE 200opencode.lock.json + fetcher mismatch tests; local smoke: GET /event → 200 (text/event-stream) … PASS on v1.17.3; CI boot-smoke matrix
ServerManager spawns the vendored binary, not $PATHopencode_binary.ts resolution tests; extension.ts wiring; config default ""

Notes

  • v1.17.3 passed the smoke on the first try — no walk-back needed despite the spike being written against 1.3.x. (β.5 owns any SSE payload drift; this PR guarantees boot + /event.)
  • Spec deviations (all noted in the plan): smoke file is boot_smoke.mjs (plain node) so vitest's glob can't pull a network test into the hermetic suite; the fetcher buffers the download in memory rather than a temp file (outcome-equivalent, nothing half-written); idempotent path prints up to date: instead of exiting silently.
  • For β.4: package with vsce package per platform after fetch:opencode --platform <target>; .vscodeignore already ships vendor/**.

🤖 Generated with Claude Code

Rchari1and others added 11 commits June 10, 2026 11:22
…ension
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ract enforcement
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ash spike (S31 grep green)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ontract end-to-end
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@jack-champagnejack-champagne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

β.2 looks solid — approving in spirit. Pulled the stacked branch locally and ran it end-to-end: build/typecheck green, fast tier 44 (amico-run) + 10 (extension) passing, fetch:opencode downloaded the real v1.17.3 linux-x64 and the committed SHA verified against the live GitHub release, and test:smoke drove the real binary to GET /event → 200 text/event-stream with a clean SIGTERM exit. CI is green on all three jobs, so the darwin-arm64 pin is machine-gated too. Supply-chain handling (archive-hash-before-unpack, hard-fail with no override, atomic temp→rename install, injectable download for hermetic tests) and graceful degradation (chat disabled but the extension still activates) are exactly right.

Two inline notes — one's a question for you on the leftover AMICO_* env wiring, the other a CI-cost suggestion. Neither blocks.

cwd: opencodeProject.projectDir,
env: {
PATH: `${binDir}:${process.env.PATH ?? ""}`,
AMICO_JULIA_SCRIPT: juliaScript,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rchari1 — this AMICO_* env + PATH=binDir:$PATH injection looks like leftover spike wiring, and it cuts against β.1's all-argv / no-AMICO_* contract (S37 / Q90 — amico-run takes everything via argv, nothing from env). I'm inclined to kill it. Before we rip it out: is there something the opencode server still needs these for (a tool the chat slice invokes that reads them), or can β.3 pass them through amico-run flags instead? Want your read.

- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- run: pnpm install --frozen-lockfile
- run: pnpm --filter amicode-v2 fetch:opencode

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both matrix legs re-download ~157MB on every run. Worth an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json'), restoring packages/extension/vendor/ before this step — the .sha256 idempotency stamp already makes fetch:opencode a no-op on a cache hit, so unchanged pins skip the download entirely.

Rchari1and others added 6 commits June 17, 2026 12:13
…xpected-throw→exit 64, updateLatest per-runId temp (concurrent-submit race), version single-sourced from package.json; solve_common.jl on Piccolo 1.19 via public Piccolo.Callbacks (no reach-through)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n hashes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ion (S35)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e spike smoke tests
v1.17.3 passes: GET /event → 200 text/event-stream against a synthesized
project, clean SIGTERM exit. No walk-back needed despite the 1.3.x-era spike.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e matrix; .vscodeignore ships vendor/
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/beta2-vendor-opencode branch from 4bb031b to 26d9018CompareJune 17, 2026 16:14
@Rchari1

Copy link
Copy Markdown
MemberAuthor

Thanks — on your two notes:

  • AMICO_* env + PATH=binDir:$PATH (extension.ts:88): you're right it's leftover spike wiring against β.1's all-argv/no-env contract (S37/Q90). Already removed in β.3+β.5: AGENTS.md + vetted template + chat→solve→inspector slice (closes #3) #9 (β.3 Task 4): the spawn env no longer carries AMICO_JULIA_SCRIPT/PROJECT/RUNS_ROOT — amico-run is argv-only, and chat→solve drives it purely via flags. PATH now carries only the amico-run launcher dir (so opencode's bash can resolve amico-run); the Julia project reaches the agent through AGENTS.md (substituted at session-copy), passed as --project. So nothing reads those env vars anymore.
  • CI cache for the 157MB opencode download: good call — I'll add an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json') restoring packages/extension/vendor/ before fetch:opencode (the .sha256 stamp already makes it a no-op on a cache hit). Tracking it as a fast-follow so it doesn't churn the stack mid-review; flag if you'd rather I fold it in now.

(Branch force-updated from the β.1 rebase — same content, just restacked on the #7 fixes.)

@jack-champagne
jack-champagne deleted the branch mainJune 18, 2026 06:29
@jack-champagne
jack-champagne changed the base branch from rchari/beta1-amico-run to mainJune 18, 2026 06:31
#7 was squash-merged (4415f02), flattening beta1's history; beta2 already
contains beta1's changes via its original commits, so this records main as an
ancestor without altering beta2's tree (-s ours). Lets #8 reach main with a
merge commit — no history rewrite, branch stays fast-forwardable.
@jack-champagne
jack-champagne merged commit eb978e2 into mainJun 19, 2026
3 checks passed
Sign up for freeto 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.

β.2 — Vendor + pin opencode in the VSIX

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

β.2: vendor + pin opencode (closes #2) - #8

Merged
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode
Jun 19, 2026
Merged

β.2: vendor + pin opencode (closes #2)#8
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Closes#2. Stacked on #7 (β.1 workspace layout) — base will retarget to main automatically when #7 merges.

Implements spec-20260610-155955-vendor-opencode (in amico#132): the extension no longer assumes opencode on $PATH.

What this is

  • opencode.lock.json — committed pin: opencode v1.17.3, per-platform SHA256 (darwin-arm64 + linux-x64). Bumping the pin = one-file PR, gated by CI.
  • scripts/fetch_opencode.mjs — zero-dep download-at-build: SHA256-verified against the manifest (hard fail, no retry/override on mismatch — supply-chain signal), unpack-to-temp + atomic rename, idempotent (.sha256 stamp → offline repeat builds), --record mode for pin bumps. vendor/ is gitignored.
  • src/opencode_binary.ts — resolution: config override (dev-only) → vendored path from the extension install dir → hard error with fetch/reinstall instructions. No $PATH fallback (§4 Assumption 4 stays dead). Config default "opencode""". On a missing binary the extension still activates (inspector/watcher/commands) with chat disabled.
  • test/boot_smoke.mjs — the S35 gate: synthesized project → vendored binary serveGET /event → 200 text/event-stream → clean SIGTERM exit. No LLM creds needed. Runs as a two-platform CI matrix (ubuntu-latest + macos-14) and as the named test:smoke script β.4's packaging step will call.
  • .vscodeignore — exists so vsce does NOT fall back to .gitignore (which would silently exclude the binary from the VSIX); !vendor/** negation makes the intent explicit.
  • Spike smoke tests deleted (smoke_cli, smoke_opencode_boot, opencode_boot_harness, vscode_shim); extension now has a real vitest unit suite (10 tests) in the fast CI job (pnpm -r run test).

AC → evidence

Issue ACEvidence
VSIX ships opencode at a fixed SHA; build fails unless /event SSE 200opencode.lock.json + fetcher mismatch tests; local smoke: GET /event → 200 (text/event-stream) … PASS on v1.17.3; CI boot-smoke matrix
ServerManager spawns the vendored binary, not $PATHopencode_binary.ts resolution tests; extension.ts wiring; config default ""

Notes

  • v1.17.3 passed the smoke on the first try — no walk-back needed despite the spike being written against 1.3.x. (β.5 owns any SSE payload drift; this PR guarantees boot + /event.)
  • Spec deviations (all noted in the plan): smoke file is boot_smoke.mjs (plain node) so vitest's glob can't pull a network test into the hermetic suite; the fetcher buffers the download in memory rather than a temp file (outcome-equivalent, nothing half-written); idempotent path prints up to date: instead of exiting silently.
  • For β.4: package with vsce package per platform after fetch:opencode --platform <target>; .vscodeignore already ships vendor/**.

🤖 Generated with Claude Code

Rchari1and others added 11 commits June 10, 2026 11:22
…ension
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ract enforcement
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ash spike (S31 grep green)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ontract end-to-end
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@jack-champagnejack-champagne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

β.2 looks solid — approving in spirit. Pulled the stacked branch locally and ran it end-to-end: build/typecheck green, fast tier 44 (amico-run) + 10 (extension) passing, fetch:opencode downloaded the real v1.17.3 linux-x64 and the committed SHA verified against the live GitHub release, and test:smoke drove the real binary to GET /event → 200 text/event-stream with a clean SIGTERM exit. CI is green on all three jobs, so the darwin-arm64 pin is machine-gated too. Supply-chain handling (archive-hash-before-unpack, hard-fail with no override, atomic temp→rename install, injectable download for hermetic tests) and graceful degradation (chat disabled but the extension still activates) are exactly right.

Two inline notes — one's a question for you on the leftover AMICO_* env wiring, the other a CI-cost suggestion. Neither blocks.

cwd: opencodeProject.projectDir,
env: {
PATH: `${binDir}:${process.env.PATH ?? ""}`,
AMICO_JULIA_SCRIPT: juliaScript,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rchari1 — this AMICO_* env + PATH=binDir:$PATH injection looks like leftover spike wiring, and it cuts against β.1's all-argv / no-AMICO_* contract (S37 / Q90 — amico-run takes everything via argv, nothing from env). I'm inclined to kill it. Before we rip it out: is there something the opencode server still needs these for (a tool the chat slice invokes that reads them), or can β.3 pass them through amico-run flags instead? Want your read.

- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- run: pnpm install --frozen-lockfile
- run: pnpm --filter amicode-v2 fetch:opencode

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both matrix legs re-download ~157MB on every run. Worth an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json'), restoring packages/extension/vendor/ before this step — the .sha256 idempotency stamp already makes fetch:opencode a no-op on a cache hit, so unchanged pins skip the download entirely.

Rchari1and others added 6 commits June 17, 2026 12:13
…xpected-throw→exit 64, updateLatest per-runId temp (concurrent-submit race), version single-sourced from package.json; solve_common.jl on Piccolo 1.19 via public Piccolo.Callbacks (no reach-through)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n hashes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ion (S35)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e spike smoke tests
v1.17.3 passes: GET /event → 200 text/event-stream against a synthesized
project, clean SIGTERM exit. No walk-back needed despite the 1.3.x-era spike.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e matrix; .vscodeignore ships vendor/
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/beta2-vendor-opencode branch from 4bb031b to 26d9018CompareJune 17, 2026 16:14
@Rchari1

Copy link
Copy Markdown
MemberAuthor

Thanks — on your two notes:

  • AMICO_* env + PATH=binDir:$PATH (extension.ts:88): you're right it's leftover spike wiring against β.1's all-argv/no-env contract (S37/Q90). Already removed in β.3+β.5: AGENTS.md + vetted template + chat→solve→inspector slice (closes #3) #9 (β.3 Task 4): the spawn env no longer carries AMICO_JULIA_SCRIPT/PROJECT/RUNS_ROOT — amico-run is argv-only, and chat→solve drives it purely via flags. PATH now carries only the amico-run launcher dir (so opencode's bash can resolve amico-run); the Julia project reaches the agent through AGENTS.md (substituted at session-copy), passed as --project. So nothing reads those env vars anymore.
  • CI cache for the 157MB opencode download: good call — I'll add an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json') restoring packages/extension/vendor/ before fetch:opencode (the .sha256 stamp already makes it a no-op on a cache hit). Tracking it as a fast-follow so it doesn't churn the stack mid-review; flag if you'd rather I fold it in now.

(Branch force-updated from the β.1 rebase — same content, just restacked on the #7 fixes.)

@jack-champagne
jack-champagne deleted the branch mainJune 18, 2026 06:29
@jack-champagne
jack-champagne changed the base branch from rchari/beta1-amico-run to mainJune 18, 2026 06:31
#7 was squash-merged (4415f02), flattening beta1's history; beta2 already
contains beta1's changes via its original commits, so this records main as an
ancestor without altering beta2's tree (-s ours). Lets #8 reach main with a
merge commit — no history rewrite, branch stays fast-forwardable.
@jack-champagne
jack-champagne merged commit eb978e2 into mainJun 19, 2026
3 checks passed
Sign up for freeto 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.

β.2 — Vendor + pin opencode in the VSIX

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

β.2: vendor + pin opencode (closes #2) - #8

Merged
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode
Jun 19, 2026
Merged

β.2: vendor + pin opencode (closes #2)#8
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Closes#2. Stacked on #7 (β.1 workspace layout) — base will retarget to main automatically when #7 merges.

Implements spec-20260610-155955-vendor-opencode (in amico#132): the extension no longer assumes opencode on $PATH.

What this is

  • opencode.lock.json — committed pin: opencode v1.17.3, per-platform SHA256 (darwin-arm64 + linux-x64). Bumping the pin = one-file PR, gated by CI.
  • scripts/fetch_opencode.mjs — zero-dep download-at-build: SHA256-verified against the manifest (hard fail, no retry/override on mismatch — supply-chain signal), unpack-to-temp + atomic rename, idempotent (.sha256 stamp → offline repeat builds), --record mode for pin bumps. vendor/ is gitignored.
  • src/opencode_binary.ts — resolution: config override (dev-only) → vendored path from the extension install dir → hard error with fetch/reinstall instructions. No $PATH fallback (§4 Assumption 4 stays dead). Config default "opencode""". On a missing binary the extension still activates (inspector/watcher/commands) with chat disabled.
  • test/boot_smoke.mjs — the S35 gate: synthesized project → vendored binary serveGET /event → 200 text/event-stream → clean SIGTERM exit. No LLM creds needed. Runs as a two-platform CI matrix (ubuntu-latest + macos-14) and as the named test:smoke script β.4's packaging step will call.
  • .vscodeignore — exists so vsce does NOT fall back to .gitignore (which would silently exclude the binary from the VSIX); !vendor/** negation makes the intent explicit.
  • Spike smoke tests deleted (smoke_cli, smoke_opencode_boot, opencode_boot_harness, vscode_shim); extension now has a real vitest unit suite (10 tests) in the fast CI job (pnpm -r run test).

AC → evidence

Issue ACEvidence
VSIX ships opencode at a fixed SHA; build fails unless /event SSE 200opencode.lock.json + fetcher mismatch tests; local smoke: GET /event → 200 (text/event-stream) … PASS on v1.17.3; CI boot-smoke matrix
ServerManager spawns the vendored binary, not $PATHopencode_binary.ts resolution tests; extension.ts wiring; config default ""

Notes

  • v1.17.3 passed the smoke on the first try — no walk-back needed despite the spike being written against 1.3.x. (β.5 owns any SSE payload drift; this PR guarantees boot + /event.)
  • Spec deviations (all noted in the plan): smoke file is boot_smoke.mjs (plain node) so vitest's glob can't pull a network test into the hermetic suite; the fetcher buffers the download in memory rather than a temp file (outcome-equivalent, nothing half-written); idempotent path prints up to date: instead of exiting silently.
  • For β.4: package with vsce package per platform after fetch:opencode --platform <target>; .vscodeignore already ships vendor/**.

🤖 Generated with Claude Code

Rchari1and others added 11 commits June 10, 2026 11:22
…ension
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ract enforcement
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ash spike (S31 grep green)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ontract end-to-end
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@jack-champagnejack-champagne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

β.2 looks solid — approving in spirit. Pulled the stacked branch locally and ran it end-to-end: build/typecheck green, fast tier 44 (amico-run) + 10 (extension) passing, fetch:opencode downloaded the real v1.17.3 linux-x64 and the committed SHA verified against the live GitHub release, and test:smoke drove the real binary to GET /event → 200 text/event-stream with a clean SIGTERM exit. CI is green on all three jobs, so the darwin-arm64 pin is machine-gated too. Supply-chain handling (archive-hash-before-unpack, hard-fail with no override, atomic temp→rename install, injectable download for hermetic tests) and graceful degradation (chat disabled but the extension still activates) are exactly right.

Two inline notes — one's a question for you on the leftover AMICO_* env wiring, the other a CI-cost suggestion. Neither blocks.

cwd: opencodeProject.projectDir,
env: {
PATH: `${binDir}:${process.env.PATH ?? ""}`,
AMICO_JULIA_SCRIPT: juliaScript,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rchari1 — this AMICO_* env + PATH=binDir:$PATH injection looks like leftover spike wiring, and it cuts against β.1's all-argv / no-AMICO_* contract (S37 / Q90 — amico-run takes everything via argv, nothing from env). I'm inclined to kill it. Before we rip it out: is there something the opencode server still needs these for (a tool the chat slice invokes that reads them), or can β.3 pass them through amico-run flags instead? Want your read.

- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- run: pnpm install --frozen-lockfile
- run: pnpm --filter amicode-v2 fetch:opencode

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both matrix legs re-download ~157MB on every run. Worth an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json'), restoring packages/extension/vendor/ before this step — the .sha256 idempotency stamp already makes fetch:opencode a no-op on a cache hit, so unchanged pins skip the download entirely.

Rchari1and others added 6 commits June 17, 2026 12:13
…xpected-throw→exit 64, updateLatest per-runId temp (concurrent-submit race), version single-sourced from package.json; solve_common.jl on Piccolo 1.19 via public Piccolo.Callbacks (no reach-through)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n hashes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ion (S35)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e spike smoke tests
v1.17.3 passes: GET /event → 200 text/event-stream against a synthesized
project, clean SIGTERM exit. No walk-back needed despite the 1.3.x-era spike.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e matrix; .vscodeignore ships vendor/
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/beta2-vendor-opencode branch from 4bb031b to 26d9018CompareJune 17, 2026 16:14
@Rchari1

Copy link
Copy Markdown
MemberAuthor

Thanks — on your two notes:

  • AMICO_* env + PATH=binDir:$PATH (extension.ts:88): you're right it's leftover spike wiring against β.1's all-argv/no-env contract (S37/Q90). Already removed in β.3+β.5: AGENTS.md + vetted template + chat→solve→inspector slice (closes #3) #9 (β.3 Task 4): the spawn env no longer carries AMICO_JULIA_SCRIPT/PROJECT/RUNS_ROOT — amico-run is argv-only, and chat→solve drives it purely via flags. PATH now carries only the amico-run launcher dir (so opencode's bash can resolve amico-run); the Julia project reaches the agent through AGENTS.md (substituted at session-copy), passed as --project. So nothing reads those env vars anymore.
  • CI cache for the 157MB opencode download: good call — I'll add an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json') restoring packages/extension/vendor/ before fetch:opencode (the .sha256 stamp already makes it a no-op on a cache hit). Tracking it as a fast-follow so it doesn't churn the stack mid-review; flag if you'd rather I fold it in now.

(Branch force-updated from the β.1 rebase — same content, just restacked on the #7 fixes.)

@jack-champagne
jack-champagne deleted the branch mainJune 18, 2026 06:29
@jack-champagne
jack-champagne changed the base branch from rchari/beta1-amico-run to mainJune 18, 2026 06:31
#7 was squash-merged (4415f02), flattening beta1's history; beta2 already
contains beta1's changes via its original commits, so this records main as an
ancestor without altering beta2's tree (-s ours). Lets #8 reach main with a
merge commit — no history rewrite, branch stays fast-forwardable.
@jack-champagne
jack-champagne merged commit eb978e2 into mainJun 19, 2026
3 checks passed
Sign up for freeto 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.

β.2 — Vendor + pin opencode in the VSIX

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

β.2: vendor + pin opencode (closes #2) - #8

Merged
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode
Jun 19, 2026
Merged

β.2: vendor + pin opencode (closes #2)#8
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Closes#2. Stacked on #7 (β.1 workspace layout) — base will retarget to main automatically when #7 merges.

Implements spec-20260610-155955-vendor-opencode (in amico#132): the extension no longer assumes opencode on $PATH.

What this is

  • opencode.lock.json — committed pin: opencode v1.17.3, per-platform SHA256 (darwin-arm64 + linux-x64). Bumping the pin = one-file PR, gated by CI.
  • scripts/fetch_opencode.mjs — zero-dep download-at-build: SHA256-verified against the manifest (hard fail, no retry/override on mismatch — supply-chain signal), unpack-to-temp + atomic rename, idempotent (.sha256 stamp → offline repeat builds), --record mode for pin bumps. vendor/ is gitignored.
  • src/opencode_binary.ts — resolution: config override (dev-only) → vendored path from the extension install dir → hard error with fetch/reinstall instructions. No $PATH fallback (§4 Assumption 4 stays dead). Config default "opencode""". On a missing binary the extension still activates (inspector/watcher/commands) with chat disabled.
  • test/boot_smoke.mjs — the S35 gate: synthesized project → vendored binary serveGET /event → 200 text/event-stream → clean SIGTERM exit. No LLM creds needed. Runs as a two-platform CI matrix (ubuntu-latest + macos-14) and as the named test:smoke script β.4's packaging step will call.
  • .vscodeignore — exists so vsce does NOT fall back to .gitignore (which would silently exclude the binary from the VSIX); !vendor/** negation makes the intent explicit.
  • Spike smoke tests deleted (smoke_cli, smoke_opencode_boot, opencode_boot_harness, vscode_shim); extension now has a real vitest unit suite (10 tests) in the fast CI job (pnpm -r run test).

AC → evidence

Issue ACEvidence
VSIX ships opencode at a fixed SHA; build fails unless /event SSE 200opencode.lock.json + fetcher mismatch tests; local smoke: GET /event → 200 (text/event-stream) … PASS on v1.17.3; CI boot-smoke matrix
ServerManager spawns the vendored binary, not $PATHopencode_binary.ts resolution tests; extension.ts wiring; config default ""

Notes

  • v1.17.3 passed the smoke on the first try — no walk-back needed despite the spike being written against 1.3.x. (β.5 owns any SSE payload drift; this PR guarantees boot + /event.)
  • Spec deviations (all noted in the plan): smoke file is boot_smoke.mjs (plain node) so vitest's glob can't pull a network test into the hermetic suite; the fetcher buffers the download in memory rather than a temp file (outcome-equivalent, nothing half-written); idempotent path prints up to date: instead of exiting silently.
  • For β.4: package with vsce package per platform after fetch:opencode --platform <target>; .vscodeignore already ships vendor/**.

🤖 Generated with Claude Code

Rchari1and others added 11 commits June 10, 2026 11:22
…ension
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ract enforcement
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ash spike (S31 grep green)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ontract end-to-end
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@jack-champagnejack-champagne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

β.2 looks solid — approving in spirit. Pulled the stacked branch locally and ran it end-to-end: build/typecheck green, fast tier 44 (amico-run) + 10 (extension) passing, fetch:opencode downloaded the real v1.17.3 linux-x64 and the committed SHA verified against the live GitHub release, and test:smoke drove the real binary to GET /event → 200 text/event-stream with a clean SIGTERM exit. CI is green on all three jobs, so the darwin-arm64 pin is machine-gated too. Supply-chain handling (archive-hash-before-unpack, hard-fail with no override, atomic temp→rename install, injectable download for hermetic tests) and graceful degradation (chat disabled but the extension still activates) are exactly right.

Two inline notes — one's a question for you on the leftover AMICO_* env wiring, the other a CI-cost suggestion. Neither blocks.

cwd: opencodeProject.projectDir,
env: {
PATH: `${binDir}:${process.env.PATH ?? ""}`,
AMICO_JULIA_SCRIPT: juliaScript,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rchari1 — this AMICO_* env + PATH=binDir:$PATH injection looks like leftover spike wiring, and it cuts against β.1's all-argv / no-AMICO_* contract (S37 / Q90 — amico-run takes everything via argv, nothing from env). I'm inclined to kill it. Before we rip it out: is there something the opencode server still needs these for (a tool the chat slice invokes that reads them), or can β.3 pass them through amico-run flags instead? Want your read.

- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- run: pnpm install --frozen-lockfile
- run: pnpm --filter amicode-v2 fetch:opencode

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both matrix legs re-download ~157MB on every run. Worth an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json'), restoring packages/extension/vendor/ before this step — the .sha256 idempotency stamp already makes fetch:opencode a no-op on a cache hit, so unchanged pins skip the download entirely.

Rchari1and others added 6 commits June 17, 2026 12:13
…xpected-throw→exit 64, updateLatest per-runId temp (concurrent-submit race), version single-sourced from package.json; solve_common.jl on Piccolo 1.19 via public Piccolo.Callbacks (no reach-through)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n hashes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ion (S35)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e spike smoke tests
v1.17.3 passes: GET /event → 200 text/event-stream against a synthesized
project, clean SIGTERM exit. No walk-back needed despite the 1.3.x-era spike.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e matrix; .vscodeignore ships vendor/
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/beta2-vendor-opencode branch from 4bb031b to 26d9018CompareJune 17, 2026 16:14
@Rchari1

Copy link
Copy Markdown
MemberAuthor

Thanks — on your two notes:

  • AMICO_* env + PATH=binDir:$PATH (extension.ts:88): you're right it's leftover spike wiring against β.1's all-argv/no-env contract (S37/Q90). Already removed in β.3+β.5: AGENTS.md + vetted template + chat→solve→inspector slice (closes #3) #9 (β.3 Task 4): the spawn env no longer carries AMICO_JULIA_SCRIPT/PROJECT/RUNS_ROOT — amico-run is argv-only, and chat→solve drives it purely via flags. PATH now carries only the amico-run launcher dir (so opencode's bash can resolve amico-run); the Julia project reaches the agent through AGENTS.md (substituted at session-copy), passed as --project. So nothing reads those env vars anymore.
  • CI cache for the 157MB opencode download: good call — I'll add an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json') restoring packages/extension/vendor/ before fetch:opencode (the .sha256 stamp already makes it a no-op on a cache hit). Tracking it as a fast-follow so it doesn't churn the stack mid-review; flag if you'd rather I fold it in now.

(Branch force-updated from the β.1 rebase — same content, just restacked on the #7 fixes.)

@jack-champagne
jack-champagne deleted the branch mainJune 18, 2026 06:29
@jack-champagne
jack-champagne changed the base branch from rchari/beta1-amico-run to mainJune 18, 2026 06:31
#7 was squash-merged (4415f02), flattening beta1's history; beta2 already
contains beta1's changes via its original commits, so this records main as an
ancestor without altering beta2's tree (-s ours). Lets #8 reach main with a
merge commit — no history rewrite, branch stays fast-forwardable.
@jack-champagne
jack-champagne merged commit eb978e2 into mainJun 19, 2026
3 checks passed
Sign up for freeto 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.

β.2 — Vendor + pin opencode in the VSIX

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

β.2: vendor + pin opencode (closes #2) - #8

Merged
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode
Jun 19, 2026
Merged

β.2: vendor + pin opencode (closes #2)#8
jack-champagne merged 18 commits into
mainfrom
rchari/beta2-vendor-opencode

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Closes#2. Stacked on #7 (β.1 workspace layout) — base will retarget to main automatically when #7 merges.

Implements spec-20260610-155955-vendor-opencode (in amico#132): the extension no longer assumes opencode on $PATH.

What this is

  • opencode.lock.json — committed pin: opencode v1.17.3, per-platform SHA256 (darwin-arm64 + linux-x64). Bumping the pin = one-file PR, gated by CI.
  • scripts/fetch_opencode.mjs — zero-dep download-at-build: SHA256-verified against the manifest (hard fail, no retry/override on mismatch — supply-chain signal), unpack-to-temp + atomic rename, idempotent (.sha256 stamp → offline repeat builds), --record mode for pin bumps. vendor/ is gitignored.
  • src/opencode_binary.ts — resolution: config override (dev-only) → vendored path from the extension install dir → hard error with fetch/reinstall instructions. No $PATH fallback (§4 Assumption 4 stays dead). Config default "opencode""". On a missing binary the extension still activates (inspector/watcher/commands) with chat disabled.
  • test/boot_smoke.mjs — the S35 gate: synthesized project → vendored binary serveGET /event → 200 text/event-stream → clean SIGTERM exit. No LLM creds needed. Runs as a two-platform CI matrix (ubuntu-latest + macos-14) and as the named test:smoke script β.4's packaging step will call.
  • .vscodeignore — exists so vsce does NOT fall back to .gitignore (which would silently exclude the binary from the VSIX); !vendor/** negation makes the intent explicit.
  • Spike smoke tests deleted (smoke_cli, smoke_opencode_boot, opencode_boot_harness, vscode_shim); extension now has a real vitest unit suite (10 tests) in the fast CI job (pnpm -r run test).

AC → evidence

Issue ACEvidence
VSIX ships opencode at a fixed SHA; build fails unless /event SSE 200opencode.lock.json + fetcher mismatch tests; local smoke: GET /event → 200 (text/event-stream) … PASS on v1.17.3; CI boot-smoke matrix
ServerManager spawns the vendored binary, not $PATHopencode_binary.ts resolution tests; extension.ts wiring; config default ""

Notes

  • v1.17.3 passed the smoke on the first try — no walk-back needed despite the spike being written against 1.3.x. (β.5 owns any SSE payload drift; this PR guarantees boot + /event.)
  • Spec deviations (all noted in the plan): smoke file is boot_smoke.mjs (plain node) so vitest's glob can't pull a network test into the hermetic suite; the fetcher buffers the download in memory rather than a temp file (outcome-equivalent, nothing half-written); idempotent path prints up to date: instead of exiting silently.
  • For β.4: package with vsce package per platform after fetch:opencode --platform <target>; .vscodeignore already ships vendor/**.

🤖 Generated with Claude Code

Rchari1and others added 11 commits June 10, 2026 11:22
…ension
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ract enforcement
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ash spike (S31 grep green)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ontract end-to-end
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@jack-champagnejack-champagne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

β.2 looks solid — approving in spirit. Pulled the stacked branch locally and ran it end-to-end: build/typecheck green, fast tier 44 (amico-run) + 10 (extension) passing, fetch:opencode downloaded the real v1.17.3 linux-x64 and the committed SHA verified against the live GitHub release, and test:smoke drove the real binary to GET /event → 200 text/event-stream with a clean SIGTERM exit. CI is green on all three jobs, so the darwin-arm64 pin is machine-gated too. Supply-chain handling (archive-hash-before-unpack, hard-fail with no override, atomic temp→rename install, injectable download for hermetic tests) and graceful degradation (chat disabled but the extension still activates) are exactly right.

Two inline notes — one's a question for you on the leftover AMICO_* env wiring, the other a CI-cost suggestion. Neither blocks.

cwd: opencodeProject.projectDir,
env: {
PATH: `${binDir}:${process.env.PATH ?? ""}`,
AMICO_JULIA_SCRIPT: juliaScript,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rchari1 — this AMICO_* env + PATH=binDir:$PATH injection looks like leftover spike wiring, and it cuts against β.1's all-argv / no-AMICO_* contract (S37 / Q90 — amico-run takes everything via argv, nothing from env). I'm inclined to kill it. Before we rip it out: is there something the opencode server still needs these for (a tool the chat slice invokes that reads them), or can β.3 pass them through amico-run flags instead? Want your read.

- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- run: pnpm install --frozen-lockfile
- run: pnpm --filter amicode-v2 fetch:opencode

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both matrix legs re-download ~157MB on every run. Worth an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json'), restoring packages/extension/vendor/ before this step — the .sha256 idempotency stamp already makes fetch:opencode a no-op on a cache hit, so unchanged pins skip the download entirely.

Rchari1and others added 6 commits June 17, 2026 12:13
…xpected-throw→exit 64, updateLatest per-runId temp (concurrent-submit race), version single-sourced from package.json; solve_common.jl on Piccolo 1.19 via public Piccolo.Callbacks (no reach-through)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n hashes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ion (S35)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e spike smoke tests
v1.17.3 passes: GET /event → 200 text/event-stream against a synthesized
project, clean SIGTERM exit. No walk-back needed despite the 1.3.x-era spike.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e matrix; .vscodeignore ships vendor/
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/beta2-vendor-opencode branch from 4bb031b to 26d9018CompareJune 17, 2026 16:14
@Rchari1

Copy link
Copy Markdown
MemberAuthor

Thanks — on your two notes:

  • AMICO_* env + PATH=binDir:$PATH (extension.ts:88): you're right it's leftover spike wiring against β.1's all-argv/no-env contract (S37/Q90). Already removed in β.3+β.5: AGENTS.md + vetted template + chat→solve→inspector slice (closes #3) #9 (β.3 Task 4): the spawn env no longer carries AMICO_JULIA_SCRIPT/PROJECT/RUNS_ROOT — amico-run is argv-only, and chat→solve drives it purely via flags. PATH now carries only the amico-run launcher dir (so opencode's bash can resolve amico-run); the Julia project reaches the agent through AGENTS.md (substituted at session-copy), passed as --project. So nothing reads those env vars anymore.
  • CI cache for the 157MB opencode download: good call — I'll add an actions/cache step keyed on hashFiles('packages/extension/opencode.lock.json') restoring packages/extension/vendor/ before fetch:opencode (the .sha256 stamp already makes it a no-op on a cache hit). Tracking it as a fast-follow so it doesn't churn the stack mid-review; flag if you'd rather I fold it in now.

(Branch force-updated from the β.1 rebase — same content, just restacked on the #7 fixes.)

@jack-champagne
jack-champagne deleted the branch mainJune 18, 2026 06:29
@jack-champagne
jack-champagne changed the base branch from rchari/beta1-amico-run to mainJune 18, 2026 06:31
#7 was squash-merged (4415f02), flattening beta1's history; beta2 already
contains beta1's changes via its original commits, so this records main as an
ancestor without altering beta2's tree (-s ours). Lets #8 reach main with a
merge commit — no history rewrite, branch stays fast-forwardable.
@jack-champagne
jack-champagne merged commit eb978e2 into mainJun 19, 2026
3 checks passed
Sign up for freeto 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.

β.2 — Vendor + pin opencode in the VSIX

2 participants

@Rchari1@jack-champagne