fix(telemetry): a second export is a second plugin - #785
Merged
Conversation
OpenCode loads every function-valued named export of a file in `plugin/` as
a plugin factory of its own. `opencode-plugin.js` exported `journalCallFor`
beside `AiddTelemetry` as a spawn-free test seam; OpenCode called it with one
argument, got `null`, and died reading `.auth` off it before any session
started. Measured against opencode 1.14.20 in a freshly installed project:
export const Stub = async () => ({ event }) -> runs
+ export function helper(){ return null } -> TypeError: null
is not an object (evaluating 'S.auth')
+ export const helper = { a: 1 } -> runs
So installing this framework for OpenCode made the tool it measures
unusable. The seam now rides on the plugin function as a property, leaving
one export, and a test asserts that only `AiddTelemetry` is function-valued.
The same run showed the second half of the fault. OpenCode publishes
`session.created` on its own bus and never delivers it to a plugin's event
hook, and `opencode run` is always such a session, so the journal never
received a `session_start`, never created the run file the rest of the
session appends to, and dropped the `turn-end` and every task declaration
after it. `telemetryLocalRead` declared the tool covered while `aidd
telemetry read`, which reads only sessions the run journal knows, could
never find one. The first call a session produces now opens it, carrying the
directory that call was already going to use — never a new guess. What is
left is only what `session.created` alone could have said, and the README
says it: on a server serving more than one directory, a session it never
announced is journalled under the plugin's own init-time directory.
Verified end to end on a scratch repository, isolated sink: a real
`opencode run` wrote its first journal ever — `session_start`,
`task_declared`, `turn_end` — and `aidd telemetry read` answered
"OpenCode: read (3 new of 3)".
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
OpenCode loads every function-valued named export of a file in
plugin/as a plugin factory of its own.opencode-plugin.jsexportedjournalCallForbesideAiddTelemetryas a spawn-free test seam; OpenCode called it with one argument, receivednull, and died reading.authoff it before any session started.Installing this framework for OpenCode therefore made the tool it measures unusable.
Measured
Against
opencode 1.14.20, in a freshly installed scratch project:.opencode/plugin/opencode runexport const Stub = async () => ({ event })+ export function helper(){ return null }TypeError: null is not an object (evaluating 'S.auth')+ export const helper = { a: 1 }(not a function)opencode-plugin.jsas shippedThe second half
The same run exposed the rest of the fault. OpenCode publishes
session.createdon its own bus and never delivers it to a plugin's event hook, andopencode runis always such a session. So the journal never received asession_start, never created the run file the rest of the session appends to, and dropped theturn-endand every task declaration after it — whiletelemetryLocalReaddeclared the tool covered andaidd telemetry read, which reads only sessions the run journal knows, could never find one.The first call a session produces now opens it, carrying the directory that call was already going to use. Never a new guess: for a session no
session.creatednamed, that is the plugin's own init-time directory, exactly whatjournalCallForalready handedturn-endandtool-used.What is left is only what
session.createdalone could have said, and the README now says it: on a server serving more than one directory, a session it never announced is journalled under the plugin's own init-time directory rather than its own. The guard that pinned the old limit sentence now pins both the new fact and what it still costs.Verified
End to end on a scratch repository with an isolated sink — the real sink was never written.
A real
opencode runproduced the first OpenCode journal this project has ever recorded:and
aidd telemetry readansweredOpenCode: read (3 new of 3).The
session_startcame from the task declaration, not fromturn_end— the case the second new test covers.Gates
node --test "scripts/__tests__/**/*.test.js"— 380/380clivitest — 3501/3501, run twice: after the code change, and again after the doc changes, since the golden build matrix embeds the shipped plugin filebiome checkon every changed file — cleancheck-markdown-links.js— 0 broken in 797 filesCATALOG.mdanddocs/prompts-documentation.mdregenerate unchangedThe six new tests were written first and were red for the reason they name before the change landed.
🤖 Generated with Claude Code
https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp