kibi-cursor 2.0.0 → 2.1.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.
Files changed (41) hide show
  1. package/.cursor-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +84 -0
  3. package/README.md +1 -1
  4. package/agent-plugin/plugin.json +1 -1
  5. package/agent-plugin/skills/kibi-usage/SKILL.md +10 -3
  6. package/agent-plugin/skills/kibi-usage/resources/fact-lanes.md +4 -0
  7. package/agent-plugin/skills/kibi-usage/resources/proof.md +45 -0
  8. package/agent-plugin/skills/kibi-usage/resources/relationship-directions.md +35 -17
  9. package/agent-plugin/skills/kibi-usage/resources/source-authoring.md +36 -0
  10. package/agent-plugin/skills/kibi-usage/resources/workflows.md +52 -1
  11. package/bin/launch-kibi-mcp.mjs +8 -1
  12. package/dist/.cursor-plugin/plugin.json +1 -1
  13. package/dist/bin/launch-kibi-mcp.mjs +8 -1
  14. package/dist/guidance.d.ts +11 -0
  15. package/dist/guidance.js +39 -5
  16. package/dist/hook-input.js +7 -4
  17. package/dist/hook-runner.js +36 -6
  18. package/dist/hook-state-storage.js +55 -2
  19. package/dist/hook-state.d.ts +4 -2
  20. package/dist/hook-state.js +30 -7
  21. package/dist/kb-mcp-tools.d.ts +5 -7
  22. package/dist/kb-mcp-tools.js +6 -126
  23. package/dist/messages.js +3 -8
  24. package/dist/path-policy.js +17 -177
  25. package/dist/skills/.canon-hash.json +6 -6
  26. package/dist/skills/kibi-usage/SKILL.md +10 -3
  27. package/dist/skills/kibi-usage/resources/fact-lanes.md +4 -0
  28. package/dist/skills/kibi-usage/resources/proof.md +45 -0
  29. package/dist/skills/kibi-usage/resources/relationship-directions.md +35 -17
  30. package/dist/skills/kibi-usage/resources/source-authoring.md +36 -0
  31. package/dist/skills/kibi-usage/resources/workflows.md +52 -1
  32. package/dist/source-linked-requirements.d.ts +16 -0
  33. package/dist/source-linked-requirements.js +55 -0
  34. package/package.json +4 -1
  35. package/skills/.canon-hash.json +6 -6
  36. package/skills/kibi-usage/SKILL.md +10 -3
  37. package/skills/kibi-usage/resources/fact-lanes.md +4 -0
  38. package/skills/kibi-usage/resources/proof.md +45 -0
  39. package/skills/kibi-usage/resources/relationship-directions.md +35 -17
  40. package/skills/kibi-usage/resources/source-authoring.md +36 -0
  41. package/skills/kibi-usage/resources/workflows.md +52 -1
@@ -1,3 +1,5 @@
1
+ // implements REQ-cursor-kibi-plugin-v1
2
+ import { extractExplicitPathFields as extractSharedExplicitPathFields, isKbPath, isDocumentationTrackedPath as isSharedDocumentationTrackedPath, isMeaningfulTrackedPath as isSharedMeaningfulTrackedPath, isSourceImpactRelevantPath as isSharedSourceImpactRelevantPath, normalizeWorkspacePath, } from "kibi-agent-core/path-policy";
1
3
  export function isFreshnessLane(lane) {
2
4
  return (lane === "requirements" ||
3
5
  lane === "scenarios" ||
@@ -9,200 +11,38 @@ export function isFreshnessLane(lane) {
9
11
  lane === "symbols.yaml" ||
10
12
  lane === "symbol-coordinates.yaml");
11
13
  }
12
- // implements REQ-cursor-kibi-plugin-v1
13
- const explicitPathKeys = new Set([
14
- "absolute_path",
15
- "file",
16
- "file_path",
17
- "filepath",
18
- "new_path",
19
- "old_path",
20
- "path",
21
- "paths",
22
- "relative_path",
23
- "target_path",
24
- ]);
25
- const sourceExtensions = new Set([
26
- ".c",
27
- ".cc",
28
- ".cpp",
29
- ".cs",
30
- ".css",
31
- ".go",
32
- ".h",
33
- ".hpp",
34
- ".html",
35
- ".java",
36
- ".js",
37
- ".jsx",
38
- ".kt",
39
- ".lua",
40
- ".mjs",
41
- ".mts",
42
- ".php",
43
- ".pl",
44
- ".py",
45
- ".rb",
46
- ".rs",
47
- ".scala",
48
- ".sh",
49
- ".swift",
50
- ".ts",
51
- ".tsx",
52
- ".vue",
53
- ]);
54
- const documentationExtensions = new Set([".md", ".mdx", ".rst", ".txt"]);
55
- const CANONICAL_KB_KNOWLEDGE_LANES = new Set([
56
- "requirements",
57
- "scenarios",
58
- "tests",
59
- "facts",
60
- "adr",
61
- "flags",
62
- "events",
63
- ]);
64
- const CANONICAL_KB_KNOWLEDGE_FILES = new Set([
65
- "symbols.yaml",
66
- "symbol-coordinates.yaml",
67
- ]);
68
- function isCanonicalKbKnowledgePath(segments) {
69
- if (segments[0] !== ".kb") {
70
- return false;
71
- }
72
- const lane = segments[1];
73
- if (lane === undefined) {
74
- return false;
75
- }
76
- return (CANONICAL_KB_KNOWLEDGE_FILES.has(lane) ||
77
- CANONICAL_KB_KNOWLEDGE_LANES.has(lane));
78
- }
79
- function isRecord(value) {
80
- return typeof value === "object" && value !== null && !Array.isArray(value);
81
- }
82
- function normalizePath(candidate) {
83
- return candidate.trim().replaceAll("\\", "/");
84
- }
85
- function pathSegments(candidate) {
86
- return normalizePath(candidate).split("/").filter(Boolean);
87
- }
88
- function collectPathValues(value, output) {
89
- if (typeof value === "string") {
90
- const normalized = normalizePath(value);
91
- if (normalized.length > 0) {
92
- output.push(normalized);
93
- }
94
- return;
95
- }
96
- if (!Array.isArray(value)) {
97
- return;
98
- }
99
- for (const item of value) {
100
- collectPathValues(item, output);
101
- }
102
- }
103
- function visitExplicitPathFields(value, output) {
104
- if (Array.isArray(value)) {
105
- for (const item of value) {
106
- visitExplicitPathFields(item, output);
107
- }
108
- return;
109
- }
110
- if (!isRecord(value)) {
111
- return;
112
- }
113
- for (const [key, child] of Object.entries(value)) {
114
- if (explicitPathKeys.has(key.toLowerCase())) {
115
- collectPathValues(child, output);
116
- }
117
- visitExplicitPathFields(child, output);
118
- }
119
- }
120
14
  export function extractExplicitPathFields(input) {
121
- const paths = [];
122
- visitExplicitPathFields(input, paths);
123
- return [...new Set(paths)];
15
+ return extractSharedExplicitPathFields(input);
124
16
  }
125
17
  export function isDirectKbPath(candidate) {
126
- return pathSegments(candidate).includes(".kb");
18
+ return isKbPath(candidate);
127
19
  }
128
20
  export function isMeaningfulTrackedPath(candidate) {
129
- const normalized = normalizePath(candidate);
130
- const segments = pathSegments(normalized);
131
- if (segments.includes("dist")) {
132
- return false;
133
- }
134
- if (segments.includes(".kb")) {
135
- return isCanonicalKbKnowledgePath(segments);
136
- }
137
- const basename = segments.at(-1) ?? "";
138
- const extension = basename.includes(".")
139
- ? `.${basename.split(".").at(-1) ?? ""}`
140
- : "";
141
- if (segments.includes("docs") || segments.includes("documentation")) {
142
- return documentationExtensions.has(extension);
143
- }
144
- if (basename === "README.md") {
145
- return true;
146
- }
147
- if (segments.includes("src") ||
148
- segments.includes("tests") ||
149
- segments.includes("test")) {
150
- return (sourceExtensions.has(extension) || documentationExtensions.has(extension));
151
- }
152
- return false;
21
+ return isSharedMeaningfulTrackedPath(candidate);
153
22
  }
154
23
  /** Paths whose edits should trigger a KB freshness stop follow-up. */
155
24
  export function isKbFreshnessRelevantPath(candidate) {
156
- const segments = pathSegments(normalizePath(candidate));
157
- if (segments[0] === ".kb") {
158
- const lane = segments[1];
159
- if (isFreshnessLane(lane))
160
- return true;
161
- }
162
- // Legacy layout during migration
163
- if (segments.includes("documentation")) {
25
+ const segments = normalizeWorkspacePath(candidate).split("/").filter(Boolean);
26
+ if (segments[0] === ".kb" && isFreshnessLane(segments[1]))
27
+ return true;
28
+ if (segments.includes("documentation"))
164
29
  return true;
165
- }
166
30
  return (segments[0] === "packages" &&
167
31
  segments[1] === "core" &&
168
32
  segments[2] === "src");
169
33
  }
170
34
  export function isSourceImpactRelevantPath(candidate) {
171
- const normalized = normalizePath(candidate);
172
- const segments = pathSegments(normalized);
173
- if (segments.includes(".kb") ||
174
- segments.includes("dist") ||
175
- segments.includes("tests") ||
176
- segments.includes("test") ||
177
- segments.includes("docs") ||
178
- segments.includes("documentation")) {
179
- return false;
180
- }
181
- const basename = segments.at(-1) ?? "";
182
- const extension = basename.includes(".")
183
- ? `.${basename.split(".").at(-1) ?? ""}`
184
- : "";
185
- return segments.includes("src") && sourceExtensions.has(extension);
35
+ return isSharedSourceImpactRelevantPath(candidate);
186
36
  }
187
37
  export function isDocumentationTrackedPath(candidate) {
188
- const normalized = normalizePath(candidate);
189
- const segments = pathSegments(normalized);
190
- const basename = segments.at(-1) ?? "";
191
- const extension = basename.includes(".")
192
- ? `.${basename.split(".").at(-1) ?? ""}`
193
- : "";
194
- return (segments.includes("docs") ||
195
- segments.includes("documentation") ||
196
- documentationExtensions.has(extension));
38
+ return isSharedDocumentationTrackedPath(candidate);
197
39
  }
198
40
  export function toRepoRelativePath(candidate, cwd) {
199
- const normalized = normalizePath(candidate);
200
- if (!cwd) {
41
+ const normalized = normalizeWorkspacePath(candidate);
42
+ if (!cwd)
201
43
  return normalized;
202
- }
203
- const cwdPrefix = `${normalizePath(cwd)}/`;
204
- if (normalized.startsWith(cwdPrefix)) {
205
- return normalized.slice(cwdPrefix.length);
206
- }
207
- return normalized;
44
+ const cwdPrefix = `${normalizeWorkspacePath(cwd)}/`;
45
+ return normalized.startsWith(cwdPrefix)
46
+ ? normalized.slice(cwdPrefix.length)
47
+ : normalized;
208
48
  }
@@ -13,15 +13,15 @@
13
13
  "kibi-traceability/resources/operation-access.md": "39f7972ab7f4ae7479e78f7072bb50e8e6c4cdf4f857425f69d2522d37db437c",
14
14
  "kibi-traceability/resources/source-authoring.md": "408c6ee2bef1b84e0194c0538ef929c26a0a617e631b2234247388140dbbdd08",
15
15
  "kibi-traceability/resources/traceability.md": "38c290a0bc71bd1692e115f22694743946e2f69630e134acfd43cee5f613fb88",
16
- "kibi-usage/SKILL.md": "47a76e74fa1439e3745afe4c883b9cb1383df7696b1a0d695c02fe4e34e3205d",
16
+ "kibi-usage/SKILL.md": "83567f8ead944457719e0254ad6bc1dbedda3a70d04266d2ff041a670336dcc6",
17
17
  "kibi-usage/resources/branch-lifecycle.md": "f1bf359e9826e83c548f3cd0287f8175a62456527b0132b06b3f9f74aa59b7d6",
18
- "kibi-usage/resources/fact-lanes.md": "41b28023a57593009867ea0ebc8e9f3f05c3bd837144772d12844423f922e763",
18
+ "kibi-usage/resources/fact-lanes.md": "7ac928cc6b3d189eee6a9cda282918677d5a222cd7ba9b7f324e6553cd3adce8",
19
19
  "kibi-usage/resources/kb-improvement.md": "17e8b6cf6a0dd43b443a2bfd92e7205d099647a5f1c75fe85413a6cea63d86c6",
20
20
  "kibi-usage/resources/logic-ir.md": "151675d0ffa813cb9e271084102a3af42de369b8f9a0c64866af0cdc4d924063",
21
21
  "kibi-usage/resources/operation-access.md": "e8b4a3676892d2f7e2cfd708ec4ad1f41b6f296e1eb3a5ecc047f43322b4a92a",
22
- "kibi-usage/resources/proof.md": "e1a44ea4bf342afebb0aaa7800221067a511f6607c687ac38db6392b7e3d9f9a",
23
- "kibi-usage/resources/relationship-directions.md": "a357072d3370db9b7d80e505795f952909a68778cc18b1d089970de91e4fda46",
24
- "kibi-usage/resources/source-authoring.md": "ac4f1a9b5785462f8c3530bdcdb82ad9a0ee1f4049454ae28bf4df09ff267ebd",
22
+ "kibi-usage/resources/proof.md": "7391046fbdeece4858b668360c60755f184af6dfedda9dbc67e2fa4574dbce7f",
23
+ "kibi-usage/resources/relationship-directions.md": "0fdd67032c2d15299f772845fc4f807eb9435b09507bd87a5911ab33db2f143d",
24
+ "kibi-usage/resources/source-authoring.md": "80978cea0614484292c7a70d511a3f50458f48ef976bf0675b8bb96abe9d3d36",
25
25
  "kibi-usage/resources/ui-requirements.md": "b7c31ab1affa3ab25ae5242d8fd8c4d546532d1cafc65d84088375317c1682cc",
26
- "kibi-usage/resources/workflows.md": "776b97a794325e7012a230d2b9fc32fc89b2a51df45dfd8498cad49170bdc43d"
26
+ "kibi-usage/resources/workflows.md": "52cadc2b1e41af7d0c3129b721d81bb542fefb97113ba3a7c817f7ab7a1f787e"
27
27
  }
@@ -2,7 +2,7 @@
2
2
  id: kibi-usage
3
3
  name: Kibi Usage
4
4
  description: Use Kibi's source-first, exact-Git, migration-aware, proof-aware operations safely across MCP or the trusted local CLI, including partial completion repair.
5
- version: 2.1.2
5
+ version: 2.2.0
6
6
  kibiCompatibility: ">=1.0.0"
7
7
  tags:
8
8
  - kibi
@@ -59,7 +59,11 @@ mutability, and Prolog requirements of each operation.
59
59
  ## Safe workflow
60
60
 
61
61
  1. Always discover before you mutate: start with `kb_search`, then exact-filter with `kb_query`. Use
62
- `kb_status` when branch or freshness confidence matters.
62
+ `kb_status` when branch or freshness confidence matters. `kb_search` ranks
63
+ lexically unless you pass `rankingMode: "intent-v1"`, `semanticFacets`, or
64
+ `sourceLocations`; use intent mode with grounded facets for conceptual
65
+ questions and before changing a source file, and keep lexical search for
66
+ literal identifiers. See `resources/workflows.md` for the mode recipe.
63
67
  2. Resolve genuine ambiguity with the human; use semantic advisor/modeling
64
68
  operations for deterministic interpretation and typed facts.
65
69
  3. Create endpoints before relationships and upsert small batches sequentially.
@@ -133,6 +137,9 @@ safe normative claims; use `observation` or `meta` for bug/workaround notes and
133
137
  tests, symbol ownership, and fresh proof-bearing receipts before claiming proof.
134
138
  For an existing product KB that needs semantic backfill, read
135
139
  `resources/kb-improvement.md`, and `resources/proof.md` for the proof workflow.
140
+ When a proof ratchet fails, follow Debugging proof regressions in
141
+ `resources/proof.md`: use `kibi proof explain` and compare current proof state
142
+ to committed `proof/baseline.json` with `kibi proof impact`.
136
143
 
137
144
  ## Predicate Ontology Decision Tree
138
145
 
@@ -157,7 +164,7 @@ Represent implementation ownership with a `symbol` entity that has
157
164
  `sourceFile`, `implements` to the requirement, and `covered_by` to the test.
158
165
  Prolog `symbol-coverage` also requires the test to `validates` the requirement
159
166
  (or the requirement `verified_by` the test). `covered_by` alone is not
160
- enough. Do not rely on legacy `// implements REQ-xxx` comments as the
167
+ enough. Do not rely on legacy `// implements REQ-<area>-<behavior>` comments as the
161
168
  traceability record.
162
169
 
163
170
  ## Complete Logical Coverage
@@ -55,6 +55,10 @@ relationship: { type: requires_predicate, from: REQ-EDITOR-DRAFT-AUTOSAVE, to: F
55
55
 
56
56
  The project-local schema endpoint must exist before this fact is linked. When ontology extension is explicitly authorized, define it first with `fact_kind: predicate_schema`, `predicate_name`, `predicate_arity`, and equally sized `argument_names` and `argument_types`. Without an authorized stable signature, record `review:ontology-gap` instead of inventing a schema.
57
57
 
58
+ ### Closed argument vocabularies
59
+
60
+ A schema can close an argument with `argument_constants` (allowed values keyed by argument name) and map older spellings with `argument_aliases`. Reuse a declared constant; `kb_upsert` rejects any other value and names the constant to use for an alias. When a genuinely new value is needed, extend `argument_constants` on the schema first. To converge existing facts, declare aliases for their spellings and let `kibi migrate` rewrite them (`predicate_schema_alignment` actions). Close only arguments with a natural shared vocabulary, such as the governed component or a severity; forcing distinct obligations into a few constants makes different requirements share one ground term.
61
+
58
62
  ### Deny predicate
59
63
 
60
64
  Claim: “Suspended users must not publish articles.” When `permission_rule` fits, preserve its positive schema name and encode prohibition as polarity:
@@ -103,3 +103,48 @@ re-run `kibi prove` for the affected selection, then confirm `kb_status` and
103
103
  `kb_coverage` before handoff.
104
104
 
105
105
  Full reference: `docs/proving-requirements.md`.
106
+
107
+ ## Debugging proof regressions
108
+
109
+ When a proof ratchet fails, diagnose first. Do not treat
110
+ `proof/baseline.json` as the thing to edit.
111
+
112
+ 1. Do not refresh `proof/baseline.json` as the first fix.
113
+ 2. Identify the exact requirement and symbol responsible for the regression.
114
+ 3. Use Kibi proof diagnostics rather than reverse-engineering
115
+ `requirement_proof.pl`:
116
+
117
+ ```bash
118
+ kibi proof explain REQ-<id>
119
+ kibi proof explain SYM-<id>
120
+ kibi proof impact
121
+ ```
122
+
123
+ `kibi proof impact` compares the current Proof projection to
124
+ `HEAD:proof/baseline.json` (the committed ratchet snapshot, not the
125
+ working-tree file). It is diagnostic: fingerprint differences are reported
126
+ and the command exits 0 on successful evaluation. The strict ratchet remains
127
+ `scripts/check-proof-baseline.mjs`.
128
+ 4. For `missing_production_symbol_coverage`, inspect symbol role, owning
129
+ requirement, `covered_by`, candidate test scope, the requirement scenario
130
+ chain, and the current proof receipt. `kibi proof explain` prints those as
131
+ three labeled blocks so they cannot be confused:
132
+ `required_proofs` (TEST contract obligations), `executable_for` (test-code
133
+ identity), and `covered_by` (production coverage candidates with primary
134
+ plus optional secondary reasons).
135
+ 5. A behavioral production symbol requires qualifying behavioral/E2E evidence
136
+ under the current proof model.
137
+ 6. Unit coverage can satisfy structural/type-shape requirements only when the
138
+ symbol genuinely represents structural shape and the proof model allows it.
139
+ 7. `executable_for` identifies executable test code. Never use it on
140
+ production helpers merely to remove production coverage obligations.
141
+ 8. Do not trust TEST names. Resolve
142
+ `TEST -> proof_contract.required_proofs -> SYM -> source` and inspect what
143
+ the executable test actually exercises. Kibi does not infer “this TEST name
144
+ does not match that source file.”
145
+ 9. A passing proof producer does not automatically make every authored
146
+ `covered_by` relationship semantically correct.
147
+ 10. Prefer one meaningful E2E scenario covering multiple internal functions
148
+ plus focused unit tests for edge cases, rather than an E2E test per helper.
149
+ 11. Refresh the baseline only after a genuine intentional proof-state
150
+ improvement requires the ratchet snapshot to be updated.
@@ -12,6 +12,7 @@
12
12
  | `constrains` | req -> fact(subject) | Requirement constrains a strict-lane domain fact |
13
13
  | `requires_property` | req -> fact(property_value) | Requirement requires a specific property value fact |
14
14
  | `supersedes` | new-req -> old-req | New requirement formally replaces an old requirement |
15
+ | `restates` | req -> req | Requirement intentionally restates another current requirement (for example a product requirement echoed in a platform requirement); suppresses `domain-redundancy` for that pair without retiring either side |
15
16
  | `covered_by` | symbol -> test | Production symbol has test coverage evidence |
16
17
 
17
18
  ## Valid Payload Examples
@@ -20,32 +21,32 @@
20
21
  ```yaml
21
22
  relationships:
22
23
  - type: implements
23
- from: SYM-001
24
- to: REQ-001
24
+ from: SYM-operation-execute-check
25
+ to: REQ-cli-check
25
26
  ```
26
27
 
27
28
  ### specified_by
28
29
  ```yaml
29
30
  relationships:
30
31
  - type: specified_by
31
- from: REQ-001
32
- to: SCEN-001
32
+ from: REQ-mcp-search-discovery
33
+ to: SCEN-mcp-search-discovery
33
34
  ```
34
35
 
35
36
  ### verified_by
36
37
  ```yaml
37
38
  relationships:
38
39
  - type: verified_by
39
- from: REQ-001
40
- to: TEST-001
40
+ from: REQ-mcp-search-discovery
41
+ to: TEST-mcp-search-discovery
41
42
  ```
42
43
 
43
44
  ### validates
44
45
  ```yaml
45
46
  relationships:
46
47
  - type: validates
47
- from: TEST-001
48
- to: SCEN-001
48
+ from: TEST-mcp-search-discovery
49
+ to: SCEN-mcp-search-discovery
49
50
  ```
50
51
 
51
52
  ### executable_for
@@ -53,39 +54,56 @@ relationships:
53
54
  relationships:
54
55
  - type: executable_for
55
56
  from: SYM-test-login
56
- to: TEST-001
57
+ to: TEST-mcp-search-discovery
57
58
  ```
58
59
 
59
60
  ### constrains
60
61
  ```yaml
61
62
  relationships:
62
63
  - type: constrains
63
- from: REQ-019
64
- to: FACT-USER-ROLE
64
+ from: REQ-cli-check
65
+ to: FACT-SUBJECT-KIBI-CHECK
65
66
  ```
66
67
 
67
68
  ### requires_property
68
69
  ```yaml
69
70
  relationships:
70
71
  - type: requires_property
71
- from: REQ-019
72
- to: FACT-LIMIT-3
72
+ from: REQ-cli-check
73
+ to: FACT-PROP-CHECK-FAILURE-EXIT-CODE
73
74
  ```
74
75
 
75
76
  ### supersedes
76
77
  ```yaml
77
78
  relationships:
78
79
  - type: supersedes
79
- from: REQ-001-v2
80
- to: REQ-001
80
+ from: REQ-opencode-kibi-briefing-v2
81
+ to: REQ-opencode-kibi-briefing-v1
81
82
  ```
82
83
 
84
+ A `-v2` suffix is acceptable only for a direct superseding replacement like
85
+ this one; otherwise name the new requirement by the behavior it governs.
86
+
87
+ ### restates
88
+ ```yaml
89
+ # Illustrative: a product requirement echoes a platform requirement verbatim.
90
+ relationships:
91
+ - type: restates
92
+ from: REQ-billing-invoice-retention
93
+ to: REQ-platform-record-retention
94
+ ```
95
+
96
+ Use `restates` only when two current requirements deliberately ground the same
97
+ logical term (same predicate, property tuple, or rule semantic key). It keeps
98
+ both requirements current and tells `domain-redundancy` the duplication is
99
+ intentional. If one requirement replaces the other, use `supersedes` instead.
100
+
83
101
  ### covered_by
84
102
  ```yaml
85
103
  relationships:
86
104
  - type: covered_by
87
- from: SYM-handler
88
- to: TEST-005
105
+ from: SYM-operation-execute-check
106
+ to: TEST-mcp-search-discovery
89
107
  ```
90
108
 
91
109
  ## Invalid Test-Fact Shortcuts
@@ -29,3 +29,39 @@ Cancellation follows the same rule: wait for the terminal journal state. A
29
29
  pre-commit rollback is retryable, a committed source with a failed derivative
30
30
  is repairable, and an indeterminate outcome is non-retryable until its recovery
31
31
  action resolves the journal.
32
+
33
+ ## Naming entities
34
+
35
+ Name every entity by what it governs, the way you would name a source file.
36
+ Never choose "the next number": parallel branches pick the same next number and
37
+ collide even when they touch unrelated behavior.
38
+
39
+ - Use `<TYPE>-<area>-<behavior>` in kebab-case, with the type prefix kept
40
+ uppercase: `REQ-cli-gc`, `SCEN-mcp-search-discovery`,
41
+ `TEST-mcp-search-discovery`, `ADR-capability-plugins-v1`,
42
+ `EVT-exact-branch-store-ensure`, and a flag named after its gate such as
43
+ `FLAG-scip-symbol-extraction`.
44
+ - The filename stem equals the frontmatter `id`
45
+ (`.kb/requirements/REQ-cli-gc.md` has `id: REQ-cli-gc`). Always set `id`
46
+ explicitly; a missing `id` falls back to a path-and-title hash that changes
47
+ when the file is renamed.
48
+ - Before creating an entity, `kb_search` the area. If an existing entity already
49
+ covers the behavior, update it, or create a replacement and link it with
50
+ `supersedes`. A `-v2` suffix is acceptable only for that direct superseding
51
+ replacement.
52
+ - A name collision with another branch usually means the same work was done
53
+ twice. Reconcile the two entities; do not rename one of them to dodge the
54
+ collision.
55
+ - The area prefix is for humans. Whether two requirements are about the same
56
+ thing is decided by their facts: a shared `subject_key` and identical
57
+ predicate or property signatures, which `domain-redundancy` and
58
+ `domain-contradictions` compare deterministically. Reuse existing subject keys
59
+ (dotted `component.aspect[.sub]`, lowercase snake segments such as
60
+ `kibi.cli.check.staged`) instead of deriving a subject from the requirement
61
+ ID.
62
+
63
+ `entity-id-style` reports new purely numeric IDs (`REQ-123`) and IDs whose
64
+ filename stem differs from `id` as non-blocking quality diagnostics. Legacy
65
+ numbered entities created before the naming standard are grandfathered and are
66
+ not renamed, because code comments such as `// implements REQ-003` still
67
+ reference them.
@@ -33,11 +33,62 @@ surfaces are a release defect: require a new package version and label any
33
33
  project override temporary. This skill never selects a package manager or
34
34
  edits dependency configuration.
35
35
 
36
+ ## Choosing a discovery mode
37
+
38
+ `kb_search` is not one behavior. It selects deterministic intent ranking when
39
+ you pass `rankingMode: "intent-v1"`, `semanticFacets`, or `sourceLocations`,
40
+ and legacy lexical ranking otherwise. Naming the tool is not enough; the inputs
41
+ decide the path.
42
+
43
+ - **Exact identity** — you already know the ID. Use `kb_query`, not search.
44
+ - **Literal token** — a symbol, file, or error string that appears verbatim.
45
+ Use lexical `kb_search` and keep the query close to the literal text.
46
+ - **Conceptual or behavioral** — "how does checkout handle a declined card".
47
+ Use intent mode and ground it in what you actually know:
48
+
49
+ ```json
50
+ {
51
+ "query": "declined card during checkout",
52
+ "rankingMode": "intent-v1",
53
+ "semanticFacets": {
54
+ "actors": ["shopper"],
55
+ "actions": ["pay"],
56
+ "objects": ["card"],
57
+ "constraints": ["declined"]
58
+ }
59
+ }
60
+ ```
61
+
62
+ - **Before changing code** — pass the file you are about to edit as a source
63
+ location, so results are matched against source-linked symbols and return
64
+ source evidence:
65
+
66
+ ```json
67
+ {
68
+ "query": "checkout total rounding",
69
+ "rankingMode": "intent-v1",
70
+ "sourceLocations": [{ "path": "src/checkout.ts", "symbol": "computeTotal" }]
71
+ }
72
+ ```
73
+
74
+ Supply facets only from the request, the code, or prior results. Inventing
75
+ facets fabricates evidence and biases ranking. Intent mode abstains below
76
+ `minScore` instead of returning weak matches; an abstention is an explicit
77
+ no-answer, so widen the query or drop to lexical search rather than treating it
78
+ as "nothing exists". There is no target percentage of intent-mode calls — a
79
+ literal identifier lookup is still best served lexically.
80
+
81
+ Results are summaries by default: identifying metadata, score, reasons, and a
82
+ snippet. Read them to pick candidates, then `kb_query` those IDs for full
83
+ bodies, or pass `fields: "full"` when you genuinely need every body. Extract
84
+ the relevant existing constraints and decisions from the response before
85
+ planning a behavior change; a search receipt is not comprehension.
86
+
36
87
  ## Discovery to Validation Sequence
37
88
 
38
89
  The canonical workflow for any KB operation follows this pattern:
39
90
 
40
- 1. **Discover**: `kb_search` with focused probes
91
+ 1. **Discover**: `kb_search` with focused probes; pick the mode above
41
92
  2. **Confirm**: `kb_query` for exact IDs and state
42
93
  3. **Inspect**: `kb_status` when freshness matters
43
94
  4. **Decompose**: `kb_semantic_advisor` on the complete normative prose; verify or supply every atomic clause
@@ -0,0 +1,16 @@
1
+ type ManifestRow = {
2
+ sourceFile: string;
3
+ relationships: {
4
+ type: string;
5
+ target: string;
6
+ }[];
7
+ };
8
+ /**
9
+ * Resolve typed requirement ownership through the shared line-scanned index.
10
+ * Cursor stores the cache beside its hook state, so subsequent hook processes
11
+ * pay only two stats and a small JSON parse while the manifests are unchanged.
12
+ */
13
+ export declare function getSourceLinkedRequirementIds(workspaceRoot: string, editedPath: string, cacheDir?: string): string[];
14
+ /** Parse the canonical writer subset while retaining typed relationships. */
15
+ export declare function parseSymbolsManifest(content: string): ManifestRow[];
16
+ export {};
@@ -0,0 +1,55 @@
1
+ // implements REQ-cursor-kibi-plugin-v1
2
+ import path from "node:path";
3
+ import { buildKnowledgeIndex, loadKnowledgeIndex, scanSymbolsManifest, } from "kibi-agent-core/knowledge-index";
4
+ const MAX_LINKED_REQUIREMENTS = 3;
5
+ const CURSOR_INDEX_OPTIONS = {
6
+ legacyLinksAsImplements: false,
7
+ cacheFileName: "cursor-knowledge-index.json",
8
+ };
9
+ function toManifestPath(workspaceRoot, filePath) {
10
+ const absolute = path.isAbsolute(filePath)
11
+ ? filePath
12
+ : path.resolve(workspaceRoot, filePath);
13
+ return path.relative(workspaceRoot, absolute).split(path.sep).join("/");
14
+ }
15
+ /**
16
+ * Resolve typed requirement ownership through the shared line-scanned index.
17
+ * Cursor stores the cache beside its hook state, so subsequent hook processes
18
+ * pay only two stats and a small JSON parse while the manifests are unchanged.
19
+ */
20
+ export function getSourceLinkedRequirementIds(workspaceRoot, editedPath, cacheDir) {
21
+ const relativePath = toManifestPath(workspaceRoot, editedPath);
22
+ const symbols = loadKnowledgeIndex(workspaceRoot, cacheDir, CURSOR_INDEX_OPTIONS).files[relativePath];
23
+ if (!symbols)
24
+ return [];
25
+ const ordered = [];
26
+ for (const symbol of symbols) {
27
+ for (const requirementId of symbol.implements) {
28
+ if (!ordered.includes(requirementId))
29
+ ordered.push(requirementId);
30
+ }
31
+ }
32
+ return ordered.slice(0, MAX_LINKED_REQUIREMENTS);
33
+ }
34
+ /** Parse the canonical writer subset while retaining typed relationships. */
35
+ // implements REQ-cursor-kibi-plugin-v1
36
+ export function parseSymbolsManifest(content) {
37
+ const index = buildKnowledgeIndex(scanSymbolsManifest(content), {}, CURSOR_INDEX_OPTIONS);
38
+ return Object.entries(index.files).flatMap(([sourceFile, symbols]) => symbols.map((symbol) => ({
39
+ sourceFile,
40
+ relationships: [
41
+ ...symbol.implements.map((target) => ({
42
+ type: "implements",
43
+ target,
44
+ })),
45
+ ...symbol.coveredBy.map((target) => ({
46
+ type: "covered_by",
47
+ target,
48
+ })),
49
+ ...symbol.executableFor.map((target) => ({
50
+ type: "executable_for",
51
+ target,
52
+ })),
53
+ ],
54
+ })));
55
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kibi-cursor",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
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",
@@ -53,6 +53,9 @@
53
53
  "optional": true
54
54
  }
55
55
  },
56
+ "dependencies": {
57
+ "kibi-agent-core": "^0.1.0"
58
+ },
56
59
  "devDependencies": {
57
60
  "@types/node": "latest",
58
61
  "typescript": "^5.7.0"