Skip to content

feat(adaptation): enhance platform detection and cache path handling …#376

Closed
mikij wants to merge 2 commits intomksglu:nextfrom
mikij:opencode-update
Closed

feat(adaptation): enhance platform detection and cache path handling …#376
mikij wants to merge 2 commits intomksglu:nextfrom
mikij:opencode-update

Conversation

@mikij
Copy link
Copy Markdown
Contributor

@mikij mikij commented Apr 28, 2026

…for OpenCode/KiloCode

What / Why / How

  • I want to add new argument to CLI for upgrade so it will make OpenCode/KiloCode plugin development/testing much easier allowing it to update itself from local git branch. CLI should support local upgrade (context-mode upgrade local) which copies current git branch instead of cloning latest GH published version.
  • Plugin needs to support new cache folder location. OpenCode silently changed (not documented) where is plugin stored inside of .cache folder (before .cache/opencode/node_modules/context-mode, now .cache/opencode/packages/context-mode@latest/node_modules/context-mode), so doctor or upgrade will not properly work for new versions of OpenCode/KiloCode. KiloCode also has a bug that uses OpenCode folder location instead of own. So `context-mode upgrade/doctor' will not work until that is resolved for KiloCode.

This fails in doctor:

■  Hook script exists: FAIL — not found at /Users/mickey/.cache/kilo/packages/context-mode@latest/node_modules/context-mode/hooks/pretooluse.mjs

Addition:

  1. OpenCode now has SessionStart (via experimental.chat.messages.transform) — no longer "not yet available"
  2. Both OpenCode and KiloCode now have high continuity (all 4 hooks working)
  3. The AGENTS.md copy step is now optional rather than required for routing awareness

Affected platforms

  • Claude Code
  • Cursor
  • VS Code Copilot (GitHub Copilot)
  • JetBrains Copilot
  • Gemini CLI
  • Qwen Code
  • OpenCode
  • KiloCode
  • Codex CLI
  • OpenClaw (Pi Agent)
  • Pi
  • Kiro
  • Antigravity
  • Zed
  • All platforms

Test plan

Checklist

  • Tests added/updated (TDD: red → green)
  • npm test passes
  • npm run typecheck passes
  • Docs updated if needed (README, platform-support.md)
  • No Windows path regressions (forward slashes only)
  • Targets next branch (unless hotfix)
Cross-platform notes

Our CI runs on Ubuntu, macOS, and Windows.

  • If touching file paths, verify forward-slash normalization on Windows
  • If touching hook paths, verify no backslash separators
  • Use path.join() / path.resolve(), never hardcode / separators
  • Use event-based stdin reading — readFileSync(0) breaks on Windows
  • Use os.tmpdir(), never hardcode /tmp

@mikij mikij marked this pull request as draft April 28, 2026 13:39
@mikij mikij force-pushed the opencode-update branch 3 times, most recently from ccdd4b3 to 8dbb2c4 Compare April 28, 2026 13:58
@mikij
Copy link
Copy Markdown
Contributor Author

mikij commented Apr 28, 2026

@mksglu this is test run result from main
image

@mikij mikij force-pushed the opencode-update branch 2 times, most recently from 862e570 to 23fdc97 Compare April 28, 2026 16:19
@mikij
Copy link
Copy Markdown
Contributor Author

mikij commented Apr 28, 2026

image from next

@mikij mikij marked this pull request as ready for review April 28, 2026 16:26
@mikij mikij force-pushed the opencode-update branch from 23fdc97 to 81292e7 Compare April 28, 2026 17:36
@mikij mikij force-pushed the opencode-update branch 5 times, most recently from 5406a20 to c1a9ae4 Compare April 29, 2026 22:42
…jection for OpenCode/KiloCode

Extract tool-naming and routing-block logic into dedicated source modules (src/tool-naming.ts, src/routing-block.ts) and update OpenCode adapter to enable sessionStart and canInjectSessionContext capabilities. Implement experimental.chat.messages.transform hook to automatically inject context window protection routing block into user messages, replacing the previous static hook approach. Update hook files to import from build outputs.
@mikij mikij force-pushed the opencode-update branch from c1a9ae4 to 383424a Compare April 30, 2026 20:35
@mikij
Copy link
Copy Markdown
Contributor Author

mikij commented Apr 30, 2026

Opened PR today. It is approved so hopefully it will be merged soon.

@mikij
Copy link
Copy Markdown
Contributor Author

mikij commented May 1, 2026

It was merged a several minutes ago. But it will be part of some 7.2.34+ version of KiloCode (latest is 7.2.33 and it was released just before my commit was merged)

@mksglu
Copy link
Copy Markdown
Owner

mksglu commented May 2, 2026

Mickey — real work in here. Thank you. Let me give you a piece-by-piece take so you can see exactly what we're keeping and why.

What you got right (adopting into the architectural PR):

  1. OpenCode/KiloCode cache path fix — the packages/context-mode@latest/ cache layout change is a real, current bug. Users on OpenCode and KiloCode are hitting it. We're adopting your fix verbatim.
  2. OpenCode SessionStart via experimental.chat.messages.transform — this is the correct hook surface for OpenCode and we didn't have it before. We're adopting this hook integration.

What we're not adopting (and why — happy to discuss):

  1. upgrade local subcommand — redundant with the existing symlink workflow. CONTRIBUTING.md already documents npm link for local development, and adding a CLI subcommand for it adds surface area without solving a new problem. Open to revisiting if you've hit a case where the symlink workflow falls short.
  2. tool-naming.ts + routing-block.ts extraction — premature abstraction. Both modules have a single consumer right now and no isolated tests. Extracting them now locks in an interface before we know the second use case. Happy to extract these the moment a second consumer appears.
  3. Bundle artifacts in the PR — these should be CI-generated on release. We've intentionally kept hand-built bundles out of the source tree to avoid diff noise on every commit.

Why we're not merging this directly: your PR ran into the same root cause as #379 and #370 — v1.0.100's "Unified Persistent Memory" hardcoded ~/.claude/ across searchAutoMemory, extract.ts, prior-session loading, and ctx_search timeline. Rather than merge 3 platform-specific PRs (Codex, Qwen, OpenCode/KiloCode), we're doing one architectural fix: HookAdapter gets getConfigDir(), getInstructionFiles(), getMemoryDir(), and every adapter (all 14) overrides with its own conventions. Your OpenCode pieces drop into that structure cleanly.

You'll be Co-Authored-By on the architectural commit and called out in the v1.0.101 release notes. When the PR lands this week, I'd love your review — especially on the OpenCode adapter to confirm we got the cache path and SessionStart wiring right.

Closing in favor of the unified fix. Thanks for digging into this.

@mksglu mksglu closed this May 2, 2026
mksglu added a commit that referenced this pull request May 2, 2026
v1.0.100's "Unified Persistent Memory" feature was Claude-centric.
Auto-memory, prior session, and persist memory all hardcoded ~/.claude/,
breaking 13 of 14 platforms. Plus a worktree filename mismatch broke
Claude Code too on worktree sessions.

Architectural fix: adds 3 methods to HookAdapter interface so every
adapter declares its own conventions:
  - getConfigDir()        — ~/.claude, ~/.codex, ~/.qwen, ~/.gemini, etc.
  - getInstructionFiles() — ['CLAUDE.md'], ['AGENTS.md'], ['QWEN.md'], etc.
  - getMemoryDir()        — ~/.claude/memory, ~/.codex/memories, etc.

BaseAdapter ships sensible defaults derived from sessionDirSegments;
only the 11 non-Claude adapters override (Claude inherits).

Wiring changes:
  - searchAutoMemory() now accepts an adapter, dispatches via methods
  - ctx_search timeline uses _detectedAdapter.getConfigDir()
  - ctx_search timeline SessionDB filename now includes worktree suffix
    (matches what session-snapshot/session-extract write to)
  - extract.ts rule detection covers AGENTS.md, GEMINI.md, QWEN.md,
    KIRO.md, copilot-instructions.md, context-mode.mdc, and any
    *.md inside a memory/memories directory

Bonus fixes (from PR #376):
  - OpenCode/KiloCode cache path: now packages/context-mode@latest/
    layout (silently changed by upstream late 2024 — broke doctor/upgrade)
  - OpenCode SessionStart equivalent via experimental.chat.messages.transform
    — prior-session continuity now works on OpenCode/KiloCode

Tests added (8 new files, 65 new tests, all green):
  - tests/adapters/base-adapter-memory.test.ts        (4)
  - tests/adapters/claude-code-memory.test.ts          (3)
  - tests/adapters/memory-conventions.test.ts         (36)
  - tests/core/auto-memory-adapter.test.ts             (5)
  - tests/core/cache-plugin-root.test.ts               (2)
  - tests/core/server-timeline-adapter.test.ts         (3)
  - tests/opencode-session-start.test.ts               (2)
  - tests/session/extract-rule-detection.test.ts      (10)

Closes architectural root cause of #367 follow-ups.
Supersedes #379 (Codex), #370 (Qwen), #376 (OpenCode/KiloCode portions).

Co-Authored-By: Marcus Neufeldt <MarcusNeufeldt@users.noreply.github.com>
Co-Authored-By: btxbtxbtx <btxbtxbtx@users.noreply.github.com>
Co-Authored-By: Mickey Lazarevic <mikij@users.noreply.github.com>
@mikij
Copy link
Copy Markdown
Contributor Author

mikij commented May 2, 2026

@mksglu Have a question about this function:

function getPlatform(): AdapterPlatformType {
  const [ kiloEnv ] = PLATFORM_ENV_VARS.filter(p => p[0]==="kilo");
  const [platform, vars] = kiloEnv;
  for (const _var of vars){
    if (process.env[_var]) {
      return platform;
    }
  }
  
  return "opencode";
}

I think this is more robust way to check for KiloCode platform and as you did not mention this, I want to ask did you miss it or also did not want to include for some reason?

@mksglu
Copy link
Copy Markdown
Owner

mksglu commented May 2, 2026

@mksglu Have a question about this function:

function getPlatform(): AdapterPlatformType {
  const [ kiloEnv ] = PLATFORM_ENV_VARS.filter(p => p[0]==="kilo");
  const [platform, vars] = kiloEnv;
  for (const _var of vars){
    if (process.env[_var]) {
      return platform;
    }
  }
  
  return "opencode";
}

I think this is more robust way to check for KiloCode platform and as you did not mention this, I want to ask did you miss it or also did not want to include for some reason?

checking

mksglu added a commit that referenced this pull request May 2, 2026
…code-plugin DRY

PR #376 follow-up. mikij flagged that src/opencode-plugin.ts hardcoded a
KILO_PID-only check that violated DRY against PLATFORM_ENV_VARS. Audit of
the canonical list itself surfaced the broader problem: half of the entries
were unverified placeholders, 4 platforms (antigravity, zed, pi, openclaw)
were entirely missing or incorrectly listed, and the plugin paradigm's
fallback to "opencode" was blind (didn't actively check OPENCODE env vars).

What ships
- Re-audited every entry against the platform's own runtime source code:
  - kilo: dropped bare `KILO` (Kilo-Org/kilocode never sets it; only KILO_PID
    is set unconditionally at packages/opencode/src/index.ts:140).
  - jetbrains-copilot: dropped IDEA_HOME and JETBRAINS_CLIENT_ID (no
    source-line evidence in any JetBrains repo). Kept IDEA_INITIAL_DIRECTORY.
  - qwen-code: dropped QWEN_SESSION_ID (0 hits in QwenLM/qwen-code).
  - openclaw: removed entirely from env-var tier (runtime never sets
    OPENCLAW_HOME/OPENCLAW_CLI). Detection falls through to ~/.openclaw/
    config-dir tier, which already worked.

- Added 3 new platforms with verified env vars:
  - antigravity: ANTIGRAVITY_CLI_ALIAS — verified in Google's
    google-gemini/gemini-cli packages/core/src/ide/detect-ide.ts (canonical
    IDE detection map). Listed before vscode-copilot since Antigravity is an
    Electron/VSCode fork.
  - zed: ZED_SESSION_ID + ZED_TERM — verified in zed-industries/zed
    crates/terminal/src/terminal.rs `insert_zed_terminal_env()` and
    cross-confirmed by Google's gemini-cli detect-ide.ts.
  - pi: PI_PROJECT_DIR — confirmed by our own consumers at
    src/pi-extension.ts:154 and src/server.ts:153.

- Reordered fork pairs so collision detection works:
  - kilo before opencode (Kilo sets OPENCODE=1 because it's an OpenCode fork).
  - cursor + antigravity before vscode-copilot (both inherit VSCODE_PID).

- src/opencode-plugin.ts getPlatform() rewritten to iterate
  PLATFORM_ENV_VARS instead of hardcoding KILO_PID. Filters to kilo+opencode
  so a stray CLAUDE_PROJECT_DIR can't leak into the plugin's platform decision.
  Symmetric: actively checks BOTH platform's env vars instead of blind
  fallback. Per-line JSDoc credits PR #376 (mikij).

Tests
- tests/adapters/detect.test.ts: removed 5 broken assertions for unverified
  env vars; added 4 assertions for new platforms (antigravity, zed×2, pi)
  and a fork-collision test (KILO_PID + OPENCODE both set → kilo wins).
- tests/adapters/detect-config-dir.test.ts: rewrote priority chain from
  OPENCLAW/CODEX assertions to fork-collision assertions
  (KILO/OPENCODE, CURSOR/VSCODE, ANTIGRAVITY/VSCODE, CURSOR/CODEX).

Verification
- 451/451 adapter + plugin tests pass on next worktree.
- Typecheck clean.

Co-Authored-By: Mickey Lazarevic <noreply@github.com>
@mksglu
Copy link
Copy Markdown
Owner

mksglu commented May 2, 2026

@mikij — you were right. Landed the full fix on `next` as commit 4e75d11 with you credited as Co-Author.

What ended up in the fix

Your point about `getPlatform()` (src/opencode-plugin.ts:80-82) was the surface. Pulling the thread surfaced a deeper problem: the canonical PLATFORM_ENV_VARS list itself had drift — half the entries were unverified placeholders, several platforms were entirely missing, and the plugin paradigm's fallback to `opencode` was blind (didn't actively check OPENCODE env vars either).

Audited every entry against the platform's own runtime source code. Highlights:

Removed / corrected (no source-line evidence):

  • kilo: dropped bare KILO — Kilo-Org/kilocode packages/opencode/src/index.ts:140 only sets KILO_PID, never bare KILO.
  • jetbrains-copilot: dropped IDEA_HOME, JETBRAINS_CLIENT_ID — neither verifiable in any JetBrains source repo.
  • qwen-code: dropped QWEN_SESSION_ID — 0 hits in QwenLM/qwen-code.
  • openclaw: removed entirely from the env-var tier — runtime never sets OPENCLAW_HOME/OPENCLAW_CLI. Detection still works via the existing ~/.openclaw/ config-dir tier.

Added (with verified source citations):

  • antigravity: ANTIGRAVITY_CLI_ALIAS — verified in google-gemini/gemini-cli packages/core/src/ide/detect-ide.ts (Google's own canonical IDE detection map).
  • zed: ZED_SESSION_ID, ZED_TERM — verified in zed-industries/zed crates/terminal/src/terminal.rs::insert_zed_terminal_env().
  • pi: PI_PROJECT_DIR — confirmed by our own consumers at src/pi-extension.ts:154 and src/server.ts:153.

Reordered fork pairs so collision detection works:

  • kilo before opencode (Kilo sets OPENCODE=1 because it's an OpenCode fork).
  • cursor + antigravity before vscode-copilot (both inherit VSCODE_PID).

getPlatform() itself rewritten exactly along your line — iterates PLATFORM_ENV_VARS instead of hardcoding any env var. Symmetric: actively checks BOTH platforms' env vars instead of blind fallback to opencode. Filtered to kilo+opencode so a stray CLAUDE_PROJECT_DIR can't leak into the plugin's platform decision.

function getPlatform(): AdapterPlatformType {
  for (const [platform, vars] of PLATFORM_ENV_VARS) {
    if (platform !== "kilo" && platform !== "opencode") continue;
    if (vars.some((v) => process.env[v])) {
      return platform as AdapterPlatformType;
    }
  }
  return "opencode";
}

Tests

  • tests/adapters/detect.test.ts: removed 5 broken assertions (for unverified env vars); added 4 for new platforms + a KILO_PID + OPENCODE both set → kilo wins fork-collision assertion.
  • tests/adapters/detect-config-dir.test.ts: priority chain rewritten as fork-collision tests (KILO/OPENCODE, CURSOR/VSCODE, ANTIGRAVITY/VSCODE, CURSOR/CODEX).

451/451 adapter + plugin tests pass on next. Typecheck clean.

Thanks again for surfacing this — both the immediate bug and the broader audit it triggered. Happy to credit you for any follow-up contributions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants