kibi-opencode 1.0.0 → 2.0.0

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.
@@ -23,9 +23,11 @@ export interface AutoUpdateRunnerDeps {
23
23
  log: (message: string, metadata?: Record<string, unknown>) => void;
24
24
  }
25
25
  export declare function findKibiOpencodePluginEntry(directory: string): KibiOpencodePluginEntry | null;
26
+ export declare function findPackageJsonUp(startUrl: string): string | null;
26
27
  export declare function getCachedPluginVersion(): string | null;
27
28
  export declare function getLatestPluginVersion(channel?: string): Promise<string | null>;
28
29
  export declare function invalidateKibiOpencodePackage(): boolean;
29
30
  export declare function runBunInstallForOpenCodePlugin(): Promise<boolean>;
30
31
  export declare function createAutoUpdateRunner(deps: AutoUpdateRunnerDeps): (input: AutoUpdateInput) => Promise<AutoUpdateResult>;
32
+ export declare function notifyAutoUpdate(message: string): Promise<void>;
31
33
  export declare const runKibiOpencodeAutoUpdate: (input: AutoUpdateInput) => Promise<AutoUpdateResult>;
@@ -188,7 +188,7 @@ function readVersionFromPackageJson(packageJsonPath) {
188
188
  const parsed = parseJsonObject(fs.readFileSync(packageJsonPath, "utf8"));
189
189
  return typeof parsed?.version === "string" ? parsed.version : null;
190
190
  }
