Skip to content

Fix opencode plugin visible logging#125

Merged
Looted merged 14 commits intomasterfrom
develop
Mar 29, 2026
Merged

Fix opencode plugin visible logging#125
Looted merged 14 commits intomasterfrom
develop

Conversation

@Looted
Copy link
Copy Markdown
Owner

@Looted Looted commented Mar 29, 2026

No description provided.

Copilot AI review requested due to automatic review settings March 29, 2026 15:52
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the kibi-opencode plugin’s logging behavior to be silent in normal operation while keeping errors visible, and adjusts prompt-injection hooks to avoid overwriting existing system prompt entries.

Changes:

  • Route info/warn logs through structured client.app.log() and keep error-class events visible via console.error.
  • Change scheduler + bootstrap-needed messaging to emit via the error channel for terminal visibility.
  • Update prompt injection behavior and tests to preserve existing output.system entries.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
packages/opencode/src/logger.ts Introduces client-backed structured logging with console-visible errors.
packages/opencode/src/index.ts Injects logger client; changes prompt injection to append instead of replace; adjusts log levels.
packages/opencode/src/scheduler.ts Treats sync/check failures as errors (terminal-visible).
packages/opencode/tests/logging-policy.test.ts Adds coverage ensuring console silence for info/warn and structured log routing.
packages/opencode/tests/index.test.ts Resets logger client between tests; updates system prompt assertions.
packages/opencode/tests/config.test.ts Switches config warning assertions to spy on logger.warn.
packages/opencode/tests/hook-contract.test.ts Adds contract tests for append-only system.transform and chat.params behavior.
packages/opencode/README.md Documents the logging policy.
packages/opencode/package.json Bumps package version.
packages/opencode/CHANGELOG.md Adds 0.5.3 entry describing the logging change.

Comment on lines +38 to +45
if (client) {
client.app.log({
body: {
service: "kibi-opencode",
level: "warn",
message: msg,
},
});
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

Same as info: this client.app.log(...) Promise is not awaited/handled, which can lead to unhandled promise rejections if the host rejects. Handle the Promise explicitly (e.g., void + .catch(...)).

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +63
if (client) {
client.app.log({
body: {
service: "kibi-opencode",
level: "error",
message: msg,
},
});
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

The structured client.app.log(...) call is not awaited/handled here either. Since console.error is synchronous but the structured log is async, failures will surface as unhandled rejections unless you explicitly handle the Promise (e.g., void ... .catch(...)).

Copilot uses AI. Check for mistakes.
Comment on lines +120 to +124
// Inject structured logger client so startup/hook messages route to
// client.app.log() instead of console when the host provides a client.
if (input.client) {
logger.setClient(input.client);
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

logger keeps client in a module-global variable, but the plugin only calls setClient when input.client is truthy. If the plugin is instantiated multiple times in-process, a previous client's logger can leak into a later invocation (including when input.client is omitted). Consider resetting the logger client at the start of each plugin invocation and then setting it when provided.

Copilot uses AI. Check for mistakes.
Comment on lines +288 to +296
if (injected === currentSystem) {
return;
}
const last =
output.system.length > 0
? output.system[output.system.length - 1]
: undefined;
if (last !== injected) {
output.system.push(injected);
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

In system.transform, you append injectPrompt(currentSystem, ...) to output.system, but injectPrompt returns ${current}\n\n${buildPrompt(...)}. When output.system already has entries, currentSystem is the join of them, so the appended entry contains the entire existing system prompt again, effectively duplicating prior prompts. To truly be append-only, append only the guidance block (e.g., buildPrompt(context)), and/or check for the sentinel across existing entries instead of using injectPrompt with the joined content.

Suggested change
if (injected === currentSystem) {
return;
}
const last =
output.system.length > 0
? output.system[output.system.length - 1]
: undefined;
if (last !== injected) {
output.system.push(injected);
// If injectPrompt made no changes, there's nothing to append.
if (injected === currentSystem) {
return;
}
// injectPrompt is expected to return `${currentSystem}\n\n${guidance}`.
// Derive just the new guidance suffix to avoid duplicating prior content.
let guidance = injected.slice(currentSystem.length);
if (guidance.startsWith("\n\n")) {
guidance = guidance.slice(2);
}
guidance = guidance.trimStart();
if (guidance.length === 0) {
return;
}
const last =
output.system.length > 0
? output.system[output.system.length - 1]
: undefined;
if (last !== guidance) {
output.system.push(guidance);

Copilot uses AI. Check for mistakes.
{
"name": "kibi-opencode",
"version": "0.5.2",
"version": "0.5.3",
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

This PR manually bumps version in package.json. The repo’s release flow uses Changesets to manage versions/changelogs; without a .changeset/*.md file, automated versioning will drift and the release tooling may not pick up this change correctly. Add an appropriate changeset and let changeset version update package.json/changelog.

Suggested change
"version": "0.5.3",
"version": "0.5.2",

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +8
## 0.5.3

### Patch Changes

- b543f92: Quieter terminal behavior: normal-operation logs now route through structured `client.app.log()` instead of `console.log`/`console.warn`. Error-class events (bootstrap-needed, sync/check failure, hook/init failure) remain visible in terminal. Preserved error visibility and hook compatibility for prompt injection.

Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

Changelog entry appears to be written manually. This repo uses Changesets to generate changelog updates; please add a changeset instead and let the versioning workflow update CHANGELOG.md to keep release automation consistent.

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +14
interface PluginClient {
app: {
log: (payload: Record<string, unknown>) => Promise<void>;
};
}

let client: PluginClient | null = null;

// implements REQ-opencode-kibi-plugin-v1
export function setClient(c: PluginClient): void {
client = c;
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

setClient is exported but its parameter type PluginClient is not exported. With declaration: true this will fail TypeScript declaration emit (Exported function has or is using private name 'PluginClient'). Export PluginClient (or inline the type / use a structural type in the function signature) so the package builds.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +30
if (client) {
client.app.log({
body: {
service: "kibi-opencode",
level: "info",
message: msg,
},
});
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

client.app.log(...) returns a Promise but the call is neither awaited nor handled. If the host logger rejects, this can create unhandled promise rejections. Consider explicitly fire-and-forget with void ... and attach a .catch(...) (or make the logger methods async and await).

Copilot uses AI. Check for mistakes.
@Looted
Copy link
Copy Markdown
Owner Author

Looted commented Mar 29, 2026

@copilot apply changes based on the comments in this thread in a new subpr

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 29, 2026

@Looted I've opened a new pull request, #126, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits March 29, 2026 16:02
…log promises, reset client per-invocation, fix system.transform dedup, use changeset for versioning

Agent-Logs-Url: https://github.com/Looted/kibi/sessions/57278c42-7fda-4283-b6b6-1cf55c043aa9

Co-authored-by: Looted <6255880+Looted@users.noreply.github.com>
fix(opencode): address logger correctness and prompt dedup review feedback
@Looted Looted merged commit 7a4d516 into master Mar 29, 2026
6 checks passed
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.

3 participants