Two surfaces label a synthesized (dynamic-dispatch) `calls` hop:
codegraph_explore's Flow and dynamic-dispatch links plus the
codegraph_node trail (`dynamic: interface → impl @file:line`), and
ContextBuilder's "## Call paths", which `codegraph context` prints
(`→[…]`). Each kept its own list. The call paths' list stopped at
callback, react-render, jsx-render, vue-handler, http-client, queue-job
and socket messages, so every other synthesizer fell through to
`event ${m.event ?? ''}`: an interface-impl hop read
`→[event @src/pdf-exporter.ts:5]`, and so did a C++ override, a redux
thunk, a gin middleware chain or a closure collection.
The wording now lives once, in src/graph/synthesized-hop.ts
(`describeSynthesizedHop`: a summary, the detail only the call paths
print, and the wiring site), as AGENTS.md asks of a derivation two
surfaces render. ToolHandler renders `dynamic: <summary> @site`, the
call paths `<summary><detail> @site`. Explore and the node trail print
exactly what they printed before; the call paths keep their wording for
the kinds they already labelled, including the queue name, a socket's
direction and the HTTP clause, and now name the rest the way explore
does. A bus event reads `bus event` there too, and the section's
footnote no longer says hops are marked `[callback/event …]`.
The helper also holds the wording #2414 gives a Go method a struct gets
by embedding (`metadata.promotedInto`), so that arm moves here too. The
unused long `label` form of ToolHandler.synthEdgeNote (last read by the
removed codegraph_trace) is dropped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On Windows a worker thread that ends - terminate(), its own process.exit(),
or the process exiting - while V8's concurrent marker is marking its heap
crashes the whole process (exit 3221225477 / 0xC0000005, no error, no dump).
Bisected on the Windows 11 ARM64 VM: --no-concurrent-marking alone stops it
(18/480 -> 0/480; no other concurrency flag does), but it costs about a third
of indexing speed, so CodeGraph avoids the dangerous moments instead:
- src/worker-teardown.ts: owners terminate a worker only once it has started
(its first message, posted after its modules load - mid-load is by far the
worst moment), and a worker about to exit runs a full collection first,
which finishes any marking in flight (gc reached at runtime, never global).
- Resolver pool / store writer: the worker collects before exiting on
'close' (the normal path - main 21/480 crashed on the VM, now 2/1200), and
the 5 s close fallback never terminates a worker still starting.
- codegraph_status change counts: the worker posts 'loaded' after its heavy
require and collects before answering; a deadline answers unknown at once
but terminates only once loaded (3/720 -> 0/1440), and MCPEngine.stop()
waits for measurements in flight.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Running the suite on a machine with Claude Code configured could wire the
CodeGraph prompt hook into the developer's own ~/.claude/settings.json:
every upgrade test whose fake upgrade succeeded ran the real post-upgrade
prompt-hook self-heal, which detected the real global Claude profile and
wrote it. Daemon suites likewise left records in the real
~/.codegraph/daemons. On Windows a HOME-only redirect would not have
helped, since os.homedir() reads USERPROFILE there.
- The prompt-hook writer is now injected through UpgradeDeps
(wirePromptHook); the CLI passes the real defaultWirePromptHook and the
upgrade tests a recorder. New tests pin that a successful upgrade calls
the recorder and that the real writer never touches a configured profile.
- A vitest setupFiles entry gives every engine test file a throwaway home:
HOME/USERPROFILE (plus HOMEDRIVE/HOMEPATH/APPDATA/LOCALAPPDATA on
Windows), XDG_CONFIG_HOME, and GIT_CONFIG_GLOBAL (seeded with a dummy
identity) point into it, and CLAUDE_CONFIG_DIR/CODEX_HOME/COPILOT_HOME/
HERMES_HOME are cleared. Spawned CLI/MCP children inherit it. A sandbox
test asserts os.homedir(), the Claude profile, the daemon registry, a
child process and git's global config all resolve inside it.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The 1.6.1 bump changed package.json only, as AGENTS.md said was enough, so
ui-package.test.ts ("is versioned with the engine") has failed on main since.
Bump ui/package.json to match, and say in AGENTS.md that a version bump
touches both files.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(cli): withhold `codegraph ui` until the viewer launches (CODEGRAPH_UI=1 opts in)
The viewer has been exercised on Expo apps only, not on API, Laravel,
Spring, Angular or Swift projects, so it stays out of this release. `ui` and
its alias `web` — also as `help ui` or `ui --help` — are refused before any
startup work, and the command is hidden from `--help`, unless CODEGRAPH_UI=1
is set, which keeps it usable for the people testing it. The viewer assets
still ship, so the opt-in works on a released build.
Reverting this commit is the launch.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(site): say the viewer is not in a release yet
The viewer pages have been live on the docs site since they landed, and
1.6.0 answers `codegraph ui` with "unknown command" (#1816, #1900). Until the
viewer launches, the guide, the CLI reference and the next-steps link say so.
Reverting this commit is part of the launch.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(changelog): hold the viewer's entries for its launch; new Highlights for the fixes release
53 entries that describe `codegraph ui` and its screens move, verbatim, to
docs/viewer-launch-changelog.md along with the launch Highlights. 12 entries
whose graph and `codegraph_explore` half ships now (the router navigation
edges, the cross-tier hops, explore's `when` conditions, SvelteKit layouts,
wrapped Express handlers, …) are reworded around the graph; their original
wording is kept in the holding file for the launch. A few kept entries lose a
viewer clause. The Highlights are rewritten for this release.
prepare-release.mjs promotes the section and extract-release-notes.mjs reads
it back with no mention of the viewer; the released sections are untouched.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
OpenCode 2 exposes MCP tools through Code Mode by default; `codemode: false`
only survives on `mcp.servers.<name>` with `disabled`. The installer wrote the
v1 `mcp.codegraph` + `enabled` shape, so the opt-out was dropped on normalize.
Write `mcp.servers.codegraph` with `disabled: false` and `codemode: false`,
migrate a leftover v1 entry on re-install, uninstall either shape, and keep
printConfig / README / AGENTS.md in sync.
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
Codex reads AGENTS.md by default, not CLAUDE.md. Move project guidance to
AGENTS.md (trim/nest long validation notes under docs/AGENTS.md), leave
CLAUDE.md as a thin @AGENTS.md wrapper for Claude Code, and document the
Codex project_doc_max_bytes raise needed for the ~35KiB root file.
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>