Skip to content

feat: [v1.17.9] bridge merge upstream OpenCode v1.4.0 → v1.17.9#964

Open
anandgupta42 wants to merge 149 commits into
mainfrom
upstream/merge-v1.17.9
Open

feat: [v1.17.9] bridge merge upstream OpenCode v1.4.0 → v1.17.9#964
anandgupta42 wants to merge 149 commits into
mainfrom
upstream/merge-v1.17.9

Conversation

@anandgupta42

@anandgupta42 anandgupta42 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Bridges the fork from upstream OpenCode v1.4.0 → v1.17.9 (a no-common-ancestor tree-overlay merge of ~1850 files) and reconciles all fork customizations on top.

Highlights:

  • Effect-API migration: reconciled the fork's Promise/namespace code against upstream's Context.Service/Layer/Effect-Schema rewrite (Service facades + makeRuntime Promise wrappers; zod()↔Effect-Schema bridges; new Tool API via tool-zod-compat).
  • Bootstrap deadlock fixed: withStatics infinite recursion + a re-entrant runtime build that prevented the agent from running at all.
  • CI runtime aligned: the merge bumped the required bun@1.3.14 but CI/pre-push stayed on 1.3.10, which couldn't boot the merged CLI as a subprocess (748 false failures). All 6 CI pins → 1.3.14.
  • Test-suite DB migration race fixed: parallel test files replayed baseline CREATE TABLE migrations against an already-current schema (table \project` already exists, ~324 cascading fails). applyOnly()` now adopts the current schema when the journal diverges; test-DB reset preserves schema; boot-time project-copy refresh isolated. Production is unaffected (single-process boot migrates once — proven by 88/88 real-model e2e).
  • Branding regressions fixed: restored fork branding the merge re-leaked into system prompts/themes/httpapi, plus TUI leaks the regex scanner missed (sidebar wordmark split across JSX spans, home-screen tips pointing at the wrong binary/dirs/trigger, error hints, terminal title).
  • 8 dropped v1.17.9 session behaviors restored (partial bash-output forwarding, server_error retryable, content-filter→error, snapshot pre-capture, compaction.auto:false, shell expansion, signed-reasoning spacing, stop-with-tools continuation).
  • CLI instance-context regressions fixed: session tracing (run --trace) wrote no artifacts and skill list exited 1 — both threw InstanceRef not provided because the instance ALS isn't bridged for plain-async CLI facade calls (the instance AsyncLocalStorage is duplicated across the module boundary). Both now read through the in-process server client (sdk.config.get() / sdk.app.skills()), which holds the resolved instance. Verified in the built binary; regression tests added.

Type of change

  • Bug fix (non-breaking)
  • New feature (upstream version bump v1.4.0 → v1.17.9)
  • This change requires a documentation update

Issue for this PR

Closes #963

How did you verify your code works?

  • typecheck: 0 errors monorepo-wide (13/13 workspace tasks, enforced by the pre-push hook).
  • Unit suite green: full bun test = 10,455 pass / 0 functional fail after the DB-race fix (was ~324 inherent fails masked as the prior over-stated "1 fail"). Independently re-verified; 0 SQLiteError/database is locked/disk I/O residue. (One test was a local-only artifact — a dev's gcloud ADC made config.providers() return a google-vertex provider whose model variants/release_date fail the generated SDK's Declaration schema; the preload now isolates Google creds so local matches CI.)
  • Real-model e2e — compiled binary: 88/88 (100%) azure/gpt-5.5 across 22 coding/data tasks (dbt, sql-join, python, refactor, multi-step…), plus ~220 earlier azure/gpt-4o-mini runs.
  • TUI visually inspected (tmux capture of the binary): altimate logo, command palette, model/theme pickers, prompt→response loop, sidebar, help — all render correctly with no /api error flood.
  • Independent verification: a git-differential audit, a 3-agent accept-vs-restore jury, an independent TUI-upstream-diff audit (0 missing upstream TUI files/behaviors/commands), and 2 codex audits.

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code (// altimate_change markers)
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings (branding scan: 0 leaks; Marker Guard green)
  • I have added tests that prove my fix is effective (90+ new tests incl. DB-race regression)
  • New and existing unit tests pass locally

Known remaining work (tracked, non-blocking)

  • config.providers() returns model data (variants, release_date, experimentalOver200K) richer than the generated SDK's Declaration response schema for providers like google-vertex — the SDK schema/codegen should be regenerated to match (route works in production; only the strict SDK response-validator is behind).
  • Cosmetic: the default theme is still named opencode (renaming needs a config-compat alias).

Full validation artifacts under .github/meta/night-run/: NIGHT2-STATUS.md, DBRACE-FIX.md, WS3-VISUAL-FINDINGS.md, TUI-UPSTREAM-DIFF.md, e2e/GPT55-BINARY-RESULTS.md.

Post-merge tester-found regressions fixed (2026-07-01)

Real-world testing by @shreyastelkar (2026-06-30) surfaced regressions; all fixed on this branch, plus a post-merge audit that restored more silently-dropped fork behavior:

🤖 Generated with Claude Code

…on (checkpoint)

Bridge overlay of upstream OpenCode v1.4.0 -> v1.17.9 (3254 commits, no common
ancestor). This is a WIP checkpoint on the merge branch; NOT ready to merge.

Done:
- Overlaid 1850 upstream files via bridge-merge.ts; reapplied PR #18186 anthropic.
- Restored altimate bits in packages/opencode/package.json (name, bin altimate/
  altimate-code, deps @altimateai/altimate-core, @altimateai/drivers,
  @opencode-ai/util, yaml; test script without --only-failures).
- Pruned root workspaces (drop console/slack/stats), fixed repository URL.
- Dropped packages/stats (hosted dashboard) + added to skipFiles.
- Vendored 5 TUI attention mp3s into packages/tui; repointed @opencode-ai/ui audio.
- Deleted 246 confirmed-stale upstream files (present in v1.4.0, removed by v1.17.9,
  unmarked) via in-v1.4.0 discriminator; kept 174 fork-origin files.
- bun install GREEN; packages/core + packages/tui typecheck GREEN.

Remaining (tracked): re-derive ~72 kept marker/requireMarkers files onto v1.17.9 +
re-apply altimate_change blocks; migrate server/tui/util-extracted customizations;
effect beta.43->beta.74 API drift; update fork test suite to v1.17.9 APIs; apply
branding transforms to overlaid files; re-evaluate 62 upstream_fix markers.
…ook (checkpoint 2)

- Add fork-local Log shim at altimate/util/log.ts (upstream removed util/log.ts in
  the Effect-logging migration); repoint 16 altimate/memory imports to it.
- Repoint Flag -> @opencode-ai/core/flag/flag, Global -> @opencode-ai/core/global.
- Persist deep impact analysis: .github/meta/merge-v1179/PLAYBOOK.md (10-phase
  reconciliation runbook) + migrate/fix verdict JSON. Also copied to obsidian.

Remaining per PLAYBOOK (the heavy systemic rewrites): Effect-API call-site migration
(Config/Provider/LLM/MCP Promise wrappers removed), Tool API rewrite across 77
altimate/memory tools (zod->Effect Schema, execute->Effect), re-home 34 marker files
into packages/tui + packages/server, apply 7 KEEP + 13 KEEP-BRANDING upstream_fixes,
DROP 2, delete ~150 stale files, then typecheck/test green.
…ema re-apply (checkpoint 3)

Resolves the §2 Effect-only API migration for the altimate consumer surface by
restoring thin Promise wrappers (backed by the instance-bound `makeRuntime`
bridge, so reads stay per-workspace) instead of churning 100+ call sites:

- `Config`: restore get/getGlobal/getConsoleState/update/invalidate/directories
  Promise wrappers (40+ `await Config.get()` callers, upstream-shared + altimate).
- `MCP`: restore status/tools/add/connect/disconnect wrappers; repoint datamate's
  `MCP.remove` -> `MCP.disconnect` (session-runtime removal; config purge is separate).
- `Skill`: restore `all()` wrapper for project-scan's environment census.

Mechanical §2 repoints (all fork-original altimate files):
- `Installation.VERSION` -> `InstallationVersion` (@opencode-ai/core/installation/version).
- glob -> `@opencode-ai/core/util/glob`; post-filter ignore dirs (core Glob.Options
  dropped the `ignore` field).
- `Config.Mcp` -> `ConfigMCPV1.Info` (@opencode-ai/core/v1/config/mcp).
- project-scan: removed Flag experimental keys -> direct process.env census reads.

Config-schema fidelity (core v1/config/config.ts, re-applied from main):
- top-level `tracing` block (enabled/dir/maxFiles/exporters), zod -> Effect Schema.
- experimental toggles dropped by the overlay: auto_enhance_prompt,
  env_fingerprint_skill_selection, auto_mcp_discovery.

Also lands the prior-session Tool-API adapter shim (altimate/tool-zod-compat.ts)
referenced by tool/tool.ts — the recipe to bridge the 77 old-shape zod/Promise
tools onto the new Effect Tool API without rewriting each.

altimate/ typecheck surface: 37 -> 3 errors (the 3 remaining are the §2.12 Tool-API
rewrites in altimate-core-rewrite.ts + tool-lookup.ts). Package total 3181 -> 3040;
the remainder is the stale-file delete (§3.4) + TUI/server re-home (§4) phases.

Marker guard --strict still fails on pre-existing broad-overlay debt (125 unmarked
sites across sdk/turbo/etc untouched here); my additions are balanced and marked.
…point 4)

Closes the last 3 typecheck errors in the fork's own src/altimate/** tree via the
tool-zod-compat adapter (§2.12):

- altimate-core-rewrite.ts: annotate execute return as the shim's `LegacyResult` so
  the legacy `Tool.define` overload's metadata type (M) infers cleanly. This tool's
  execute omits the `ctx` param, so M was being inferred from a complex multi-branch
  return union and failing overload resolution. `args` still types from `parameters`.
- tool-lookup.ts: upstream's Tool rewrite made `info.init()` an Effect (was a Promise)
  and `parameters` an Effect Schema (was zod). Run the init Effect via
  `Effect.runPromise` and describe parameters from `Def.jsonSchema` (JSON Schema,
  populated for both native tools and our legacy zod tools) instead of the removed
  zod introspection. New `describeJsonSchema`/`inferJsonType` replace the zod walkers.

src/altimate/** now typechecks with 0 errors (was 37 at the start of this resume).
Package total 3040 -> 3037; the remainder is upstream-shared restructure: stale-file
deletion (§3.4) + TUI/server re-home (§4) + Effect migration of survivor files.
…ages/tui (checkpoint 5)

The TUI was extracted upstream to packages/tui (live) from cli/cmd/tui/** (dead — no
@tui alias resolves it). Re-apply the fork customizations into the live package,
preserving altimate_change markers. packages/tui + packages/core both typecheck GREEN.

Re-homed (functional + branding):
- context/sdk.tsx — smooth-streaming delta pre-merge (ALTIMATE_SMOOTH_STREAMING).
  Adapted to v2 GlobalEvent (discriminant nested under `.payload`, not top-level).
- routes/session/footer.tsx — YOLO-mode badge (ALTIMATE_CLI_YOLO).
- routes/session/sidebar.tsx — "Altimate Code" branding (uses InstallationVersion).
- component/logo.tsx — restore brand colors (primary/accent vs textMuted/text) in the
  rewritten 8-arg renderLine call-site.
- component/dialog-status.tsx — `altimate mcp auth` branding fix.
- component/error-component.tsx — `altimate-code: fatal:` title + AltimateAI/altimate-code
  issue URL (was anomalyco/opencode brand leak).
- context/route.tsx — restore dropped navigate debug log (console.debug; tui has no
  structured logger).

Flag re-home (packages/core/src/flag/flag.ts): added ALTIMATE_CALM_MODE,
ALTIMATE_SMOOTH_STREAMING, ALTIMATE_CLI_YOLO getters + altTruthy helper, since packages/tui
depends on @opencode-ai/core (not opencode) and could not otherwise see the fork flags.

MOOT (not re-applied — upstream issue gone): dialog-mcp / dialog-workspace-list logger
fixes (tui uses console.* throughout, has no structured logger, the old console.log/debug
prints don't exist in the rewritten files).

DEFERRED (tracked, code re-architected into other owner files — next pass):
- theme #704 light-fg + code-block/inline-code bg → packages/tui/src/theme/index.ts
  (generateSystem/getSyntaxRules). One human decision: inline-code backgroundElement vs
  upstream's new background.
- beginner/first-time tips + onboarding hint → feature-plugins/home/{tips,tips-view}.tsx
  (home is now a plugin-slot shell).
- UpgradeIndicator: component + utils exist only in the old tree, not ported → blocks the
  footer + home upgrade-indicator blocks until ported into packages/tui/src/component.
- sidebar trace section → sidebar_content plugin slot.

OLD cli/cmd/tui/** files untouched (deleted later in §3.4 after all re-homing verified).
… flags (checkpoint 6)

Second re-homing wave into packages/tui (live TUI). packages/tui + packages/core both
typecheck GREEN.

Re-homed (functional):
- context/sync.tsx — full streaming feature set: yolo auto-approve (adapted to the new
  permission.reply API: workspace arg + reply:"once"), smooth-streaming direct-path delta
  update, and the complete line-streaming buffer feature (lineBuffer + flushLineBuffer +
  flushAllBuffersForMessage + the 5 event-handler hooks). event.type/.properties is correct
  here (useEvent unwraps GlobalEvent.payload, unlike sdk.tsx).
- routes/session/index.tsx — `builder` agent name on plan_exit, smooth-streaming scroll
  (toBottom 0ms), calm-mode content width cap (maxWidth via ALTIMATE_CONTENT_MAX_WIDTH).
- theme/index.ts — light-mode fg fallback (#704), code-block + inline-code backgrounds for
  light-theme contrast. NOTE: inline-code uses theme.backgroundElement vs upstream's new
  theme.background — flagged inline for the next merge's human review.
- feature-plugins/home/tips-view.tsx — fork DE-specific tips (/discover, /cost-report,
  /dbt-docs, /sql-review, /migrate-sql, lineage, anti-patterns) folded into the new Tip pool.

Flags re-homed into packages/core/src/flag/flag.ts (tui depends on core, not opencode):
ALTIMATE_LINE_STREAMING, ALTIMATE_CONTENT_MAX_WIDTH (+ numberEnv helper), joining the
ALTIMATE_CALM_MODE/SMOOTH_STREAMING/CLI_YOLO added in checkpoint 5.

MOOT (upstream v1.17.9 shipped equivalents — dropped per upstream_fix rule):
- prompt skills-dialog keybind → upstream `prompt_skills` keybind.
- session workspace-gate, smooth-streaming memoize, light-theme md fg (upstream ships
  fg=markdownText + bg=background).

DEFERRED — architectural (tracked): enhance feature (enhance-prompt.ts), dialog-provider
(AltimateApi), dialog-skill (skill-helpers + keymap port). All three depend on opencode-package
code unreachable from packages/tui — need the shared code moved into @opencode-ai/core, routed
via SDK/server, or implemented as tui plugins. Real features; not dropped.

DEFERRED — render-rewritten: session/index TextPart code-during-streaming, tips first-time-only
behavior, sidebar trace section (sidebar_content slot), footer/home UpgradeIndicator (component
not yet ported into packages/tui).

OLD cli/cmd/tui/** files untouched (deleted in §3.4 after all re-homing verified).
…ckpoint 7)

app.tsx re-home into packages/tui/src/app.tsx + UpgradeIndicator component port.
packages/tui + packages/core both typecheck GREEN.

app.tsx (5 applied):
- terminal-detection: created fork-original packages/tui/src/terminal-detection.ts
  (detectModeFromCOLORFGBG, #704) + eager COLORFGBG light-mode short-circuit in the
  theme-detection path (avoids the 1s waitForThemeMode delay).
- branding: docs URL opencode.ai/docs -> docs.altimate.sh; DialogAlert update message
  "OpenCode v…" -> "Altimate Code v…".
app.tsx MOOT (2): variant_list keybind (upstream v1.17.9 shipped PR #21185 natively);
disableStdoutInterception (opentui API removed; renderer externalOutputMode handles it).
app.tsx DEFERRED (7): trace-viewer feature — depends on opencode-side altimate/observability
(Trace/renderTraceViewer/DialogTraceList), unreachable from packages/tui. Same architectural
blocker as the dialogs/enhance (task: expose opencode deps to tui).

UpgradeIndicator port (fork-original, was deferred — now unblocked since it only needed
Installation.VERSION = InstallationVersion in core):
- packages/tui/src/component/upgrade-indicator{,-utils}.tsx — repointed imports to the tui
  layout, Installation.VERSION -> InstallationVersion. Added semver + @types/semver to
  packages/tui (were opencode-only deps).
- routes/session/footer.tsx — wired <UpgradeIndicator /> back into the session footer.
(home-screen UpgradeIndicator still deferred — lives in the new feature-plugins/home/footer
plugin, a different surface.)

OLD cli/cmd/tui/** files untouched (deleted in §3.4 after remaining re-homing/decisions).
…(checkpoint 8)

The old TUI tree packages/opencode/src/cli/cmd/tui/** (31 files) is dead: the live TUI is
packages/tui (@opencode-ai/tui), launched via cli/cmd/tui.ts; opencode has no @tui path
alias so the old tree never resolved. All its fork customizations were re-homed into
packages/tui (checkpoints 5-7) or documented as architecturally-deferred; the originals
remain on main + git history for reference.

- Repoint the one live cross-import: server/routes/session.ts formatTranscript now imports
  from @opencode-ai/tui/util/transcript (the util moved to packages/tui). Added the
  ./util/transcript entry to packages/tui's exports map.
- git rm -r packages/opencode/src/cli/cmd/tui (31 files).

opencode typecheck: 3037 -> 2582 errors (-455, the dead TUI tree).

CORRECTION to the earlier deletion plan: server/server.ts is NOT stale — cli/cmd/serve.ts
loads it as the live server (it is the Hono server; upstream's httpapi tree is unused here).
So the server cluster (~282 errors) is SURVIVOR reconciliation (restore the hono dep, repoint
moved imports util/log/bus/error/permission-schema), not deletion. Next cluster.
hono + hono-openapi were dropped from packages/opencode/package.json during the overlay
(present on main as catalog: refs, still in the workspace catalog). The live Hono server
(server/server.ts, loaded by cli/cmd/serve.ts) and its routes need them. Re-added both as
catalog: deps.

opencode typecheck: 2582 -> 2486 (-96; 27 direct hono module errors + cascades resolved).

Remaining are per-file survivor reconciliation: moved-module repoints (util/log, @/bus,
../error → core/shims) and Effect-API migration in survivor files (provider/server/session),
plus the test suite. No more dropped-dep batch wins (only bun-pty left, 2 errors in a
stale pty file that moved to core).
…ckpoint 10)

Restore re-export shims at the old util/* paths upstream deleted when those utils moved to
@opencode-ai/core, so survivor + test importers resolve without per-file repoints (the
established §2.13 shim pattern, same as error/token/locale):
- src/util/log.ts   -> @/altimate/util/log (fork Log successor)
- src/util/glob.ts  -> @opencode-ai/core/util/glob (Glob)
- src/util/flock.ts -> @opencode-ai/core/util/flock (Flock)

opencode typecheck: 2582 -> 2431 across checkpoints 8-10 (TUI delete -455, hono dep -96,
util/log shim -39, glob/flock shims -16).

Remaining ~2431 = heavy per-file survivor reconciliation (no more batch wins): @/bus API
change (BusEvent->EventV2), server route modules, provider/session Effect-API migration,
and the test suite (~1446) which tracks src once src is green.
…scaffold (checkpoint 11)

Architectural decision for the v1.17.9 TUI extraction: fork TUI features that depend on
opencode-package code (AltimateApi, enhance-prompt, observability) are implemented as
host-registered TuiPlugins living in opencode-side fork-owned files — NOT as edits inside
upstream packages/tui. This keeps upstream packages/tui byte-for-byte upstream (clean future
merges) while the plugins retain their opencode deps and render via TuiPluginApi
(slots/command/keymap/dialog/client). Full rationale + per-feature re-home plan:
docs/internal/2026-06-23-tui-fork-features-as-plugins-adr.md.

- New: packages/opencode/src/plugin/tui/altimate/index.ts — altimateTuiPlugins() aggregator.
- Wire: plugin/tui/internal.ts appends altimateTuiPlugins(...) to the builtin plugin list
  (the host already composes the TUI plugin set, so this is the natural injection point).

Compiles clean (opencode typecheck unchanged at 2431). The 4 deferred features
(provider-credentials, skill-ops, prompt-enhance, trace-viewer) are ported into this directory
next, per the ADR; their pre-merge sources are preserved on main.
…checkpoint 12)

Per the ADR (docs/internal/2026-06-23-tui-fork-features-as-plugins-adr.md), the fork TUI
features that depend on opencode-package code are now plugins in
packages/opencode/src/plugin/tui/altimate/, registered via altimateTuiPlugins() into the host
plugin list. Upstream packages/tui stays untouched. opencode typecheck unchanged at 2431 (all
4 plugins compile clean).

- provider-credentials.tsx — palette cmd "Connect altimate-backend" → credential DialogPrompt
  backed by AltimateApi.{parseAltimateKey,validateCredentials,saveCredentials}.
- skill-ops.tsx — "/skills" list (api.client.app.skills + detectToolReferences categorization),
  create/install/test/show/edit/remove ops, ctrl+a/n/i → registered commands.
- trace-viewer.tsx — "/trace" command + trace-list dialog + open-in-browser, with the
  Bun.serve trace viewer server kept opencode-side (renderTraceViewer/Trace.* from
  altimate/observability). This is exactly why it belongs in an opencode-side plugin.
- prompt-enhance.tsx — "enhance prompt" command + enhancePrompt logic ready; the prompt
  read/write is gated on a small plugin-API extension (api.prompt.active(): TuiPromptRef) that
  TuiPluginApi doesn't yet expose — tracked as the next step to fully restore it.

Each file is fork-owned and fully wrapped in altimate_change markers. Documented per-plugin
deferrals (all needing a typed SDK/api addition, none a feature drop): skill cache-reload flag,
per-dialog keybind scoping, provider in-list trigger, prompt active-ref accessor.
…extension (checkpoint 13)

Completes the prompt-enhance fork feature. The plugin api had no accessor for the active prompt
input, so the enhance read/write was deferred (ckpt 12). Added the sanctioned plugin-contract
extension (the designed extension point — not inline edits scattered through upstream render code):

- packages/plugin/src/tui.ts — add `prompt: { active(): TuiPromptRef | undefined }` to TuiPluginApi.
- packages/tui/src/plugin/adapters.tsx — implement it from the host's usePromptRef context
  (PromptRef is structurally TuiPromptRef); thread promptRef through the adapter Input.
- packages/tui/src/app.tsx — pass the already-available promptRef into createTuiApiAdapters.
- packages/opencode/src/plugin/tui/runtime.ts — pass api.prompt through the scoped legacy host api.
- packages/opencode/test/fixture/tui-plugin.ts — add prompt.active() to the test api mock.
- altimate/prompt-enhance.tsx — the "Enhance prompt" command now reads api.prompt.active().current.input,
  awaits enhancePrompt(), and writes back via ref.set(). Auto-enhance-before-submit stays deferred
  (needs a pre-submit hook; isAutoEnhanceEnabled kept ready).

All four fork TUI plugins are now functional. packages/tui + packages/core + packages/plugin green;
opencode unchanged at 2431. All additions altimate_change-marked.
…oint 14)

Re-export shims for util modules upstream moved into @opencode-ai/core:
- src/util/hash.ts  -> @opencode-ai/core/util/hash
- src/util/which.ts -> @opencode-ai/core/util/which
- src/file/ripgrep.ts -> @opencode-ai/core/ripgrep

opencode 2431 -> 2428. Cheap module-shim wins are now exhausted: remaining importers fail on
deeper Effect-API breaks too, so shimming one import no longer makes a file green. The rest of
task #7 (provider.ts 106, session/prompt 73, session/index 72, server/* — Auth/Env makeRuntime
compat wrappers + @/bus EventV2 migration + dep drift LanguageModelV2->V3) is per-file survivor
reconciliation. util/fn, util/context, util/abort, util/lock, shell/shell still need locating
(moved out of the dropped @opencode-ai/util package, not yet found in core).
…kpoint 15)

Same proven makeRuntime compat-wrapper pattern as Config/MCP/Skill (ckpt 3): upstream removed the
imperative Promise wrappers on Auth and Env in the Effect-only migration, but survivor files
(provider/provider.ts, session/llm.ts, server/server.ts + provider tests) still call
`await Auth.get()` / `Env.set()` etc. Both Services retain get/all/set/remove as Effect methods
with self-contained defaultLayers, so the wrappers are a clean restore (instance-bound runtime
keeps reads/writes scoped):

- src/auth/index.ts — restore get/all/set/remove Promise wrappers.
- src/env/index.ts  — restore get/all/set/remove Promise wrappers.

opencode 2428 -> 2298 (-130). Both modules typecheck clean. Confirms compat wrappers are the
high-leverage lever for the remaining survivor Effect-API breaks (next: Provider.defaultModel/
getModel/getSmallModel, LLM.stream).
Env is backed by process.env (no async IO) and fork callers read it synchronously
(provider/provider.ts: `const env = Env.all(); env[key]`, and `Env.get()` assigned to string).
The previous async Promise wrappers (ckpt 15) produced Promise-vs-value type errors. Switch the
Env wrappers to makeRuntime runSync, returning plain values — matching the pre-merge sync Env API.
(Auth stays async: it does file IO.)

opencode 2298 -> 2284. Env module clean.
…eckpoint 17)

Upstream moved the version constant to InstallationVersion (@opencode-ai/core/installation/version).
Add `export const VERSION = InstallationVersion` to src/installation/index.ts so the many survivor
callers of Installation.VERSION resolve without per-file repoints (single-line shim; the module
already imports InstallationVersion).

opencode 2284 -> 2240 (-44). Session-resume cumulative: 3181 -> 2240 (-941).
…code-ai/util imports (ckpt 18)

The @opencode-ai/util package was removed in the extraction; survivor files still imported from it.
- Restore src/util/fn.ts (the zod fn() helper, from main) — it has no @opencode-ai/core home.
- Repoint across 14 survivor files: @opencode-ai/util/{error,slug,lazy} -> @opencode-ai/core/util/*;
  @opencode-ai/util/fn -> @/util/fn.

opencode 2240 -> 2226.
…ll shim (ckpt 19)

- Restore src/util/{context,abort,lock}.ts from main (self-contained fork utils with no
  @opencode-ai/core home — context uses AsyncLocalStorage, abort/lock have no imports).
- src/shell/shell.ts re-export shim: `export * as Shell from "@opencode-ai/core/shell"` (core
  ships flat exports; fork callers import the Shell namespace).

opencode 2226 -> 2216. Remaining module-not-found is mostly @/bus (a real BusEvent->EventV2
migration, not a shim) + per-file survivor work.
…ckpoint 20)

The fork keeps the Bus pattern (bus-event.ts BusEvent.define + bus/global.ts GlobalBus both
survive, and ~14 files + 60+ call sites use the Bus namespace), but bus/index.ts was dropped in
the overlay. Restored it from main and fixed the one Effect-version drift: ServiceMap.Service ->
Context.Service (ServiceMap was removed from effect; matches the env/config Service pattern).

opencode 2216 -> 2197. bus/index.ts typechecks clean; resolves the @/bus import + Bus.publish/
subscribe call sites across server/session/provider.
…fix (checkpoint 21)

- src/util/schema.ts re-export shim: `export * from "@opencode-ai/core/schema"` (withStatics et al
  moved to core).
- src/provider/schema.ts: new Effect Schema brand constructor is `.make()` not `.makeUnsafe()`.
  Fixed the 15 ProviderID/ModelID brand constructions. The fork keeps its branded ProviderID/ModelID
  (callers use ProviderID.make()/.opencode etc.) — only the internal Schema API updated.

opencode 2197 -> 2109 (-88; the brand fix cascades across all provider/model-ID usages in
provider.ts, session/prompt.ts, share-next.ts, tool/batch.ts). Session-resume: 3181 -> 2109.
…shims (checkpoint 22)

Re-export shims for modules moved to @opencode-ai/core:
- src/permission/schema.ts -> core/permission/schema
- src/project/schema.ts -> core/project/schema
- src/filesystem.ts -> core/filesystem
- src/npm/index.ts -> core/npm

opencode 2109 -> 2108 (low net — resolving these imports exposes the importing files' deeper
type errors). Module-not-found shims now largely exhausted; remaining ~2108 is per-file type work
(TS2339 Service/branded, TS2345/2322 type mismatches, Effect call sites) + ~1240 tests.
Delete 7 test files that import the deleted cli/cmd/tui tree (upgrade-indicator, theme
light-mode #704, worker, thread). The features they covered were re-homed into packages/tui /
the fork plugins; these tests are unrunnable here. Recoverable from main; test coverage should be
re-homed to packages/tui in a follow-up.

opencode 2108 -> 2093 (src 788 / test 1302). Remaining is deep per-file Effect-API migration in
the session/provider/server survivors + the test suite tracking those API changes.
… core (checkpoint 24)

session/project Drizzle table definitions moved to @opencode-ai/core/{session,project}/sql; some
survivor files still imported the old ./session.sql / ./project.sql paths (which now resolve to
the raw `*.sql` ambient module, hence the "no exported member MessageTable" errors). Repointed
message-v2.ts, session/projectors.ts, server/projectors.ts, project/project.ts to the core paths.

opencode 2093 -> 2091. Cross-cutting wins now exhausted; remaining is deep per-file Effect/Schema/
Drizzle migration in the session/provider/server survivors + their tests.
…(checkpoint 25)

Four highest-error survivor files driven to 0 (3 via parallel subagents + provider by hand);
src 788 -> 653, total 2091 -> 1977.

- provider/provider.ts (106->0 cumulative): LanguageModelV2->V3 alias, ./sdk/copilot ->
  @opencode-ai/core/github-copilot/copilot-provider, @gitlab/gitlab-ai-provider ->
  gitlab-ai-provider (upstream rename, dep already present), NamedError.create zod->Effect Schema
  fields (+ import Schema), interleaved.field enum += "reasoning".
- session/message-v2.ts (28->0): zod NamedError kept via @opencode-ai/util/error; local zod brand
  schemas for SessionID/MessageID/PartID (.zod dropped on core brands); inline LSP.Range/FileDiff
  zod mirrors; convertToModelMessages now async (Effect.promise).
- session/index.ts (43->0): restored fork ProjectID (src/project/schema.ts) + re-added fork ID
  statics .zod/.make/.ascending (src/session/schema.ts) — unblocks ~10 consumer files; re-brand at
  the core-drizzle Project.ID<->ProjectID boundary; Storage.read via AppRuntime+Service.
- server/server.ts (20->0): restored dropped flat Hono routes + lsp/index.ts + server/error.ts +
  control-plane/schema.ts + util/effect-zod.ts from main; Promise wrappers on Vcs/Command/Agent/
  Format; WorkspaceID re-based on core WorkspaceV2.ID; zod() AST-walker at HTTP schema call sites.

NOTE: the restored flat route files (routes/{mcp,question,experimental,...}.ts) carry their own
internal API errors (why the overlay dropped them) — server.ts imports now resolve; their internals
are follow-up. All fork additions altimate_change-marked.
…eckpoint 26)

session/prompt, cli/cmd/run + run/tool, account/index, project/project, acp/service + directory,
tool/registry, session/session, session/processor — all driven to 0. Total 1977 -> 1757
(src 653 -> 451). Session-resume cumulative: 3181 -> 1757.

Patterns applied (all marker-wrapped): Promise-wrapper restores on more Service modules
(Agent.get/defaultAgent, SessionRevert.cleanup, SessionStatus.set/get, SessionSummary.summarize,
Command.get, MCP.readResource, Config.waitForDependencies, Snapshot.track/patch, Instruction
facade); EventV2 publish/subscribe via Bus shim / EventV2Bridge; Effect Tool-API exec loop
(AppRuntime.runPromise of init()/execute, ToolJsonSchema.fromTool, legacyToInit fromPlugin bridge);
ProviderV2/ModelV2/Project.ID <-> fork brand re-mapping with .make() at core-drizzle boundaries;
restored dropped fork tools tool/{ls,codesearch}.ts from main.

KNOWN STRUCTURAL FOLLOW-UP (surfaced by 4 agents): Provider / Plugin / Project / ToolRegistry are
fork namespace/Promise modules, but consumers (agent/agent.ts, project/instance-store, app-runtime,
session/tools) expect Effect Services (.Service/.defaultLayer/.node). Decide: migrate those modules
to Services vs adapt consumers. This is the next major cluster (agent.ts ~10 errs gated on it).
…heckpoint 27)

6-agent batch: server/routes/{session,mcp,experimental,question} + tool/batch + mcp/discover +
skill/discovery + plugin/openai/ws all -> 0. Total 1757 -> 1602 (src 451 -> 358). Session-resume
cumulative: 3181 -> 1602.

Patterns: zod() AST-walker (util/effect-zod) at resolver()/validator() sites for Effect-Schema
Info types; many more Promise wrappers (MCP.{resources,supportsOAuth,startAuth,finishAuth,
authenticate,removeAuth}, Worktree.{create,list,remove,reset}, Question.{list,reply,reject},
SessionStatus.list, Todo.get, SessionSummary.diff, SessionRevert.{revert,unrevert}); restored
fork PermissionID brand + ResponseStreamError/HeaderTimeoutError (provider/error.ts) + ConfigPaths
env-substitution helpers; Tool-API legacy form for BatchTool; ConfigMCPV1.Info; Project.ID brand
boundaries.

REMAINING (~358 src) is now dominated by task #9: ~10 core modules (Provider, Plugin, Project,
SessionPrompt, SessionCompaction, ShareNext, Worktree, ToolRegistry, LLM, SessionProcessor,
InstanceBootstrap) are fork namespaces but the new upstream consumers (app-runtime AppLayer,
httpapi handlers, control-plane, share/session, provider/auth, agent.ts) need them as Effect
Context.Services. That migration is the critical path for the bulk of the rest.
…ionPrompt/SessionCompaction (ckpt 28)

Task #9 (the AppLayer/Service cluster) — facade approach validated via 4 parallel agents. Each adds
an Effect Context.Service (+ layer/defaultLayer/node) that DELEGATES to the existing namespace
functions (Effect.promise/Effect.sync wrap), so the new upstream consumers (app-runtime AppLayer,
httpapi handlers, control-plane, share/session, github.handler, instance-store) compile while
behavior is preserved and all existing namespace exports + Promise wrappers stay intact. Project
recovered its exact Interface + Project.NotFoundError tagged error + UpdateInput/UpdatePayload from
upstream git history (commit 3e1972fd92).

opencode 1602 -> 1503 (src 358 -> 305). app-runtime now needs only Plugin/Provider/SessionProcessor/
LLM/ToolRegistry (next wave). Facade modules themselves clean (residual share-next *.sql + compaction
brand are pre-existing, separate). All additions altimate_change-marked.
…olRegistry/SessionProcessor (ckpt 29)

Completes the task #9 Service-facade migration (2nd wave, 5 parallel agents). Each adds an Effect
Context.Service (+ layer/defaultLayer/node) delegating to the existing namespace functions, preserving
all fork logic (Provider keeps altimate-backend/gitlab/snowflake/databricks loaders intact) and the
Promise wrappers. Interfaces recovered from upstream git history (9581bf0670, 2638e2acfa, 3e1972fd92).
LLM facade adapted to Effect 4.0 beta.74 Stream API + the fork's LLMEvent adapter.

Result: src/effect/app-runtime.ts 10 -> 1 error (only Discovery.node left), agent/agent.ts 10 -> 2.
opencode 1503 -> 1477 (src 305 -> 248). Session-resume cumulative: 3181 -> 1477.

Long tail remaining: Discovery facade (app-runtime:108), agent.ts brand/2, a few pre-existing in-file
errors (plugin state loop, provider NoModelsError/toPublicInfo/defaultModelIDs additions), missing
runtime assets (event.sql, max-steps.txt), then ~1226 tests.
…checkpoint 30)

7-parallel-agent batch over ~40 files cleared the post-Service-cluster long tail. Total 1477->1277,
src 248 -> 52. Session-resume cumulative: opencode 3181 -> 1277 (src now ~52). No duplicate-export
conflicts from the concurrent shared-file work.

Highlights:
- Restored dropped fork files from main: server/routes/event.ts, server/middleware.ts,
  sync/event.sql.ts, session/prompt/max-steps.txt (runtime assets), permission/permission.sql.ts,
  Ripgrep async-generator namespace (file/ripgrep.ts).
- Effect Tool-API: extended tool-zod-compat for the deferred-factory Tool.define form (skill/task/
  bash tools); assertExternalDirectoryLegacy for ls/glob.
- bootstrap.ts rewritten to the Effect-Service form (InstanceBootstrap.defaultLayer/.node) —
  cleared ripples in instance-store/layer, app-runtime, worktree, control-plane/workspace.
- More Promise wrappers (Vcs.diff/defaultBranch, Question.ask, Skill.get/available, Config.updateGlobal,
  provider/auth methods/authorize/callback); Provider additions NoModelsError/toPublicInfo/
  defaultModelIDs/ListResult; Project.InfoSchema; pty -> @opencode-ai/core/pty + PtyID shim.
- zod() AST-walker across remaining Hono routes; ProviderV2/ModelV2<->fork brand re-maps; lsp/index
  rewritten to the new context-aware LSPServer/LSPClient API; ServiceMap->Context in auth services.
- Deleted stale duplicate config/migrate-tui-config.ts.

Remaining ~52 src across ~20 files (<=5 each) + ~1222 tests.
anandgupta42 and others added 2 commits June 30, 2026 22:39
…e dir)

The 37 MCP test "failures" seen off-CI were not a merge regression — the rewritten
client is correct. `discoverExternalMcp` (and `MCP.defaultLayer` auto-discovery) read
the home-scoped global config (`~/.claude.json`, VS Code / Cursor / Copilot configs).
The discover/lifecycle tests never isolated the home dir, so on any dev machine with a
populated `~/.claude.json` the real MCP servers leaked into hermetic "returns empty" /
mock-server-count assertions. CI stayed green only because its HOME is clean.

Fix: spy `os.homedir()` onto a fresh empty temp dir per test (bun's `os.homedir()`
caches `$HOME` at process start, so `process.env.HOME` can't be overridden at runtime —
matches the existing `spyOn(os, "homedir")` pattern in the editor-context tests).

Full `test/mcp/` now 196 pass / 0 fail with a populated real HOME (was 159/37).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The v1.17.9 merge rewrote `defaultModelFromConfig` in `acp/service.ts` and dropped
the fork's model-selection preference: when the user has `altimate-backend` configured
but hasn't pinned a model, ACP sessions (Zed and other editor clients) should default
to `altimate-backend/altimate-default`. The rewritten version fell straight through to
the `opencode` provider, routing ACP clients away from altimate's own backend.

main carried this in `acp/agent.ts`'s `defaultModel()` (marked `capture provider filter`
+ `default to altimate-backend when configured and no model chosen yet`); the ACP split
into per-file modules preserved the yolo + auth-branding customizations but lost this one.

- Restore the altimate-backend preference between the configured-model check and the
  opencode fallback, honoring an explicit `provider` allowlist (skip only if the user
  configured `provider` and left altimate-backend out) — faithful to main's logic.
- Thread the user config's `provider` filter through from the caller.
- Export the (previously private) pure helper and add `test/acp/default-model.test.ts`
  (5 cases: preference, opencode fallback, allowlist include/exclude, configured wins).

Found via a marker-count differential (main vs HEAD) over fork-customized files.
Full `test/acp/` 124 pass / 0 fail. Typecheck + marker guard clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 89eaf01882

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/tui/src/component/prompt/index.tsx
Comment thread packages/tui/src/component/prompt/index.tsx
Comment thread packages/tui/src/routes/session/permission.tsx
Comment thread packages/tui/src/routes/session/question.tsx
Comment thread packages/tui/src/component/prompt/index.tsx
Comment thread packages/tui/src/component/dialog-session-rename.tsx
Comment thread packages/tui/src/routes/session/index.tsx
Comment thread packages/tui/src/component/dialog-provider.tsx
Comment thread packages/tui/src/routes/session/dialog-message.tsx
Comment thread packages/core/src/session.ts
anandgupta42 and others added 4 commits June 30, 2026 23:22
…startup crash

The two DB layers over one sqlite file (packages/core migrations + packages/opencode
`storage/db.ts`) can collide on mixed old/new-binary databases. The legacy storage layer
adds columns via a guarded `addColumn` (e.g. `project.icon_url_override`) WITHOUT recording
the corresponding core migration in the core `migration` journal. When the schema is not
fully current (`currentSchemaApplied` returns false), `applyOnly` then re-runs the core
migration's unguarded `ALTER TABLE project ADD icon_url_override` → SQLite throws
`duplicate column name: icon_url_override` → startup crashes.

Reproduced live: `bun run src ... run` against a real legacy `opencode-local.db` failed
with the duplicate-column error before app start; fresh installs and the shipped binary's
own (fully-current) db are unaffected. Same class as the already-fixed `session ADD metadata`
collision that `adoptCoreOwnedDatabase` handles — this closes the additive-column gap.

Fix (`applyOnly` per-migration loop): SQLite has no `ADD COLUMN IF NOT EXISTS`, so when a
migration fails with a "schema object already exists" error (`duplicate column name` /
`already exists`), treat it as already-applied — record the id and continue. Robust to both
Effect failures and defects (`Effect.exit` + `Cause.pretty`); any other error re-raises
faithfully via `Effect.failCause`, so real migration breakage still crashes loudly.

Tests (`database-migration.test.ts`): adopt-when-column-exists (red before the fix:
`SQLiteError: duplicate column name: icon_url_override`) + a negative test proving a genuine
migration error still throws. Full migration suite 21 pass / 0 fail. Core typecheck + marker
guard clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`share-next.fullSync` synced an empty `session_diff` to the shared web view. The facade
`Session.diff` (session/index.ts) reads the persisted `["session_diff", sessionID]` storage
key, which main's `summarize` wrote after each turn but the v1.17.9 merge's summarize no
longer does — so shared sessions showed no file changes.

Route `fullSync` to `SessionSummary.diff({ sessionID })`, which computes the full-session
diff on read (restored in b5715e7), instead of the facade that reads the now-unwritten
key. Avoids touching the after-every-turn `summarize` hot path.

Found via a codex adversarial subsystem audit; verified against `main` and the live wiring
(`ShareNext` node registered, `session share` command + routes active). share + session
suites: 728 pass / 0 fail. Typecheck + marker guard clean.

Note: aggregate session summary counts (additions/deletions/files) remain 0 after turns —
cosmetic/internal only (the TUI renders file lists via SessionSummary.diff, not the aggregate
count), left as a follow-up to avoid hot-path risk.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`substitute()` in config/paths.ts still computed the env-substitution stats
(dollar_refs/unresolved/defaulted/escaped, legacy_brace_*) but the v1.17.9 merge dropped the
`Telemetry.track({ type: "config_env_interpolation" })` emit — the stats were computed and
discarded, and the only remaining reference to the event was its telemetry schema definition.

Restore the single emit site (dynamic import to avoid the circular dep with @/altimate/telemetry),
matching main. Observability-only — config interpolation itself was unaffected.

Found via codex adversarial audit (pass 2: tool/cli/config/snapshot/flag/util — no other drops).
config + telemetry suites green. Typecheck + marker guard clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…a proxy)

The workspace HttpApi group is declared at `/experimental/workspace` (the v2 SDK generates
`experimental.workspace.list/status/adapter/create/warp` against that exact path — no `/api`
prefix, unlike every other endpoint). But `Server.createApp` only bridged `/api/*` to the
HttpApi, so workspace requests fell through to the legacy Hono catch-all, which proxies unknown
paths to app.altimate.ai → HTTP 500. The legacy `WorkspaceRoutes` that used to serve this path
was removed during the merge, and the gating comment in experimental.ts referenced a
`control-plane/workspace.ts` typecheck blocker that is now stale (monorepo typecheck is green;
the HttpApi actively uses that service).

Net effect: the TUI's workspace list/status/create silently failed (calls are wrapped in
`.catch(() => undefined)`, so no crash — workspaces just never appeared).

Fix: bridge `/experimental/workspace` and `/experimental/workspace/*` to `httpApiBridge` before
the legacy `/experimental` routes. The handler worked all along — it was simply unrouted; no
control-plane reconciliation needed.

Verified on the rebuilt binary via `serve`: `GET /experimental/workspace?directory=…` → 200 `[]`
(was 500), `/experimental/workspace/status` → 200. Found via codex adversarial audit (pass 3).
Server suite 276 pass / 0 fail. Typecheck + marker guard clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 555ac7fbd6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/core/src/tool/edit.ts
Comment thread packages/tui/src/context/sync.tsx
Comment thread packages/server/src/handlers.ts
Comment thread packages/cli/src/tui.ts
Comment thread packages/server/src/handlers/skill.ts
Comment thread packages/server/src/handlers/reference.ts
Comment thread packages/core/src/session/runner/llm.ts
Comment thread packages/core/src/database/migration.ts
…sks, webfetch allowed

The reviewer agent's `*: deny` (last-match-wins) clobbered the defaults'
`external_directory: ask`, so `read`/`grep`/`glob` on paths outside the
project (sibling repos, `~/.claude/skills`) hard-failed instead of
prompting. `bash: deny` also made reviewing a PR by URL impossible
(`gh pr view` is the primary path).

- `external_directory`: use `readonlyExternalDirectory` (ask + whitelisted
  dirs allow), same pattern as the `explore` agent
- `bash`: `deny` → `ask` — every command still requires explicit user
  approval; DDL safety denials still win via `userWithSafety`
- allow `webfetch`/`websearch`/`list` for read-only PR/issue review
- update reviewer prompt tool list to match
- regression test: external dir asks, gh pr view asks, DROP still denied,
  edit/sql_execute_write still denied
…om a non-empty prompt

- `input.line.home` / `input.line.end` were defined in keybind config and
  the keymap command list but nothing dispatched them for the prompt
  editor — register prompt-local commands so `Ctrl+A`/`Ctrl+E` jump to
  line start/end (#973)
- Up/Down now browse prompt history whenever the cursor is on the
  first/last line, not only when the prompt is empty (#975); the
  in-progress draft is stashed on entry and restored when navigating
  back past the newest entry
- extracted testable helpers to `prompt/navigation.ts` +
  `movePromptHistory` in `prompt/history.tsx`; unit tests added
…ommand, calm /feedback

- #971: autocomplete concatenated TUI palette slash entries with server
  commands without a collision check, so `/mcps` showed twice. Dedupe
  generically by command name; the TUI entry wins (opens `DialogMcp`)
  while typed `/mcps` / `/mcps enable <name>` still reaches the server
  direct handler
- #972: MCP surfaces now show how to authenticate — `DialogMcp` rows and
  the `/mcps` status table both render
  `Needs authentication (run: altimate mcp auth <name>)`, matching
  `/status`; formatter extracted as
  `SessionPrompt.formatMcpStatusForDisplay` with unit tests
- #974: `/feedback` template now asks at most ONE round of clarifying
  questions and only for essential missing fields; keeps the
  category/label follow-up; drops the confirm-before-filing and
  separate session-context interview steps
Session output either linkified only the visible (truncated) text or let
the terminal auto-detect links from truncated display text. Add
`util/terminal-link.tsx`:

- markdown (assistant + reasoning): attach a chunk transform that keeps
  the full URL as the link target while middle-ellipsizing the display
  text to the available width
- shell + generic tool output: wrap detected URLs in explicit link
  elements with the full `href` from the untruncated source text

Unit tests cover full-target preservation when display text is
shortened or collapsed.
…keybind (merge drops)

Post-merge audit findings:

- explore agent lost `codesearch: "allow"` in the v1.17.9 merge — the
  tool gates on that permission, so explore silently degraded to local
  grep whenever codesearch was available
- `prompt_skills` keybind was declared and mapped to `prompt.skills`
  but the prompt palette gather list never included it, so configuring
  it had no effect
…#978 ask design

CI (TypeScript job) failures:

- `cli/cmd/db.ts` read-only guard (c87d59d) opened an
  `altimate_change start` block but never closed it — four marker
  integrity/discipline suites failed. Add the missing `end`.
- v0.8.0 adversarial + carry-forward pin tests asserted the reviewer's
  old `bash: deny`. #978 relaxed bash to `ask`; update the pins to the
  real invariant: NO bash command ever evaluates to "allow" (redirect
  writes, credential reads, plain git all ask), destructive DDL stays
  hard-denied, edit/write stay denied.
…e (audit findings)

Post-merge audit found fork features re-homed into TUI plugins with
"deferred" gaps that regressed pre-merge behavior:

- auto_enhance_prompt: docs promised auto-rewrite before sending but the
  submit path never called it. New fork endpoint
  `POST /altimate/prompt/enhance` (no-op unless
  `experimental.auto_enhance_prompt: true`, returns original text on
  failure) called from the TUI submit path before pasted-text expansion.
  Internal `SessionPrompt.prompt` callers are not rewritten.
- Altimate provider connect: selecting `altimate-backend` in the provider
  list now dispatches `altimate.provider.connect` (validation + save via
  `AltimateApi`), and a new `dialog.openModel(providerID)` plugin-API
  seam restores the bootstrap + model-picker handoff after save.
- skill create/install: server skill cache is invalidated again via the
  raw generated client (`GET /skill?reload=true`, no SDK regen); success
  toasts only fire after reload verification, otherwise an explicit
  error names the skills that failed to appear.

Guard tests extended in `test/upstream/fork-feature-guards.test.ts` so a
future merge dropping these handoffs fails CI.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ae163389dd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/core/src/tool/read.ts
Comment thread packages/core/src/tool/write.ts
Comment thread packages/core/src/tool/apply-patch.ts
Comment thread packages/core/src/session.ts
Comment thread packages/tui/src/context/project.tsx
Comment thread packages/tui/src/routes/session/dialog-fork-from-timeline.tsx
Comment thread packages/tui/src/component/dialog-session-list.tsx
Comment thread packages/tui/src/component/dialog-tag.tsx
Comment thread packages/tui/src/context/sync.tsx
Comment thread packages/server/src/handlers/model.ts
…unch row growth)

Found by the v0.8.10 -> v1.17.9 upgrade-path test: `__drizzle_migrations`
gained one row on every launch. `adoptCoreOwnedDatabase` re-marks entries
each boot, and `markDrizzleEntriesApplied` used `INSERT OR IGNORE` on a
table with no unique constraint, so nothing was ever ignored. The
guarded DDL never re-ran (no crash, no data change) but the journal
leaked rows unbounded.

- mark via `INSERT ... SELECT ... WHERE NOT EXISTS (name)` — idempotent
- `dedupeDrizzleJournal` self-heals existing duplicate rows (keep MIN(id)
  per name), guarded, runs after name backfill and before migrate()
- regression test: two simulated boots keep the journal row count stable;
  a seeded duplicate is collapsed. Fails without the fix.
…regressions)

Code-level gates (typecheck/unit/CI) passed while every tester-filed
regression (dead keybinds, /mcps dupe, reviewer perms, truncated URLs)
shipped — because they are emergent behaviors of the compiled artifact.
This suite drives the real binary in tmux with a hermetic mock LLM and
carries one named journey per issue.

- OPENCODE_TEST_CLI-gated: skips entirely in normal CI (13 skip); run
  locally against a built binary
- 10 passing journeys: clean boot, ctrl+p palette, Tab agent switch,
  /models, prompt round-trip + trace file, ctrl+c keeps session alive,
  #971 (single /mcps row), #973 (Ctrl+A/E), #975 (history recall w/ draft)
- 3 documented test.todo with FINDING notes + unit-test pointers where a
  full journey isn't hermetically feasible: #972 (needs real OAuth MCP →
  covered by mcps-command.test.ts), #976 (direct-mode OSC8 capture),
  #978 (mock harness doesn't render the permission dialog → rules covered
  by agent.test.ts + agent-safety.test.ts)
- also adds the v0.8.10->v1.17.9 upgrade-path test report

Run: OPENCODE_TEST_CLI="$PWD/dist/.../altimate-code" bun test test/tui-journeys

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

if (status?.status === "connected") {
// Disable: disconnect the MCP
await sdk.client.mcp.disconnect({ name })
} else {
// Enable/Retry: connect the MCP (handles disabled, failed, and other states)
await sdk.client.mcp.connect({ name })

P2 Badge Do not expose MCP toggles without routes

The MCP dialog toggles servers through legacy /mcp/:name/connect and /mcp/:name/disconnect clients, but the standalone server does not register any MCP group. In the packaged TUI, trying to enable, retry, or disable an MCP server from this dialog always fails at the HTTP call and leaves the UI state unchanged; add served V2 MCP routes or hide these actions for this server.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/tui/src/component/prompt/index.tsx
Comment thread packages/tui/src/component/prompt/index.tsx
Comment thread packages/tui/src/context/sdk.tsx
Comment thread packages/tui/src/routes/session/permission.tsx
Comment thread packages/tui/src/component/prompt/index.tsx
Comment thread packages/tui/src/component/dialog-skill.tsx
Comment thread packages/tui/src/context/sync.tsx
Comment thread packages/tui/src/context/sync.tsx
Comment thread packages/tui/src/component/dialog-provider.tsx
…indings)

The v1.17.9 bridge merge silently reverted several upstream behaviors the
fork depends on. Found by the systematic merge audit (Contract-1), verified
as real split-brains (fork consumers present, producer dropped):

- session/compaction.ts: tail-preserving compaction was dead — consumers
  read `tail_start_id` (session.ts, message-v2.ts) but no writer set it.
  Restore upstream's tail-selection (`select`/`preserveRecentBudget`/`turns`)
  so recent turns are preserved across compaction.
- share/share-next.ts: restore `catch`/`try` around background full-sync and
  flush — an unawaited `fullSync` could reject unhandled on share failure.
- session/retry.ts: restore retrying transient 5xx API errors even when the
  SDK marks them non-retryable.
- session/llm.ts: restore `includeRawChunks` for the github-copilot provider
  — Copilot billing (`totalNanoAiu`) only populates via raw chunks; the
  consumer path existed but the flag was dropped.

Each wrapped in `altimate_change upstream_fix` markers, each with a
regression test that fails without the fix.
…nt calls)

Lower-severity merge drops the fork wants, from the Contract-1/2 audit:

- util/filesystem.ts: restore Windows path normalization (`windowsPath()`
  for Git Bash/Cygwin/WSL styles) — HEAD had only `realpathSync.native`.
- cli/cmd/mcp.ts: prefer `altimate-code.json` in CONFIG_FILENAMES so CLI
  MCP installs default to the fork's config name (opencode.json still
  discovered for compatibility).
- tui first-run onboarding: restore the dropped beginner-tips / `isFirstTime`
  home hint ("Get started: /connect … /discover … Ctrl+P") for new users.
- branding: fix user-visible "OpenCode config" leak in the core initialize
  template; add markers to unmarked fork branding in footer/uninstall.

Each with a test. Skipped (documented in MERGE-VALIDATION-MATRIX.md): the
`opencode.internal` internal routing-key inconsistency — not user-visible,
works today, and changing it risks in-process routing breakage for no gain.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7232b3474d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/tui/src/routes/session/question.tsx
Comment thread packages/tui/src/context/sync.tsx
Comment thread packages/core/src/tool/edit.ts
Comment thread packages/tui/src/component/prompt/index.tsx
Comment thread packages/tui/src/component/prompt/index.tsx
Comment thread packages/tui/src/component/dialog-session-rename.tsx
@anandgupta42

Copy link
Copy Markdown
Contributor Author

Review-comment triage: resolving 136 codex comments as not-applicable to the shipped runtime

I went through all 136 unresolved, non-outdated codex review threads. None target packages/opencode/src — the shipped @altimateai/altimate-code runtime. They break down as:

Where Count Why not applicable
packages/tui/src V2-client calls 75 Premised on the TUI running against upstream's standalone packages/server V2 server (so legacy session.create/session.prompt//project/current 404). The fork's TUI talks to packages/opencode/src/server — a superset that implements those routes. Empirically disproven: the packaged binary's TUI creates a session and gets a model response end-to-end.
packages/core/src V2 scaffolding 14 Tools (core/src/tool/{read,write,edit,apply-patch}) are imported only by specs/v2/api.ts, not the runtime — shipped tools are packages/opencode/src/tool/* with the permission/safety system intact. core/config.ts .opencode-only discovery is superseded by opencode/src/config/paths.ts (.altimate-code primary). core/database/migration.ts and core/session/runner/* are not imported by the shipped runtime (migration = opencode/src/storage/db.ts, validated by a v0.8.10→HEAD upgrade test; agent loop = opencode/src/session/*).
packages/server/src standalone V2 10 Upstream's standalone V2 server (no-op session execution, missing routes). The fork does not run it as its main server; it bridges only parts into an experimental HttpApi surface.
packages/cli/src 2 Pure upstream, zero fork markers — not shipped (fork uses packages/opencode/src/cli).

These are legitimate observations about upstream's in-progress V2 restructure, but they don't affect the artifact this PR ships. Resolving as not-applicable. If the standalone V2 server / V2 tool set is promoted to the shipped path in a future change, this is the backlog to revisit. Un-resolve any you'd like to keep open.

…cking)

Release-evaluation board (build/packaging perspective) found the release
workflow pinned Bun 1.3.10 at all 4 setup-bun steps, but the build/publish
scripts throw unless Bun satisfies ^1.3.14 (package.json packageManager +
packages/script guard). CI was already bumped to 1.3.14; release.yml was
missed — so every tag release would fail before producing artifacts.
…s (release board)

Release-evaluation board (upstream-adoption + integration-seam perspectives)
found upstream v1.17.9 work the bridge merge reverted or left unwired — the
"don't lose upstream work" axis. All restored with upstream_fix markers + tests:

- provider/provider.ts: Cloudflare AI Gateway unified provider now receives
  `apiKey` (authenticated unified-model calls were failing) — upstream 8fd5753f76.
- provider/transform.ts: Devstral detection uses locale-safe `toLowerCase()`
  (was `toLocaleLowerCase()`) — upstream babe5070e2.
- project/project.ts: session project-migration preserves `time_updated`
  (schema `$onUpdate` was silently rewriting session recency) — upstream c5c9a1d435.
- config/tui.ts + tui-migrate.ts: managed TUI config is loaded + migrated again
  (existing managed tui.json / legacy theme+keybinds were ignored after upgrade).
- config/paths.ts: restore main's `.jsonc`-before-`.json` same-dir precedence.
- plugin/index.ts: wire the Azure / DigitalOcean / xAI auth plugins into
  INTERNAL_PLUGINS (files were merged in but never registered, so users could
  not authenticate to those providers) — matches upstream's internalPlugins().
- cli/cmd/run.ts: attach the basic-auth header to in-process `run` requests so
  local run still reaches the embedded server when OPENCODE_SERVER_PASSWORD is
  set (was 401ing) — upstream 632f94fa68.
Release-evaluation board (safety perspective) found the #209 sensitive-write
guard was neutralized at runtime. The guard calls
`ctx.ask({ permission: "sensitive_write" })` before writing a sensitive target
(.env / .ssh / .git / ...), but `sensitive_write` was never configured, so it
fell through to the builder's `"*": "allow"` default and silently auto-approved
— defeating the guard the fork deliberately restored. Pre-existing (present on
main too), not a merge regression, but a real bypass.

Default `sensitive_write: "ask"` in the agent defaults so sensitive writes
prompt (users can still override to "allow"). Write-restricted agents
(analyst/reviewer/plan) keep their later `"*": "deny"`. Regression test asserts
builder=ask, analyst/reviewer=deny.
Follow-up to the release-board processor.ts finding. Server-side
(provider-executed) tool calls were already NOT re-executed locally —
native-runtime.ts skips ToolRuntime.dispatch when event.providerExecuted
is set. The remaining gap: the processor didn't propagate that flag onto
the tool part's metadata, so rendering/serialization couldn't distinguish
a provider-executed tool from a client-executed one.

Tag `providerExecuted: true` in the tool part metadata on the tool-call
event (mirrors upstream's part-tagging). Assertion added to the existing
provider-executed test.

Remaining scoped follow-up (not done — telemetry-only, entangled with
HEAD's different settlement-event architecture): emit `provider.executed`
on the Tool.Failed/Completed settlement events (the sibling test stays
`.todo`, blocked on the documented injected-LLM harness limitation).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e3a160ae0e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/server/src/handlers/pty.ts
Comment thread packages/tui/src/component/dialog-provider.tsx
Comment thread packages/core/src/session/projector.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment