kibi-opencode 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -150,6 +150,19 @@ Config files (project overrides global):
150
150
 
151
151
  Per ADR-016, prompt text injection uses only `experimental.chat.system.transform`. The `chat.params` hook is reserved for model option enrichment (temperature, topP, etc.) and never carries prompt text.
152
152
 
153
+ ### Logging Policy
154
+
155
+ The plugin follows a **silent-except-errors** policy for terminal output:
156
+
157
+ | Channel | Terminal | Structured log |
158
+ |---------|----------|---------------|
159
+ | Normal operation (sync success, guidance injection, session summaries) | No | Yes, via `client.app.log()` |
160
+ | Error-class events (bootstrap-needed, sync/check failure, hook/init failure) | Yes, via `console.error` | Yes, via `client.app.log()` |
161
+
162
+ Routine diagnostics route through [`client.app.log()`](https://opencode.ai/docs/plugins/) and never appear in the terminal. Only error-class events break terminal silence. This keeps the developer's workspace clean while preserving full visibility in structured logs for debugging.
163
+
164
+ The `experimental.chat.system.transform` hook handles prompt injection (see [Hook Policy](#hook-policy)). The `chat.params` hook is compatibility-only and never carries prompt text.
165
+
153
166
  ### Hook Modes
154
167
 
155
168
  - `auto`: Use `experimental.chat.system.transform` (primary); `chat.params` is a no-op registration for host compatibility
package/dist/index.d.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  export interface PluginInput {
2
2
  worktree: string;
3
3
  directory: string;
4
+ client?: {
5
+ app: {
6
+ log: (payload: Record<string, unknown>) => Promise<void>;
7
+ };
8
+ };
4
9
  }
5
10
  interface OpencodeEventPayload {
6
11
  type: string;
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import * as config from "./config.js";
4
4
  import * as fileFilter from "./file-filter.js";
5
5
  import * as logger from "./logger.js";
6
6
  import { analyzePath } from "./path-kind.js";
7
- import { injectPrompt } from "./prompt.js";
7
+ import { buildPrompt, SENTINEL } from "./prompt.js";
8
8
  import { isMustPriorityRequirement } from "./requirement-doc.js";
9
9
  import { createSyncScheduler } from "./scheduler.js";
10
10
  import { getSessionTracker } from "./session-tracker.js";
@@ -56,9 +56,15 @@ const kibiOpencodePlugin = async (input) => {
56
56
  return {};
57
57
  }
58
58
  // Check workspace health for bootstrap nudges
59
+ // Reset the logger client first to avoid leaking a previous invocation's
60
+ // client into this instance, then set the new one if provided.
61
+ logger.resetClient();
62
+ if (input.client) {
63
+ logger.setClient(input.client);
64
+ }
59
65
  const workspaceHealth = checkWorkspaceHealth(input.worktree);
60
66
  if (workspaceHealth.needsBootstrap) {
61
- logger.warn("kibi-opencode: workspace needs Kibi bootstrap");
67
+ logger.error("kibi-opencode: workspace needs Kibi bootstrap");
62
68
  getSessionTracker().recordWarning("bootstrap-needed", input.worktree, "Workspace missing Kibi bootstrap");
63
69
  }
64
70
  // Log session summary periodically (gated on config)
@@ -131,7 +137,7 @@ const kibiOpencodePlugin = async (input) => {
131
137
  : suggestion.suggestionType === "adr"
132
138
  ? "long-comment-missed-adr"
133
139
  : "missing-traceability";
134
- logger.info(`kibi-opencode: detected durable ${suggestion.suggestionType} knowledge in ${filePath}`);
140
+ logger.warn(`kibi-opencode: detected durable ${suggestion.suggestionType} knowledge in ${filePath}`);
135
141
  getSessionTracker().recordWarning(warningCategory, filePath, `Consider routing this ${suggestion.suggestionType} knowledge to Kibi instead of inline comments: ${suggestion.reasoning}`);
136
142
  }
137
143
  }
@@ -172,15 +178,23 @@ const kibiOpencodePlugin = async (input) => {
172
178
  const hookMode = cfg.prompt.hookMode;
173
179
  if (hookMode === "system-transform" || hookMode === "auto") {
174
180
  hooks["experimental.chat.system.transform"] = async (_input, output) => {
175
- const currentSystem = output.system.join("\n");
176
- const injected = injectPrompt(currentSystem, cfg, {
181
+ // Skip if sentinel already present in any existing entry
182
+ if (output.system.some((entry) => entry.includes(SENTINEL))) {
183
+ return;
184
+ }
185
+ // Build only the guidance block and append it; existing entries are preserved
186
+ const guidance = buildPrompt({
177
187
  recentEdits,
178
188
  workspaceHealth,
179
189
  hasRecentKbEdit,
180
190
  recentCommentSuggestion,
181
191
  });
182
- output.system.length = 0;
183
- output.system.push(injected);
192
+ const last = output.system.length > 0
193
+ ? output.system[output.system.length - 1]
194
+ : undefined;
195
+ if (last !== guidance) {
196
+ output.system.push(guidance);
197
+ }
184
198
  };
185
199
  }
186
200
  if (hookMode === "chat-params" || hookMode === "auto") {
package/dist/logger.d.ts CHANGED
@@ -1,3 +1,10 @@
1
+ export interface PluginClient {
2
+ app: {
3
+ log: (payload: Record<string, unknown>) => Promise<void>;
4
+ };
5
+ }
6
+ export declare function setClient(c: PluginClient): void;
7
+ export declare function resetClient(): void;
1
8
  export declare function info(msg: string): void;
2
9
  export declare function warn(msg: string): void;
3
10
  export declare function error(msg: string): void;
package/dist/logger.js CHANGED
@@ -1,11 +1,59 @@
1
1
  // implements REQ-opencode-kibi-plugin-v1
2
+ let client = null;
3
+ // implements REQ-opencode-kibi-plugin-v1
4
+ export function setClient(c) {
5
+ client = c;
6
+ }
7
+ // implements REQ-opencode-kibi-plugin-v1
8
+ export function resetClient() {
9
+ client = null;
10
+ }
11
+ // implements REQ-opencode-kibi-plugin-v1
2
12
  export function info(msg) {
3
- console.log("[kibi-opencode]", msg);
13
+ if (client) {
14
+ void client.app
15
+ .log({
16
+ body: {
17
+ service: "kibi-opencode",
18
+ level: "info",
19
+ message: msg,
20
+ },
21
+ })
22
+ .catch(console.error);
23
+ return;
24
+ }
25
+ // Fallback when no client is available (e.g. during tests or early init)
4
26
  }
27
+ // implements REQ-opencode-kibi-plugin-v1
5
28
  export function warn(msg) {
6
- console.warn("[kibi-opencode]", msg);
29
+ if (client) {
30
+ void client.app
31
+ .log({
32
+ body: {
33
+ service: "kibi-opencode",
34
+ level: "warn",
35
+ message: msg,
36
+ },
37
+ })
38
+ .catch(console.error);
39
+ return;
40
+ }
41
+ // Fallback when no client is available
7
42
  }
8
43
  // implements REQ-opencode-kibi-plugin-v1
9
44
  export function error(msg) {
45
+ // Always emit to console for user visibility
10
46
  console.error("[kibi-opencode]", msg);
47
+ // Also emit to structured logs if client is available
48
+ if (client) {
49
+ void client.app
50
+ .log({
51
+ body: {
52
+ service: "kibi-opencode",
53
+ level: "error",
54
+ message: msg,
55
+ },
56
+ })
57
+ .catch(console.error);
58
+ }
11
59
  }
package/dist/scheduler.js CHANGED
@@ -114,7 +114,7 @@ class WorktreeSyncScheduler {
114
114
  const checkResult = await this.runCheck(this.worktree, checkRules);
115
115
  checkExitCode = checkResult.exitCode;
116
116
  if (checkExitCode !== 0) {
117
- logger.warn(`check.failed ${JSON.stringify({ rules: checkRules, exitCode: checkExitCode })}`);
117
+ logger.error(`check.failed ${JSON.stringify({ rules: checkRules, exitCode: checkExitCode })}`);
118
118
  }
119
119
  else {
120
120
  logger.info(`check.succeeded ${JSON.stringify({ rules: checkRules })}`);
@@ -157,7 +157,7 @@ class WorktreeSyncScheduler {
157
157
  logger.info(`sync.succeeded ${JSON.stringify(meta)}`);
158
158
  }
159
159
  else {
160
- logger.warn(`sync.failed ${JSON.stringify(meta)}`);
160
+ logger.error(`sync.failed ${JSON.stringify(meta)}`);
161
161
  }
162
162
  this.onRunComplete?.(meta);
163
163
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kibi-opencode",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Kibi OpenCode plugin - thin adapter to integrate Kibi with OpenCode sessions",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",