191
- function findPackageJsonUp(startUrl) {
191
+ export function findPackageJsonUp(startUrl) {
192
192
  let current = path.dirname(fileURLToPath(startUrl));
193
193
  while (true) {
194
194
  const packageJsonPath = path.join(current, "package.json");
@@ -384,13 +384,14 @@ export function createAutoUpdateRunner(deps) {
384
384
  return { status: "updated", currentVersion, latestVersion };
385
385
  };
386
386
  }
387
+ export async function notifyAutoUpdate(message) {
388
+ logger.info("auto-update.notification", { message });
389
+ }
387
390
  export const runKibiOpencodeAutoUpdate = createAutoUpdateRunner({
388
391
  getCurrentVersion: getCachedPluginVersion,
389
392
  getLatestVersion: getLatestPluginVersion,
390
393
  invalidatePackage: invalidateKibiOpencodePackage,
391
394
  runInstall: runBunInstallForOpenCodePlugin,
392
- notify: async (message) => {
393
- logger.info("auto-update.notification", { message });
394
- },
395
+ notify: notifyAutoUpdate,
395
396
  log: (message, metadata) => logger.info(message, metadata),
396
397
  });
@@ -47,6 +47,11 @@ export interface EnforcementPolicyInput {
47
47
  /** Posture fallback when resolvedContext is unavailable. */
48
48
  posture?: RepoPosture | undefined;
49
49
  }
50
+ export interface NormalizedPolicyEvent extends EnforcementLifecycleEvent {
51
+ pathKind: PathKind;
52
+ linkedEntityResult: PolicyLinkedEntityResult;
53
+ e2eSignal: E2eCoverageSignal;
54
+ }
50
55
  interface EnforcementPolicyResultBase {
51
56
  affectedPaths: string[];
52
57
  dirtyFileCount: number;
@@ -70,4 +75,9 @@ export type EnforcementPolicyResult = (EnforcementPolicyResultBase & {
70
75
  text: null;
71
76
  });
72
77
  export declare function computeEnforcementPolicy(input: EnforcementPolicyInput): EnforcementPolicyResult;
78
+ export declare function advisoryResultFromEvents(relevantEvents: readonly NormalizedPolicyEvent[], extras: {
79
+ affectedPaths: string[];
80
+ e2eReminder: string | null;
81
+ reminderKindsToMark: ReminderKind[];
82
+ }): EnforcementPolicyResult;
73
83
  export {};
@@ -266,23 +266,33 @@ export function computeEnforcementPolicy(input) {
266
266
  text: null,
267
267
  };
268
268
  }
269
+ return advisoryResultFromEvents(relevantEvents, {
270
+ affectedPaths,
271
+ e2eReminder,
272
+ reminderKindsToMark,
273
+ });
274
+ }
275
+ // Defensive empty-list checkpoint. `computeEnforcementPolicy` returns earlier
276
+ // when `relevantEvents` is empty; tests call this helper directly so the
277
+ // branch stays executable and covered.
278
+ export function advisoryResultFromEvents(relevantEvents, extras) {
269
279
  const firstRelevantEvent = relevantEvents[0];
270
280
  if (!firstRelevantEvent) {
271
281
  return {
272
282
  kind: "checkpoint_passed",
273
- affectedPaths,
283
+ affectedPaths: extras.affectedPaths,
274
284
  dirtyFileCount: 0,
275
- e2eReminder,
276
- reminderKindsToMark,
285
+ e2eReminder: extras.e2eReminder,
286
+ reminderKindsToMark: extras.reminderKindsToMark,
277
287
  text: null,
278
288
  };
279
289
  }
280
290
  return {
281
291
  kind: "advisory_guidance",
282
- affectedPaths,
292
+ affectedPaths: extras.affectedPaths,
283
293
  dirtyFileCount: relevantEvents.length,
284
- e2eReminder,
285
- reminderKindsToMark,
294
+ e2eReminder: extras.e2eReminder,
295
+ reminderKindsToMark: extras.reminderKindsToMark,
286
296
  text: advisoryText(firstRelevantEvent),
287
297
  };
288
298
  }
@@ -1,3 +1,7 @@
1
+ export declare function emptyLinkedTargets(): {
2
+ ids: [];
3
+ source: "none";
4
+ };
1
5
  export type SymbolsManifestRow = {
2
6
  id?: string;
3
7
  sourceFile?: string;
@@ -2,6 +2,10 @@
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import { loadKbSyncPaths } from "./file-filter.js";
5
+ // ── Shared types ────────────────────────────────────────────────────
6
+ export function emptyLinkedTargets() {
7
+ return { ids: [], source: "none" };
8
+ }
5
9
  // ── Lightweight YAML parser (symbols.yaml subset) ───────────────────
6
10
  //
7
11
  // Handles:
@@ -218,7 +222,7 @@ export function getFileLinkedEntityIds(worktree, filePath) {
218
222
  return { ids: orderedIds.slice(0, 3), source: "symbols" };
219
223
  }
220
224
  catch {
221
- return { ids: [], source: "none" };
225
+ return emptyLinkedTargets();
222
226
  }
223
227
  }
224
228
  // implements REQ-opencode-file-context-guidance-v1
@@ -26,7 +26,9 @@ interface KibiBootstrapCapabilityDetectionInput {
26
26
  sdkTypesDts?: string;
27
27
  }
28
28
  export declare function findSdkPackageJsonForPluginRoot(pluginRoot: string): string | undefined;
29
+ export declare function capabilityInputsOrEmpty<T extends object>(load: () => T): T | Record<string, never>;
29
30
  export declare function detectKibiBootstrapCommandCapability(input: KibiBootstrapCapabilityDetectionInput): KibiBootstrapCommandCapability;
30
31
  export declare function getKibiBootstrapCommandCapability(): KibiBootstrapCommandCapability;
32
+ export declare function _resetKibiBootstrapCapabilityCacheForTests(): void;
31
33
  export declare function registerKibiBootstrapCommand(configInput: unknown, capability?: KibiBootstrapCommandCapability): KibiBootstrapCommandCapability;
32
34
  export {};
@@ -111,6 +111,14 @@ function hasConfigHook(pluginHooksDts) {
111
111
  function hasConfigCommandField(sdkTypesDts) {
112
112
  return /\bcommand\??:\s*\{[\s\S]*?\[key:\s*string\]:\s*\{[\s\S]*?\btemplate:\s*string\s*;/.test(sdkTypesDts);
113
113
  }
114
+ export function capabilityInputsOrEmpty(load) {
115
+ try {
116
+ return load();
117
+ }
118
+ catch {
119
+ return {};
120
+ }
121
+ }
114
122
  function resolveHostCapabilityInputs() {
115
123
  const moduleDir = path.dirname(fileURLToPath(import.meta.url));
116
124
  const dogfoodHost = resolveDogfoodHostCapabilityInputs([
@@ -125,7 +133,7 @@ function resolveHostCapabilityInputs() {
125
133
  if (dogfoodHost) {
126
134
  return dogfoodHost;
127
135
  }
128
- try {
136
+ return capabilityInputsOrEmpty(() => {
129
137
  const pluginPackageJsonPath = require.resolve("@opencode-ai/plugin/package.json");
130
138
  const pluginRoot = path.dirname(pluginPackageJsonPath);
131
139
  const sdkPackageJsonPath = findSdkPackageJsonForPluginRoot(pluginRoot) ??
@@ -139,10 +147,7 @@ function resolveHostCapabilityInputs() {
139
147
  ...(pluginHooksDts ? { pluginHooksDts } : {}),
140
148
  ...(sdkTypesDts ? { sdkTypesDts } : {}),
141
149
  };
142
- }
143
- catch {
144
- return {};
145
- }
150
+ });
146
151
  }
147
152
  function isRecord(value) {
148
153
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -177,6 +182,10 @@ export function getKibiBootstrapCommandCapability() {
177
182
  return cachedCapability;
178
183
  }
179
184
  // implements REQ-KIBI-BOOTSTRAP-PLAN
185
+ export function _resetKibiBootstrapCapabilityCacheForTests() {
186
+ cachedCapability = null;
187
+ }
188
+ // implements REQ-KIBI-BOOTSTRAP-PLAN
180
189
  export function registerKibiBootstrapCommand(configInput, capability = getKibiBootstrapCommandCapability()) {
181
190
  if (!capability.supported) {
182
191
  return capability;
@@ -10,6 +10,7 @@ import type { RiskClass } from "./risk-classifier.js";
10
10
  * - "ignored": The change is in a build artifact or third-party path — no KB
11
11
  * impact.
12
12
  */
13
+ export declare function isSafeDocsUnknownPath(riskClass: RiskClass, pathKind: PathKind): boolean;
13
14
  export type MeaningfulChangeClass = "requires-kb-evidence" | "advisory" | "ignored";
14
15
  /**
15
16
  * Classify whether a file change requires KB freshness evidence.
@@ -1,3 +1,15 @@
1
+ /**
2
+ * Classification for whether a file change requires KB freshness evidence.
3
+ *
4
+ * - "requires-kb-evidence": The change is meaningful for KB freshness — the KB
5
+ * snapshot should be considered stale and needs a re-sync.
6
+ * - "advisory": The change is low-risk (lockfiles, docs-only) — advisory only.
7
+ * - "ignored": The change is in a build artifact or third-party path — no KB
8
+ * impact.
9
+ */
10
+ export function isSafeDocsUnknownPath(riskClass, pathKind) {
11
+ return riskClass === "safe_docs_only" && pathKind === "unknown";
12
+ }
1
13
  // Directories whose contents are always ignored for KB freshness.
2
14
  const IGNORED_DIRECTORIES = [
3
15
  ".git",
@@ -113,9 +125,8 @@ export function classifyMeaningfulChange(params) {
113
125
  if (UPGRADE_RISK_CLASSES.has(riskClass)) {
114
126
  return "requires-kb-evidence";
115
127
  }
116
- if (riskClass === "safe_docs_only" && pathKind === "unknown") {
128
+ if (isSafeDocsUnknownPath(riskClass, pathKind))
117
129
  return "advisory";
118
- }
119
130
  }
120
131
  // 5. DEFAULT — safety default for unknown paths
121
132
  return "requires-kb-evidence";
package/dist/plugin.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  import { type OpenCodeConfigHookInput } from "./kibi-bootstrap-capability.js";
2
+ export declare function resetCommentSuggestion(): null;
3
+ export declare function nextRecentCommentSuggestion<T>(inspectingCodeComments: boolean, suggestion: T | null | undefined): T | null;
4
+ export declare function adoptPrecomputedSuggestion<T>(recent: T | null, precomputed: T | null | undefined): T | null;
2
5
  export interface PluginInput {
3
6
  worktree: string;
4
7
  directory: string;