kibi-opencode 0.15.0 → 0.15.2
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 +4 -12
- package/dist/config.d.ts +0 -3
- package/dist/config.js +0 -9
- package/dist/e2e-coverage-signals.js +1 -3
- package/dist/enforcement-policy.d.ts +1 -1
- package/dist/enforcement-policy.js +9 -4
- package/dist/enforcement-scope.js +1 -3
- package/dist/file-entity-links.js +2 -6
- package/dist/file-operation-reminders.d.ts +4 -4
- package/dist/file-operation-state.js +4 -2
- package/dist/init-kibi-alias.js +0 -1
- package/dist/init-kibi-capability.js +1 -5
- package/dist/kb-freshness-state.js +6 -2
- package/dist/kibi-checkpoint-runner.d.ts +1 -1
- package/dist/kibi-checkpoint-runner.js +6 -3
- package/dist/knowledge-classifier.js +2 -1
- package/dist/meaningful-change-classifier.d.ts +1 -1
- package/dist/meaningful-change-classifier.js +1 -2
- package/dist/plugin-startup.js +0 -1
- package/dist/plugin.js +45 -395
- package/dist/prompt.d.ts +2 -6
- package/dist/prompt.js +21 -84
- package/dist/reconcile-engine.d.ts +15 -1
- package/dist/reconcile-engine.js +1 -3
- package/dist/scheduler.js +16 -4
- package/dist/session-edit-state.js +2 -1
- package/dist/source-linked-guidance.js +3 -1
- package/dist/tui.js +1 -403
- package/dist/tui.jsx +1 -113
- package/dist/version-metadata.json +1 -1
- package/package.json +3 -5
- package/dist/brief-delivery-reasons.d.ts +0 -12
- package/dist/brief-delivery-reasons.js +0 -132
- package/dist/brief-intent.d.ts +0 -41
- package/dist/brief-intent.js +0 -142
- package/dist/briefing-runtime.d.ts +0 -24
- package/dist/briefing-runtime.js +0 -277
- package/dist/graph-narrator.d.ts +0 -25
- package/dist/graph-narrator.js +0 -408
- package/dist/idle-brief-audit.d.ts +0 -36
- package/dist/idle-brief-audit.js +0 -186
- package/dist/idle-brief-paths.d.ts +0 -6
- package/dist/idle-brief-paths.js +0 -120
- package/dist/idle-brief-reader.d.ts +0 -37
- package/dist/idle-brief-reader.js +0 -163
- package/dist/idle-brief-runtime.d.ts +0 -55
- package/dist/idle-brief-runtime.js +0 -496
- package/dist/idle-brief-store.d.ts +0 -113
- package/dist/idle-brief-store.js +0 -262
- package/dist/session-fingerprint.d.ts +0 -11
- package/dist/session-fingerprint.js +0 -21
- package/dist/tui-brief-delivery.d.ts +0 -67
- package/dist/tui-brief-delivery.js +0 -279
- package/dist/tui-brief-view-model.d.ts +0 -63
- package/dist/tui-brief-view-model.js +0 -209
- package/dist/utils/brief-marker.d.ts +0 -19
- package/dist/utils/brief-marker.js +0 -101
package/README.md
CHANGED
|
@@ -24,8 +24,8 @@ The plugin now uses a posture-aware, low-token smart-enforcement model before em
|
|
|
24
24
|
|
|
25
25
|
- **Repo posture detection**: distinguishes `root_active`, `root_partial`, `root_uninitialized`, `vendored_only`, and `hybrid_root_plus_vendored`
|
|
26
26
|
- **Risk classification**: separates `safe_docs_only`, `safe_test_only`, `kb_doc_structural`, `req_policy_candidate`, `behavior_candidate`, `traceability_candidate`, and `manual_kb_edit`
|
|
27
|
-
- **Source-linked
|
|
28
|
-
- **Start-task risky cue**: authoritative risky edits also add a compact
|
|
27
|
+
- **Source-linked Kibi links**: risky code edits (`behavior_candidate`, `traceability_candidate`) prepend a concise list of existing Kibi links (e.g., `- Existing Kibi links: REQ-001, REQ-002`) when 1-3 concrete source-linked KB hits are found in `documentation/symbols.yaml`. Skip on cache hit.
|
|
28
|
+
- **Start-task risky cue**: authoritative risky edits also add a compact Kibi context cue so agents can start with explicit source-linked guidance before acting, while staying inside the same single prompt block and token budget.
|
|
29
29
|
- **Effective mode gating**: `advisory` (default) never blocks; `strict` escalates checks and reminders for `root_active` and `hybrid_root_plus_vendored` postures when `requireRootKbForStrict` is enabled; `hard` fails closed for authoritative roots and linked git worktrees, injecting a stop-state with MCP recovery steps until the Kibi checkpoint passes. `maintenanceDegraded` overrides everything back to `advisory`.
|
|
30
30
|
- **Low-token prompt policy**: docs-only and test-only edits avoid unnecessary discovery prompts; vendored-only repos suppress operational bootstrap nudges; at most one contextual block is injected per prompt (≤120 words, ≤5 bullets)
|
|
31
31
|
- **Completion reminder**: when `completionReminder` is enabled, risky code edits append a single prompt-visible `kb_check` reminder exactly once per cached context
|
|
@@ -127,13 +127,6 @@ The plugin injects guidance into OpenCode sessions to improve agent grounding. U
|
|
|
127
127
|
|
|
128
128
|
OpenCode exposes Kibi MCP prompts as slash commands. The \`/init-kibi\` command triggers the \`kb_autopilot_generate\` workflow to assist in retroactive bootstrap using only public MCP tools.
|
|
129
129
|
|
|
130
|
-
When the plugin detects an authoritative risky edit (`behavior_candidate` or `traceability_candidate` risk class), it automatically renders a Kibi briefing before the prompt. The plugin uses two complementary paths: the `file.edited` event hook as a fast-path hint, and prompt-cycle reconciliation as an authoritative fallback for programmatic edits that bypass the event bus. Briefings are rendered directly into the prompt to ensure immediate visibility.
|
|
131
|
-
|
|
132
|
-
- **Immediate delivery**: Briefings are rendered-first into the prompt guidance block headed `🧠 **Kibi briefing available**` and TUI toasts titled `Kibi Knowledge Update`. Unread briefings automatically open the interactive TUI via the `kibi.brief` route.
|
|
133
|
-
- **Narrative structure**: Delivery favors user-facing prose with `What changed` and `Why it matters`, plus conditional `Project knowledge impact` / `Interpretation note` sections when evidence or caveats exist.
|
|
134
|
-
- **TL;DR fallback**: If a full briefing is unavailable, fallback output still preserves `What changed` / `Why it matters` framing while keeping the manual command cue available.
|
|
135
|
-
- **Manual command**: Use `/brief-kibi` or the `kibi.open_latest_brief` command at any time to trigger an on-demand briefing if auto-delivery is skipped or fails.
|
|
136
|
-
|
|
137
130
|
### Discovery-first MCP guidance
|
|
138
131
|
|
|
139
132
|
Agent-visible guidance is intentionally limited to the curated public MCP surface:
|
|
@@ -179,7 +172,6 @@ Config files (project overrides global):
|
|
|
179
172
|
| `ux.toastFailures` | boolean | `true` | Show failure toasts for sync/check issues |
|
|
180
173
|
| `ux.toastSuccesses` | boolean | `false` | Show success toasts for sync/check completion |
|
|
181
174
|
| `ux.toastCooldownMs` | number | `10000` | Cooldown between repeated UX toasts |
|
|
182
|
-
| `ux.briefs.autoSubmit` | boolean | `true` | **Deprecated/No-op**: Auto-submission is no longer needed with render-first briefing |
|
|
183
175
|
PP|| `guidance.dynamic` | boolean | `true` | Enable dynamic contextual guidance |
|
|
184
176
|
| `guidance.dynamic` | boolean | `true` | Enable dynamic contextual guidance |
|
|
185
177
|
| `guidance.warnOnKbEdits` | boolean | `true` | Enable loud warnings for .kb/** edits |
|
|
@@ -234,7 +226,7 @@ The plugin uses the official OpenCode toast APIs with automatic capability detec
|
|
|
234
226
|
1. **Legacy transport**: `client.tui.toast(payload)` — used when available in plugin context
|
|
235
227
|
2. **SDK transport**: `client.tui.showToast({ body: payload })` — used as fallback
|
|
236
228
|
3. **No capability**: Returns `{ status: "unavailable", reason: "missing-capability" }`
|
|
237
|
-
The `sendToast` helper returns a discriminated `SendToastResult` union and never throws. There is no raw HTTP fallback.
|
|
229
|
+
The `sendToast` helper returns a discriminated `SendToastResult` union and never throws. There is no raw HTTP fallback.
|
|
238
230
|
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.
|
|
239
231
|
|
|
240
232
|
### Hook Modes
|
|
@@ -315,7 +307,7 @@ The OpenCode plugin respects the repository ignore policy used by Kibi's discove
|
|
|
315
307
|
- The plugin's background sync and file-event handling skip paths matched by repository `.gitignore` files, nested `.gitignore` files, and `.git/info/exclude`.
|
|
316
308
|
- The plugin also treats a curated set of tool/runtime directories as never-relevant for KB sync (for example: `.sisyphus`, `.opencode`, `.kb`, `.git`, `node_modules`, `vendor`, `third_party`).
|
|
317
309
|
|
|
318
|
-
When a file event occurs for an ignored path, the plugin skips processing and will not surface candidate guidance for that file. This avoids noisy
|
|
310
|
+
When a file event occurs for an ignored path, the plugin skips processing and will not surface candidate guidance for that file. This avoids noisy sync triggers and prevents build/editor artifacts from triggering KB sync work.
|
|
319
311
|
|
|
320
312
|
- **E2e reminder evidence**: File-operation reminders use exact Kibi graph evidence first (`covered_by` links to `[e2e]`-tagged entities or `/e2e/`-sourced entities) and narrow path heuristics second. Package-level e2e tests do not trigger "authoritative evidence" flags at the file level.
|
|
321
313
|
|
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
|
@@ -11,9 +11,6 @@ const DEFAULTS = {
|
|
|
11
11
|
toastFailures: true,
|
|
12
12
|
toastSuccesses: false,
|
|
13
13
|
toastCooldownMs: 10000,
|
|
14
|
-
briefs: {
|
|
15
|
-
autoSubmit: true,
|
|
16
|
-
},
|
|
17
14
|
},
|
|
18
15
|
guidance: {
|
|
19
16
|
dynamic: true,
|
|
@@ -103,12 +100,6 @@ export function validateAndMerge(obj) {
|
|
|
103
100
|
out.ux.toastSuccesses = u.toastSuccesses;
|
|
104
101
|
if (typeof u.toastCooldownMs === "number")
|
|
105
102
|
out.ux.toastCooldownMs = u.toastCooldownMs;
|
|
106
|
-
if (u.briefs && typeof u.briefs === "object") {
|
|
107
|
-
const b = u.briefs;
|
|
108
|
-
out.ux.briefs = { autoSubmit: true };
|
|
109
|
-
if (typeof b.autoSubmit === "boolean")
|
|
110
|
-
out.ux.briefs.autoSubmit = b.autoSubmit;
|
|
111
|
-
}
|
|
112
103
|
}
|
|
113
104
|
if (typeof src.logLevel === "string")
|
|
114
105
|
out.logLevel = src.logLevel;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { E2eCoverageSignal } from "./e2e-coverage-signals.js";
|
|
2
2
|
import type { FileLifecycle, ReminderKind } from "./file-operation-state.js";
|
|
3
|
+
import type { KbFreshnessEvidence } from "./kb-freshness-state.js";
|
|
3
4
|
import type { PathKind } from "./path-kind.js";
|
|
4
5
|
import type { RepoPosture } from "./repo-posture.js";
|
|
5
6
|
import type { RiskClass } from "./risk-classifier.js";
|
|
6
7
|
import type { EffectiveMode } from "./smart-enforcement.js";
|
|
7
8
|
import type { WorkContext } from "./work-context-resolver.js";
|
|
8
|
-
import type { KbFreshnessEvidence } from "./kb-freshness-state.js";
|
|
9
9
|
export interface PolicyLinkedEntityResult {
|
|
10
10
|
ids: string[];
|
|
11
11
|
source: "symbols" | "doc-path" | "none";
|
|
@@ -55,7 +55,10 @@ function normalizeEvents(input) {
|
|
|
55
55
|
return input.lifecycleEvents.map((event, index) => {
|
|
56
56
|
const linkedEntityResult = input.linkedEntityResults?.[index] ??
|
|
57
57
|
(input.linkedEntityIds?.[index]
|
|
58
|
-
? {
|
|
58
|
+
? {
|
|
59
|
+
ids: input.linkedEntityIds[index] ?? [],
|
|
60
|
+
source: "symbols",
|
|
61
|
+
}
|
|
59
62
|
: DEFAULT_LINKED_ENTITY_RESULT);
|
|
60
63
|
return {
|
|
61
64
|
...event,
|
|
@@ -97,7 +100,8 @@ function uniqueReminderKinds(events) {
|
|
|
97
100
|
else {
|
|
98
101
|
add("kibi_write");
|
|
99
102
|
}
|
|
100
|
-
if (event.e2eSignal.level !== "none" &&
|
|
103
|
+
if (event.e2eSignal.level !== "none" &&
|
|
104
|
+
event.e2eSignal.reminderText !== null) {
|
|
101
105
|
add(event.lifecycle === "deleted" ? "e2e_delete" : "e2e_write");
|
|
102
106
|
}
|
|
103
107
|
}
|
|
@@ -168,7 +172,8 @@ function hardBlockText(events) {
|
|
|
168
172
|
if (remainingCount > 0) {
|
|
169
173
|
pathLines.push(`- +${remainingCount} more dirty files`);
|
|
170
174
|
}
|
|
171
|
-
const deletedWithoutLinks = events.some((event) => event.lifecycle === "deleted" &&
|
|
175
|
+
const deletedWithoutLinks = events.some((event) => event.lifecycle === "deleted" &&
|
|
176
|
+
event.linkedEntityResult.ids.length === 0);
|
|
172
177
|
const representativePath = events[0]?.normalizedPath ?? "<changed-file>";
|
|
173
178
|
const evidenceNotes = [linkedIdsText(events), e2eEvidenceText(events)].filter((note) => note !== null);
|
|
174
179
|
const deletionCleanup = deletedWithoutLinks
|
|
@@ -189,7 +194,7 @@ function hardBlockText(events) {
|
|
|
189
194
|
"KB freshness resolution:",
|
|
190
195
|
"- **KB updated**: run `kb_search` for discovery, then `kb_upsert`/`kb_delete` for mutations, then `kb_check`.",
|
|
191
196
|
"- **No KB impact**: provide a no-impact rationale in your final report after source-linked discovery via `kb_search` or `kb_query(sourceFile=...)` and `kb_check`.",
|
|
192
|
-
"- **Deferred/failed**: do not claim task completion."
|
|
197
|
+
"- **Deferred/failed**: do not claim task completion.",
|
|
193
198
|
].join("\n"),
|
|
194
199
|
shownPaths,
|
|
195
200
|
remainingCount,
|
|
@@ -30,7 +30,5 @@ export function buildDirtyRelevantFingerprint(values) {
|
|
|
30
30
|
if (normalized.length === 0) {
|
|
31
31
|
return "clean";
|
|
32
32
|
}
|
|
33
|
-
return createHash("sha256")
|
|
34
|
-
.update(JSON.stringify(normalized))
|
|
35
|
-
.digest("hex");
|
|
33
|
+
return createHash("sha256").update(JSON.stringify(normalized)).digest("hex");
|
|
36
34
|
}
|
|
@@ -108,7 +108,6 @@ export function parseSymbolsYaml(content) {
|
|
|
108
108
|
if (target === undefined)
|
|
109
109
|
continue;
|
|
110
110
|
pendingRel.target = target.trim();
|
|
111
|
-
continue;
|
|
112
111
|
}
|
|
113
112
|
}
|
|
114
113
|
}
|
|
@@ -142,7 +141,7 @@ function resolveDocPathIdentity(relPath, syncPaths) {
|
|
|
142
141
|
// Strip glob from pattern to get the root dir prefix
|
|
143
142
|
// e.g. "documentation/requirements/**/*.md" → "documentation/requirements"
|
|
144
143
|
const rootDir = pattern.replace(/\/\*\*\/.*$/, "").replace(/\/+$/, "");
|
|
145
|
-
if (normalizedRel.startsWith(rootDir
|
|
144
|
+
if (normalizedRel.startsWith(`${rootDir}/`)) {
|
|
146
145
|
return entityId;
|
|
147
146
|
}
|
|
148
147
|
}
|
|
@@ -168,10 +167,7 @@ function normalizeFilePath(worktree, filePath) {
|
|
|
168
167
|
const absPath = path.isAbsolute(filePath)
|
|
169
168
|
? filePath
|
|
170
169
|
: path.resolve(worktree, filePath);
|
|
171
|
-
return path
|
|
172
|
-
.relative(worktree, absPath)
|
|
173
|
-
.split(path.sep)
|
|
174
|
-
.join("/");
|
|
170
|
+
return path.relative(worktree, absPath).split(path.sep).join("/");
|
|
175
171
|
}
|
|
176
172
|
// ── Public API ──────────────────────────────────────────────────────
|
|
177
173
|
// implements REQ-opencode-file-context-guidance-v1
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { RepoPosture } from "./repo-posture.js";
|
|
2
|
-
import type { PathKind } from "./path-kind.js";
|
|
3
|
-
import type { RiskClass } from "./risk-classifier.js";
|
|
4
|
-
import type { ReminderKind } from "./file-operation-state.js";
|
|
5
1
|
import type { E2eCoverageSignal } from "./e2e-coverage-signals.js";
|
|
6
2
|
import { type CheckpointEvidence, type EnforcementLifecycleEvent, type EnforcementPolicyResult } from "./enforcement-policy.js";
|
|
3
|
+
import type { ReminderKind } from "./file-operation-state.js";
|
|
4
|
+
import type { PathKind } from "./path-kind.js";
|
|
5
|
+
import type { RepoPosture } from "./repo-posture.js";
|
|
6
|
+
import type { RiskClass } from "./risk-classifier.js";
|
|
7
7
|
import type { EffectiveMode } from "./smart-enforcement.js";
|
|
8
8
|
import type { WorkContext } from "./work-context-resolver.js";
|
|
9
9
|
export interface LinkedEntityResult {
|
|
@@ -37,11 +37,13 @@ export function createFileOperationState(opts) {
|
|
|
37
37
|
return "edited";
|
|
38
38
|
}
|
|
39
39
|
// created|edited + deleted -> deleted
|
|
40
|
-
if ((existing === "created" || existing === "edited") &&
|
|
40
|
+
if ((existing === "created" || existing === "edited") &&
|
|
41
|
+
incoming === "deleted") {
|
|
41
42
|
return "deleted";
|
|
42
43
|
}
|
|
43
44
|
// deleted + created|edited -> deleted
|
|
44
|
-
if (existing === "deleted" &&
|
|
45
|
+
if (existing === "deleted" &&
|
|
46
|
+
(incoming === "created" || incoming === "edited")) {
|
|
45
47
|
return "deleted";
|
|
46
48
|
}
|
|
47
49
|
// Fallback: use incoming
|
package/dist/init-kibi-alias.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
2
|
import { createRequire } from "node:module";
|
|
3
|
+
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { buildInitKibiAlias } from "./init-kibi-alias.js";
|
|
6
6
|
export const INIT_KIBI_COMMAND_NAME = "init-kibi";
|
|
@@ -97,7 +97,6 @@ function readPackageVersion(filePath) {
|
|
|
97
97
|
return undefined;
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
-
// implements REQ-opencode-kibi-briefing-v2
|
|
101
100
|
export function findSdkPackageJsonForPluginRoot(pluginRoot) {
|
|
102
101
|
const scopeRoot = path.dirname(pluginRoot);
|
|
103
102
|
const candidates = [
|
|
@@ -151,7 +150,6 @@ function isRecord(value) {
|
|
|
151
150
|
function isCommandMap(value) {
|
|
152
151
|
return isRecord(value);
|
|
153
152
|
}
|
|
154
|
-
// implements REQ-opencode-kibi-briefing-v2
|
|
155
153
|
export function detectInitKibiCommandCapability(input) {
|
|
156
154
|
const { pluginVersion, pluginHooksDts, sdkTypesDts } = input;
|
|
157
155
|
if (typeof pluginHooksDts !== "string" || pluginHooksDts.length === 0) {
|
|
@@ -171,7 +169,6 @@ export function detectInitKibiCommandCapability(input) {
|
|
|
171
169
|
pluginVersion: pluginVersion ?? "unknown",
|
|
172
170
|
};
|
|
173
171
|
}
|
|
174
|
-
// implements REQ-opencode-kibi-briefing-v2
|
|
175
172
|
export function getInitKibiCommandCapability() {
|
|
176
173
|
if (cachedCapability?.supported) {
|
|
177
174
|
return cachedCapability;
|
|
@@ -179,7 +176,6 @@ export function getInitKibiCommandCapability() {
|
|
|
179
176
|
cachedCapability = detectInitKibiCommandCapability(resolveHostCapabilityInputs());
|
|
180
177
|
return cachedCapability;
|
|
181
178
|
}
|
|
182
|
-
// implements REQ-opencode-kibi-briefing-v2
|
|
183
179
|
export function registerInitKibiCommand(configInput, capability = getInitKibiCommandCapability()) {
|
|
184
180
|
if (!capability.supported) {
|
|
185
181
|
return capability;
|
|
@@ -199,8 +199,12 @@ export function createKbFreshnessEvidenceStore() {
|
|
|
199
199
|
kbMutation: record.kbMutation,
|
|
200
200
|
kbCheck: record.kbCheck,
|
|
201
201
|
...(record.decision !== undefined ? { decision: record.decision } : {}),
|
|
202
|
-
...(record.rationale !== undefined
|
|
203
|
-
|
|
202
|
+
...(record.rationale !== undefined
|
|
203
|
+
? { rationale: record.rationale }
|
|
204
|
+
: {}),
|
|
205
|
+
...(record.checkRules !== undefined
|
|
206
|
+
? { checkRules: record.checkRules }
|
|
207
|
+
: {}),
|
|
204
208
|
};
|
|
205
209
|
},
|
|
206
210
|
resetScope(scope) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type KibiConfig } from "./config.js";
|
|
2
|
-
import { type EnforcementLifecycleEvent, type PolicyLinkedEntityResult } from "./enforcement-policy.js";
|
|
3
2
|
import type { E2eCoverageSignal } from "./e2e-coverage-signals.js";
|
|
3
|
+
import { type EnforcementLifecycleEvent, type PolicyLinkedEntityResult } from "./enforcement-policy.js";
|
|
4
4
|
import type { PathKind } from "./path-kind.js";
|
|
5
5
|
import { type CheckRunner, type SyncRunMetadata, type SyncRunner, type TimeoutHandle } from "./scheduler.js";
|
|
6
6
|
import type { WorkContext } from "./work-context-resolver.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// implements REQ-opencode-worktree-hard-enforcement-v1
|
|
2
2
|
import { DEFAULTS } from "./config.js";
|
|
3
|
-
import { buildEnforcementScopeKey } from "./enforcement-scope.js";
|
|
4
3
|
import { computeEnforcementPolicy, } from "./enforcement-policy.js";
|
|
4
|
+
import { buildEnforcementScopeKey } from "./enforcement-scope.js";
|
|
5
5
|
import { createSyncScheduler, } from "./scheduler.js";
|
|
6
6
|
const HARD_CHECKPOINT_TIMEOUT_MS = 30_000;
|
|
7
7
|
const CHECKPOINT_REASON = "smart-enforcement.checkpoint";
|
|
@@ -69,7 +69,8 @@ export class KibiCheckpointRunner {
|
|
|
69
69
|
if (context) {
|
|
70
70
|
return this.passed.has(this.scopeKey(context, normalizedFingerprint));
|
|
71
71
|
}
|
|
72
|
-
return (this.passedScopeKeysByFingerprint.get(normalizedFingerprint)?.size ??
|
|
72
|
+
return ((this.passedScopeKeysByFingerprint.get(normalizedFingerprint)?.size ??
|
|
73
|
+
0) > 0);
|
|
73
74
|
}
|
|
74
75
|
// implements REQ-opencode-worktree-hard-enforcement-v1
|
|
75
76
|
async runCheckpoint(context, fingerprint) {
|
|
@@ -193,7 +194,9 @@ export class KibiCheckpointRunner {
|
|
|
193
194
|
const policy = computeEnforcementPolicy({
|
|
194
195
|
resolvedContext: context.workContext,
|
|
195
196
|
effectiveMode: "hard",
|
|
196
|
-
lifecycleEvents: context.lifecycleEvents ?? [
|
|
197
|
+
lifecycleEvents: context.lifecycleEvents ?? [
|
|
198
|
+
defaultLifecycleEvent(context),
|
|
199
|
+
],
|
|
197
200
|
pathKinds: context.pathKinds ?? ["code"],
|
|
198
201
|
linkedEntityResults: context.linkedEntityResults ?? [
|
|
199
202
|
{ ids: [], source: "none" },
|
|
@@ -73,6 +73,7 @@ const TEST_CUES = [
|
|
|
73
73
|
* Analyze a comment or prose block and suggest most appropriate entity type.
|
|
74
74
|
*/
|
|
75
75
|
export function classifyKnowledge(text) {
|
|
76
|
+
// implements REQ-opencode-kibi-plugin-v1
|
|
76
77
|
if (!text || text.trim().length < 50) {
|
|
77
78
|
return null;
|
|
78
79
|
}
|
|
@@ -94,7 +95,7 @@ export function classifyKnowledge(text) {
|
|
|
94
95
|
bestMatch = {
|
|
95
96
|
type: "fact",
|
|
96
97
|
confidence: factScore >= 3 ? "high" : "medium",
|
|
97
|
-
reasoning:
|
|
98
|
+
reasoning: "Contains strict domain fact cues (invariants, properties, limits, cardinalities) for the strict fact lane",
|
|
98
99
|
};
|
|
99
100
|
}
|
|
100
101
|
if (reqScore > maxMatches) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { PathKind } from "./path-kind.js";
|
|
2
1
|
import type { FileLifecycle } from "./file-operation-state.js";
|
|
2
|
+
import type { PathKind } from "./path-kind.js";
|
|
3
3
|
import type { RiskClass } from "./risk-classifier.js";
|
|
4
4
|
/**
|
|
5
5
|
* Classification for whether a file change requires KB freshness evidence.
|
|
@@ -51,8 +51,7 @@ function isIgnoredPath(normalizedPath, pathKind) {
|
|
|
51
51
|
// Special handling for .kb/ — only ignored when pathKind is NOT "kb".
|
|
52
52
|
// Actual KB entity files (pathKind=kb) should still require evidence.
|
|
53
53
|
if (pathKind !== "kb") {
|
|
54
|
-
if (normalizedPath.startsWith(".kb/") ||
|
|
55
|
-
normalizedPath.includes("/.kb/")) {
|
|
54
|
+
if (normalizedPath.startsWith(".kb/") || normalizedPath.includes("/.kb/")) {
|
|
56
55
|
return true;
|
|
57
56
|
}
|
|
58
57
|
}
|
package/dist/plugin-startup.js
CHANGED
|
@@ -20,7 +20,6 @@ function isSmartEnforcementSyncReason(reason) {
|
|
|
20
20
|
}
|
|
21
21
|
const workspaceCacheState = new Map();
|
|
22
22
|
export function resolveCurrentBranch(cwd) {
|
|
23
|
-
// implements REQ-opencode-kibi-briefing-v3
|
|
24
23
|
// 1. Check KIBI_BRANCH env var first (highest precedence)
|
|
25
24
|
const envBranch = process.env.KIBI_BRANCH?.trim();
|
|
26
25
|
if (envBranch && envBranch.length > 0) {
|