kibi-cursor 0.2.2 → 0.3.1

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kibi-cursor",
3
3
  "displayName": "Kibi",
4
- "version": "0.2.2",
4
+ "version": "0.3.1",
5
5
  "description": "Optional Cursor adapter for Kibi. Requires SWI-Prolog 9+ and project-local kibi-cli, kibi-mcp, and kibi-core before the bundled MCP server can start.",
6
6
  "license": "AGPL-3.0-or-later",
7
7
  "author": {
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # kibi-cursor
2
2
 
3
+ ## 0.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - f1db710: Kibi check outputs now have a stable advisory diagnostics lane for auditability review signals. Operators and MCP clients can receive `qualityDiagnostics` alongside hard `violations` without advisory-only findings changing pass/fail counts or exit behavior. Existing staged impact failures, including symbol granularity violations, remain blocking. Source impact analysis now also highlights overly broad symbols, indistinguishable symbol coordinates, and mixed-purpose component/class ownership as review-only guidance.
8
+
9
+ Technical summary:
10
+
11
+ - Add the public `QualityDiagnostic` type with `error`, `warning`, `review`, and `info` severities plus explicit `blocking` semantics.
12
+ - Preserve existing `violations`, `diagnostics`, and `impactDiagnostics` fields while adding MCP structured `qualityDiagnostics` output support.
13
+ - Preserve explicitly filtered MCP `kb_check` rule semantics so advisory full-KB quality scans only run for unfiltered checks or requested impact diagnostics.
14
+ - Clarify Codex and Cursor bundled agent guidance so targeted checks use explicit rules and final checks omit rules for full-KB `qualityDiagnostics` review.
15
+ - Add quality diagnostic text formatting and shared blocking helpers that treat `blocking: true` or `severity: "error"` as hard failures.
16
+ - Add non-blocking `multi_requirement_symbol_review`, `duplicate_symbol_coordinate_review`, and `component_mixed_purpose_review` impact diagnostics.
17
+
18
+ ## 0.3.0
19
+
20
+ ### Minor Changes
21
+
22
+ - Kibi now gives agents source-impact feedback while they are still editing, instead of waiting for the commit hook to be the first signal. Meaningful source edits can be checked through MCP with changed-file impact diagnostics, so agents see coarse symbol ownership, stale symbol evidence, and semantic-review prompts while the source context is fresh. OpenCode, Cursor, and Codex adapters now steer agents toward that MCP-first workflow and keep CLI/hooks as the later safety net.
23
+
24
+ Technical summary:
25
+
26
+ - Add reusable CLI changed-file impact diagnostics and export them for MCP consumption.
27
+ - Extend MCP `kb_check` with source-file impact options and structured impact output.
28
+ - Update OpenCode, Cursor, and Codex guidance/hooks to request impact-enabled `kb_check` after source edits.
29
+ - Document semantic-review diagnostics and class-member granularity expectations.
30
+
3
31
  ## 0.2.2
4
32
 
5
33
  ### Patch Changes
package/README.md CHANGED
@@ -96,22 +96,22 @@ Hooks are warning-only and never replace MCP/CLI behavior:
96
96
  - **sessionStart**: bootstrap reminder when `.kb/config.json` is missing.
97
97
  - **preToolUse**: warns on explicit direct `.kb/**` edits without blocking.
98
98
  - **beforeReadFile** and **postToolUse (Read)**: inject source-linked lookup guidance once per path per session.
99
- - **postToolUse (Write/Edit)**: inject traceability and freshness guidance once per path per session.
100
- - **stop**: emits a single freshness follow-up when meaningful paths changed during the session.
99
+ - **postToolUse (Write/Edit)**: inject traceability and freshness guidance once per path per session, including `kb_check({sourceFiles:[...], includeImpactDiagnostics:true, includeWorkingTreeDiff:true})` for meaningful source edits.
100
+ - **stop**: emits a single freshness or impact-check follow-up when meaningful paths changed during the session.
101
101
 
102
102
  ### What the plugin does not do
103
103
 
104
104
  Per the thin-adapter architecture, `kibi-cursor` does not:
105
105
 
106
106
  - Own KB storage, parsing, or validation
107
- - Run background `kibi sync` or `kibi check` (use git hooks and MCP tools)
107
+ - Run background `kibi sync` or CLI `kibi check` (use git hooks and MCP tools; for source edits, use impact-enabled MCP `kb_check` first)
108
108
  - Block agent actions in advisory mode
109
109
 
110
110
  ## Architecture
111
111
 
112
112
  `kibi-cursor` is a thin bridge layer:
113
113
 
114
- - **Agent-visible guidance**: public MCP tools (`kb_search`, `kb_query`, `kb_upsert`, `kb_check`, etc.) and the `/init-kibi` command
114
+ - **Agent-visible guidance**: public MCP tools (`kb_search`, `kb_query`, `kb_upsert`, impact-enabled `kb_check`, etc.) and the `/init-kibi` command
115
115
  - **Editor-specific value**: Cursor hooks for read/write reminders and session freshness follow-ups
116
116
  - **Foundation**: `kibi-core`, `kibi-cli`, and `kibi-mcp` remain required for project-local operations
117
117
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kibi-cursor",
3
3
  "displayName": "Kibi",
4
- "version": "0.2.2",
4
+ "version": "0.3.1",
5
5
  "description": "Optional Cursor adapter for Kibi. Requires SWI-Prolog 9+ and project-local kibi-cli, kibi-mcp, and kibi-core before the bundled MCP server can start.",
6
6
  "license": "AGPL-3.0-or-later",
7
7
  "author": {
package/dist/guidance.js CHANGED
@@ -31,6 +31,7 @@ export function writeGuidance(filePath, cwd, hasKibi) {
31
31
  }
32
32
  return [
33
33
  "Kibi write guidance: link production symbols to requirements.",
34
+ `After editing, run kb_check({sourceFiles:["${relativePath}"], includeImpactDiagnostics:true, includeWorkingTreeDiff:true}) for symbol granularity and semantic review of linked requirements/tests.`,
34
35
  `After editing, resolve freshness with kb_search/kb_query for sourceFile="${relativePath}".`,
35
36
  "Prefer symbol manifest + executable_for or // implements REQ-xxx for traceability.",
36
37
  ].join("\n");
@@ -6,7 +6,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
6
6
  import { readGuidance, writeGuidance } from "./guidance.js";
7
7
  import { parseHookInput, parseStdinJson, readStdin } from "./hook-input.js";
8
8
  import { addDirtyPaths, clearSessionHookState, hasGuidedPath, loadHookState, recordKbMcpTool, rememberGuidedPath, resolveStateDir, } from "./hook-state.js";
9
- import { extractKbMcpToolName } from "./kb-mcp-tools.js";
9
+ import { extractKbMcpToolCall } from "./kb-mcp-tools.js";
10
10
  import { BOOTSTRAP_REMINDER, DIRECT_KB_EDIT_WARNING, stopFollowupMessage, } from "./messages.js";
11
11
  import { extractExplicitPathFields, isDirectKbPath, isMeaningfulTrackedPath, toRepoRelativePath, } from "./path-policy.js";
12
12
  const editableTools = new Set([
@@ -86,9 +86,12 @@ export async function runHook(rawInput, environment = {}) {
86
86
  };
87
87
  }
88
88
  case "postToolUse": {
89
- const kbToolName = extractKbMcpToolName(input.toolName, input.toolInput);
90
- if (kbToolName) {
91
- recordKbMcpTool(stateDir, kbToolName);
89
+ const kbToolCall = extractKbMcpToolCall(input.toolName, input.toolInput);
90
+ if (kbToolCall) {
91
+ recordKbMcpTool(stateDir, kbToolCall.toolName, {
92
+ impactCheckRun: kbToolCall.impactCheckRun,
93
+ sourceFiles: kbToolCall.sourceFiles,
94
+ });
92
95
  }
93
96
  const explicitPaths = extractExplicitPathFields(input.toolInput);
94
97
  const dirtyPaths = explicitPaths
@@ -4,6 +4,8 @@ export type HookState = {
4
4
  guidedWritePaths: string[];
5
5
  kbMutationTools: string[];
6
6
  kbCheckRun: boolean;
7
+ impactCheckRun: boolean;
8
+ impactCheckedPaths: string[];
7
9
  };
8
10
  export declare function resolveStateDir(pluginData: string | undefined, conversationId: string | undefined): string | undefined;
9
11
  export declare function loadHookState(stateDir: string | undefined): HookState;
@@ -12,7 +14,10 @@ export declare function updateHookState(stateDir: string | undefined, updater: (
12
14
  export declare function addDirtyPaths(stateDir: string | undefined, dirtyPaths: readonly string[]): HookState;
13
15
  export declare function rememberGuidedPath(stateDir: string | undefined, kind: "read" | "write", guidedPath: string): HookState;
14
16
  export declare function hasGuidedPath(state: HookState, kind: "read" | "write", guidedPath: string): boolean;
15
- export declare function recordKbMcpTool(stateDir: string | undefined, toolName: string): HookState;
17
+ export declare function recordKbMcpTool(stateDir: string | undefined, toolName: string, options?: {
18
+ impactCheckRun?: boolean;
19
+ sourceFiles?: readonly string[];
20
+ }): HookState;
16
21
  export declare function clearSessionHookState(stateDir: string | undefined): HookState;
17
22
  /** @deprecated Use clearSessionHookState */
18
23
  export declare function clearDirtyPaths(stateDir: string | undefined): HookState;
@@ -44,6 +44,8 @@ function emptyHookState() {
44
44
  guidedWritePaths: [],
45
45
  kbMutationTools: [],
46
46
  kbCheckRun: false,
47
+ impactCheckRun: false,
48
+ impactCheckedPaths: [],
47
49
  };
48
50
  }
49
51
  function acquireLock(pluginData) {
@@ -129,12 +131,21 @@ function coerceHookState(value) {
129
131
  .filter((entry) => entry.length > 0)
130
132
  : [];
131
133
  const kbCheckRun = value.kbCheckRun === true;
134
+ const impactCheckRun = value.impactCheckRun === true;
135
+ const impactCheckedPaths = Array.isArray(value.impactCheckedPaths)
136
+ ? value.impactCheckedPaths
137
+ .filter((entry) => typeof entry === "string")
138
+ .map(normalizePath)
139
+ .filter((entry) => entry.length > 0)
140
+ : [];
132
141
  return {
133
142
  dirtyPaths: [...new Set(dirtyPaths)].slice(-maxDirtyPaths),
134
143
  guidedReadPaths: [...new Set(guidedReadPaths)].slice(-maxGuidedPaths),
135
144
  guidedWritePaths: [...new Set(guidedWritePaths)].slice(-maxGuidedPaths),
136
145
  kbMutationTools: [...new Set(kbMutationTools)].slice(-maxKbMutationTools),
137
146
  kbCheckRun,
147
+ impactCheckRun,
148
+ impactCheckedPaths: [...new Set(impactCheckedPaths)].slice(-maxGuidedPaths),
138
149
  };
139
150
  }
140
151
  export function resolveStateDir(pluginData, conversationId) {
@@ -219,14 +230,21 @@ export function hasGuidedPath(state, kind, guidedPath) {
219
230
  const bucket = kind === "read" ? state.guidedReadPaths : state.guidedWritePaths;
220
231
  return bucket.includes(normalized);
221
232
  }
222
- export function recordKbMcpTool(stateDir, toolName) {
233
+ export function recordKbMcpTool(stateDir, toolName, options = {}) {
223
234
  const normalized = toolName.trim();
224
235
  if (normalized.length === 0) {
225
236
  return loadHookState(stateDir);
226
237
  }
227
238
  return updateHookState(stateDir, (state) => {
228
239
  if (normalized === "kb_check") {
229
- return { ...state, kbCheckRun: true };
240
+ return {
241
+ ...state,
242
+ kbCheckRun: true,
243
+ impactCheckRun: state.impactCheckRun || options.impactCheckRun === true,
244
+ impactCheckedPaths: options.impactCheckRun === true
245
+ ? mergeStringPaths(state.impactCheckedPaths, options.sourceFiles ?? [])
246
+ : state.impactCheckedPaths,
247
+ };
230
248
  }
231
249
  if (normalized === "kb_upsert" || normalized === "kb_delete") {
232
250
  return {
@@ -1 +1,7 @@
1
+ export type KbMcpToolCall = {
2
+ toolName: string;
3
+ impactCheckRun: boolean;
4
+ sourceFiles: string[];
5
+ };
6
+ export declare function extractKbMcpToolCall(toolName: string | undefined, toolInput: unknown): KbMcpToolCall | undefined;
1
7
  export declare function extractKbMcpToolName(toolName: string | undefined, toolInput: unknown): string | undefined;
@@ -11,7 +11,95 @@ function readString(record, keys) {
11
11
  }
12
12
  return undefined;
13
13
  }
14
+ function readBoolean(record, keys) {
15
+ for (const key of keys) {
16
+ const value = record[key];
17
+ if (typeof value === "boolean") {
18
+ return value;
19
+ }
20
+ }
21
+ return undefined;
22
+ }
23
+ function readStringArray(record, keys) {
24
+ for (const key of keys) {
25
+ const value = record[key];
26
+ if (!Array.isArray(value)) {
27
+ continue;
28
+ }
29
+ return value.filter((item) => typeof item === "string" && item.length > 0);
30
+ }
31
+ return [];
32
+ }
33
+ function readRecord(record, keys) {
34
+ for (const key of keys) {
35
+ const value = record[key];
36
+ if (isRecord(value)) {
37
+ return value;
38
+ }
39
+ }
40
+ return undefined;
41
+ }
42
+ export function extractKbMcpToolCall(toolName, toolInput) {
43
+ const directToolName = toolName?.trim();
44
+ let normalizedToolName = directToolName?.startsWith("kb_")
45
+ ? directToolName
46
+ : undefined;
47
+ if (isRecord(toolInput)) {
48
+ normalizedToolName ??= readString(toolInput, [
49
+ "toolName",
50
+ "tool_name",
51
+ "name",
52
+ ]);
53
+ const args = readRecord(toolInput, ["arguments", "args"]);
54
+ const payload = args ?? toolInput;
55
+ const includeImpactDiagnostics = readBoolean(payload, [
56
+ "includeImpactDiagnostics",
57
+ "include_impact_diagnostics",
58
+ ]);
59
+ const includeWorkingTreeDiff = readBoolean(payload, [
60
+ "includeWorkingTreeDiff",
61
+ "include_working_tree_diff",
62
+ ]);
63
+ const sourceFiles = readStringArray(payload, [
64
+ "sourceFiles",
65
+ "source_files",
66
+ ]);
67
+ if (normalizedToolName?.startsWith("kb_")) {
68
+ return {
69
+ toolName: normalizedToolName,
70
+ impactCheckRun: normalizedToolName === "kb_check" &&
71
+ includeImpactDiagnostics === true &&
72
+ includeWorkingTreeDiff === true &&
73
+ sourceFiles.length > 0,
74
+ sourceFiles,
75
+ };
76
+ }
77
+ const nestedArgs = toolInput.arguments ?? toolInput.args;
78
+ if (isRecord(nestedArgs)) {
79
+ const nestedTool = readString(nestedArgs, [
80
+ "toolName",
81
+ "tool_name",
82
+ "name",
83
+ ]);
84
+ if (nestedTool?.startsWith("kb_")) {
85
+ return { toolName: nestedTool, impactCheckRun: false, sourceFiles: [] };
86
+ }
87
+ }
88
+ }
89
+ if (normalizedToolName?.startsWith("kb_")) {
90
+ return {
91
+ toolName: normalizedToolName,
92
+ impactCheckRun: false,
93
+ sourceFiles: [],
94
+ };
95
+ }
96
+ return undefined;
97
+ }
14
98
  export function extractKbMcpToolName(toolName, toolInput) {
99
+ const toolCall = extractKbMcpToolCall(toolName, toolInput);
100
+ if (toolCall) {
101
+ return toolCall.toolName;
102
+ }
15
103
  if (toolName) {
16
104
  const normalized = toolName.trim();
17
105
  if (normalized.startsWith("kb_")) {
package/dist/messages.js CHANGED
@@ -1,4 +1,4 @@
1
- import { isKbFreshnessRelevantPath } from "./path-policy.js";
1
+ import { isKbFreshnessRelevantPath, isSourceImpactRelevantPath, } from "./path-policy.js";
2
2
  export const BOOTSTRAP_REMINDER = "Kibi config was not found at the Cursor workspace root. Use the Kibi MCP /init-kibi workflow to bootstrap project memory before relying on KB lookups; do not edit .kb/ files directly.";
3
3
  export const DIRECT_KB_EDIT_WARNING = "Avoid direct edits to .kb/. Use Kibi MCP tools for KB discovery and mutations so project memory stays valid.";
4
4
  export function stopFollowupMessage(state) {
@@ -6,6 +6,14 @@ export function stopFollowupMessage(state) {
6
6
  const tools = [...new Set(state.kbMutationTools)];
7
7
  return `Kibi KB updated (${tools.join(", ")}).`;
8
8
  }
9
+ const sourceImpactPaths = state.dirtyPaths.filter(isSourceImpactRelevantPath);
10
+ const uncheckedSourcePaths = sourceImpactPaths.filter((sourcePath) => !state.impactCheckedPaths.includes(sourcePath));
11
+ if (uncheckedSourcePaths.length > 0 && !state.impactCheckRun) {
12
+ return impactCheckFollowup(uncheckedSourcePaths);
13
+ }
14
+ if (uncheckedSourcePaths.length > 0) {
15
+ return impactCheckFollowup(uncheckedSourcePaths);
16
+ }
9
17
  const freshnessPaths = state.dirtyPaths.filter(isKbFreshnessRelevantPath);
10
18
  if (freshnessPaths.length === 0 || state.kbCheckRun) {
11
19
  return undefined;
@@ -14,6 +22,16 @@ export function stopFollowupMessage(state) {
14
22
  const noun = fileCount === 1 ? "file" : "files";
15
23
  return `Kibi: sync or record no-impact after ${fileCount} edited ${noun}.`;
16
24
  }
25
+ function impactCheckFollowup(sourcePaths) {
26
+ const fileCount = sourcePaths.length;
27
+ const noun = fileCount === 1 ? "file" : "files";
28
+ const sourceFiles = JSON.stringify(sourcePaths.slice(0, 10));
29
+ return [
30
+ `Kibi: run impact-enabled kb_check after ${fileCount} edited source ${noun}.`,
31
+ `Use kb_check({sourceFiles:${sourceFiles}, includeImpactDiagnostics:true, includeWorkingTreeDiff:true}).`,
32
+ "Review symbol granularity and semantic review of linked requirements/tests before stopping.",
33
+ ].join("\n");
34
+ }
17
35
  /** @deprecated Use stopFollowupMessage */
18
36
  export function freshnessReminder(dirtyPaths) {
19
37
  const fileCount = dirtyPaths.length;
@@ -3,5 +3,6 @@ export declare function isDirectKbPath(candidate: string): boolean;
3
3
  export declare function isMeaningfulTrackedPath(candidate: string): boolean;
4
4
  /** Paths whose edits should trigger a KB freshness stop follow-up. */
5
5
  export declare function isKbFreshnessRelevantPath(candidate: string): boolean;
6
+ export declare function isSourceImpactRelevantPath(candidate: string): boolean;
6
7
  export declare function isDocumentationTrackedPath(candidate: string): boolean;
7
8
  export declare function toRepoRelativePath(candidate: string, cwd: string | undefined): string;
@@ -29,6 +29,7 @@ const sourceExtensions = new Set([
29
29
  ".mjs",
30
30
  ".mts",
31
31
  ".php",
32
+ ".pl",
32
33
  ".py",
33
34
  ".rb",
34
35
  ".rs",
@@ -122,6 +123,23 @@ export function isKbFreshnessRelevantPath(candidate) {
122
123
  segments[1] === "core" &&
123
124
  segments[2] === "src");
124
125
  }
126
+ export function isSourceImpactRelevantPath(candidate) {
127
+ const normalized = normalizePath(candidate);
128
+ const segments = pathSegments(normalized);
129
+ if (segments.includes(".kb") ||
130
+ segments.includes("dist") ||
131
+ segments.includes("tests") ||
132
+ segments.includes("test") ||
133
+ segments.includes("docs") ||
134
+ segments.includes("documentation")) {
135
+ return false;
136
+ }
137
+ const basename = segments.at(-1) ?? "";
138
+ const extension = basename.includes(".")
139
+ ? `.${basename.split(".").at(-1) ?? ""}`
140
+ : "";
141
+ return segments.includes("src") && sourceExtensions.has(extension);
142
+ }
125
143
  export function isDocumentationTrackedPath(candidate) {
126
144
  const normalized = normalizePath(candidate);
127
145
  const segments = pathSegments(normalized);
@@ -7,6 +7,8 @@ alwaysApply: false
7
7
 
8
8
  Before changing production code, discover linked requirements with `kb_search` and `kb_query(sourceFile=...)`.
9
9
 
10
+ After meaningful source edits, run `kb_check({sourceFiles:[...], includeImpactDiagnostics:true, includeWorkingTreeDiff:true})` while the edit context is fresh. Review symbol granularity and whether linked requirements, scenarios, and tests still cover the changed behavior or UI copy.
11
+
10
12
  Preserve the canonical chain `REQ-* -> SCEN-* -> TEST-*` when modeling behavior.
11
13
 
12
14
  Prefer symbol manifest + `executable_for` for test/e2e code. Inline `// implements REQ-xxx` remains acceptable for quick code-only changes.
@@ -10,12 +10,14 @@ Validate and strengthen traceability before and after code changes.
10
10
  ## MCP workflow
11
11
 
12
12
  - Locate requirements with `kb_search` and inspect exact details with `kb_query`.
13
+ - After meaningful source edits, run `kb_check({sourceFiles:[...], includeImpactDiagnostics:true, includeWorkingTreeDiff:true})` before deciding whether traceability is current.
13
14
  - Apply updates with `kb_upsert` for requirements, scenarios, tests, or facts.
14
15
  - Validate constraints and consistency with `kb_check`.
15
16
 
16
17
  ## Guidance
17
18
 
18
19
  - Prefer source-linked relationships so symbols and files can be traced back cleanly.
20
+ - Treat `symbol_semantic_review_needed` as a prompt to inspect linked requirements/tests; Kibi reports graph links but does not prove prose semantics.
19
21
  - Include `kb_query` and `kb_delete` only when explicit cleanups are required.
20
22
  - Never directly edit `.kb/**`; all modeling and cleanup goes through MCP tools.
21
23
  - Preserve the canonical chain `REQ-* -> SCEN-* -> TEST-*` when adding or changing requirements.
@@ -182,7 +182,9 @@ Never fire `kb_upsert` calls in parallel. Execute them sequentially to avoid loc
182
182
 
183
183
  ## Targeted and Final Checks
184
184
 
185
- Run `kb_check` with specific rules during iteration for fast feedback. For example, use `rules: ["required-fields", "no-dangling-refs"]` after small changes. Run a full `kb_check` without rule filters before declaring work complete.
185
+ Run `kb_check` with specific rules during iteration for fast feedback. For example, use `rules: ["required-fields", "no-dangling-refs"]` after small changes. Supplying `rules` preserves that scoped validation and skips the full-KB advisory scan. Run a full `kb_check` without rule filters before declaring work complete so `qualityDiagnostics[]` includes the full-KB audit-quality review.
186
+
187
+ For meaningful source edits, run impact diagnostics while the edit context is fresh: `kb_check({sourceFiles:["src/changed-file.ts"], includeImpactDiagnostics:true, includeWorkingTreeDiff:true})`. Review `symbol_granularity_violation` as a hard ownership-shape problem and `symbol_semantic_review_needed` as an advisory prompt to inspect whether linked requirements, scenarios, and tests still match the changed behavior or UI copy.
186
188
 
187
189
  ## Domain Contradictions and Evolution
188
190
 
@@ -203,7 +205,7 @@ Call `kb_status` when you suspect the branch KB is stale or when switching conte
203
205
  | Bug-as-flag | `flag` misused for defect tracking | Use `fact` with `fact_kind: observation` or `meta` |
204
206
  | Parallel upserts | Lock contention and nondeterminism | Execute `kb_upsert` calls sequentially |
205
207
  | Embedded scenarios in reqs | Violates canonical traceability chain | Create separate `req`, `scen`, and `test` entities |
206
- | Missing `kb_check` | Undetected dangling refs and violations | Run targeted checks during work, full check at completion |
208
+ | Missing `kb_check` | Undetected dangling refs, violations, and full-KB quality diagnostics | Run targeted checks during work, full unfiltered check at completion |
207
209
  | Tags as multi-ID lookup | Tags are metadata, not identifiers | Use `kb_query` with explicit `id` values |
208
210
  | `relates_to` for strict modeling | Loses contradiction safety | Use `constrains` and `requires_property` instead |
209
211
  | `status: implemented` on requirements | Not a valid lifecycle status | Use a valid status such as `closed`, add an `implemented` tag, and link evidence instead |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kibi-cursor",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "description": "Kibi Cursor plugin - thin adapter for Cursor MCP integration and editor hooks",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -7,6 +7,8 @@ alwaysApply: false
7
7
 
8
8
  Before changing production code, discover linked requirements with `kb_search` and `kb_query(sourceFile=...)`.
9
9
 
10
+ After meaningful source edits, run `kb_check({sourceFiles:[...], includeImpactDiagnostics:true, includeWorkingTreeDiff:true})` while the edit context is fresh. Review symbol granularity and whether linked requirements, scenarios, and tests still cover the changed behavior or UI copy.
11
+
10
12
  Preserve the canonical chain `REQ-* -> SCEN-* -> TEST-*` when modeling behavior.
11
13
 
12
14
  Prefer symbol manifest + `executable_for` for test/e2e code. Inline `// implements REQ-xxx` remains acceptable for quick code-only changes.
@@ -10,12 +10,14 @@ Validate and strengthen traceability before and after code changes.
10
10
  ## MCP workflow
11
11
 
12
12
  - Locate requirements with `kb_search` and inspect exact details with `kb_query`.
13
+ - After meaningful source edits, run `kb_check({sourceFiles:[...], includeImpactDiagnostics:true, includeWorkingTreeDiff:true})` before deciding whether traceability is current.
13
14
  - Apply updates with `kb_upsert` for requirements, scenarios, tests, or facts.
14
15
  - Validate constraints and consistency with `kb_check`.
15
16
 
16
17
  ## Guidance
17
18
 
18
19
  - Prefer source-linked relationships so symbols and files can be traced back cleanly.
20
+ - Treat `symbol_semantic_review_needed` as a prompt to inspect linked requirements/tests; Kibi reports graph links but does not prove prose semantics.
19
21
  - Include `kb_query` and `kb_delete` only when explicit cleanups are required.
20
22
  - Never directly edit `.kb/**`; all modeling and cleanup goes through MCP tools.
21
23
  - Preserve the canonical chain `REQ-* -> SCEN-* -> TEST-*` when adding or changing requirements.
@@ -182,7 +182,9 @@ Never fire `kb_upsert` calls in parallel. Execute them sequentially to avoid loc
182
182
 
183
183
  ## Targeted and Final Checks
184
184
 
185
- Run `kb_check` with specific rules during iteration for fast feedback. For example, use `rules: ["required-fields", "no-dangling-refs"]` after small changes. Run a full `kb_check` without rule filters before declaring work complete.
185
+ Run `kb_check` with specific rules during iteration for fast feedback. For example, use `rules: ["required-fields", "no-dangling-refs"]` after small changes. Supplying `rules` preserves that scoped validation and skips the full-KB advisory scan. Run a full `kb_check` without rule filters before declaring work complete so `qualityDiagnostics[]` includes the full-KB audit-quality review.
186
+
187
+ For meaningful source edits, run impact diagnostics while the edit context is fresh: `kb_check({sourceFiles:["src/changed-file.ts"], includeImpactDiagnostics:true, includeWorkingTreeDiff:true})`. Review `symbol_granularity_violation` as a hard ownership-shape problem and `symbol_semantic_review_needed` as an advisory prompt to inspect whether linked requirements, scenarios, and tests still match the changed behavior or UI copy.
186
188
 
187
189
  ## Domain Contradictions and Evolution
188
190
 
@@ -203,7 +205,7 @@ Call `kb_status` when you suspect the branch KB is stale or when switching conte
203
205
  | Bug-as-flag | `flag` misused for defect tracking | Use `fact` with `fact_kind: observation` or `meta` |
204
206
  | Parallel upserts | Lock contention and nondeterminism | Execute `kb_upsert` calls sequentially |
205
207
  | Embedded scenarios in reqs | Violates canonical traceability chain | Create separate `req`, `scen`, and `test` entities |
206
- | Missing `kb_check` | Undetected dangling refs and violations | Run targeted checks during work, full check at completion |
208
+ | Missing `kb_check` | Undetected dangling refs, violations, and full-KB quality diagnostics | Run targeted checks during work, full unfiltered check at completion |
207
209
  | Tags as multi-ID lookup | Tags are metadata, not identifiers | Use `kb_query` with explicit `id` values |
208
210
  | `relates_to` for strict modeling | Loses contradiction safety | Use `constrains` and `requires_property` instead |
209
211
  | `status: implemented` on requirements | Not a valid lifecycle status | Use a valid status such as `closed`, add an `implemented` tag, and link evidence instead |