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.
- package/.cursor-plugin/plugin.json +1 -1
- package/CHANGELOG.md +84 -0
- package/README.md +1 -1
- package/agent-plugin/plugin.json +1 -1
- package/agent-plugin/skills/kibi-usage/SKILL.md +10 -3
- package/agent-plugin/skills/kibi-usage/resources/fact-lanes.md +4 -0
- package/agent-plugin/skills/kibi-usage/resources/proof.md +45 -0
- package/agent-plugin/skills/kibi-usage/resources/relationship-directions.md +35 -17
- package/agent-plugin/skills/kibi-usage/resources/source-authoring.md +36 -0
- package/agent-plugin/skills/kibi-usage/resources/workflows.md +52 -1
- package/bin/launch-kibi-mcp.mjs +8 -1
- package/dist/.cursor-plugin/plugin.json +1 -1
- package/dist/bin/launch-kibi-mcp.mjs +8 -1
- package/dist/guidance.d.ts +11 -0
- package/dist/guidance.js +39 -5
- package/dist/hook-input.js +7 -4
- package/dist/hook-runner.js +36 -6
- package/dist/hook-state-storage.js +55 -2
- package/dist/hook-state.d.ts +4 -2
- package/dist/hook-state.js +30 -7
- package/dist/kb-mcp-tools.d.ts +5 -7
- package/dist/kb-mcp-tools.js +6 -126
- package/dist/messages.js +3 -8
- package/dist/path-policy.js +17 -177
- package/dist/skills/.canon-hash.json +6 -6
- package/dist/skills/kibi-usage/SKILL.md +10 -3
- package/dist/skills/kibi-usage/resources/fact-lanes.md +4 -0
- package/dist/skills/kibi-usage/resources/proof.md +45 -0
- package/dist/skills/kibi-usage/resources/relationship-directions.md +35 -17
- package/dist/skills/kibi-usage/resources/source-authoring.md +36 -0
- package/dist/skills/kibi-usage/resources/workflows.md +52 -1
- package/dist/source-linked-requirements.d.ts +16 -0
- package/dist/source-linked-requirements.js +55 -0
- package/package.json +4 -1
- package/skills/.canon-hash.json +6 -6
- package/skills/kibi-usage/SKILL.md +10 -3
- package/skills/kibi-usage/resources/fact-lanes.md +4 -0
- package/skills/kibi-usage/resources/proof.md +45 -0
- package/skills/kibi-usage/resources/relationship-directions.md +35 -17
- package/skills/kibi-usage/resources/source-authoring.md +36 -0
- package/skills/kibi-usage/resources/workflows.md +52 -1
package/dist/path-policy.js
CHANGED
|
@@ -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
|
-
|
|
122
|
-
visitExplicitPathFields(input, paths);
|
|
123
|
-
return [...new Set(paths)];
|
|
15
|
+
return extractSharedExplicitPathFields(input);
|
|
124
16
|
}
|
|
125
17
|
export function isDirectKbPath(candidate) {
|
|
126
|
-
return
|
|
18
|
+
return isKbPath(candidate);
|
|
127
19
|
}
|
|
128
20
|
export function isMeaningfulTrackedPath(candidate) {
|
|
129
|
-
|
|
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 =
|
|
157
|
-
if (segments[0] === ".kb")
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
200
|
-
if (!cwd)
|
|
41
|
+
const normalized = normalizeWorkspacePath(candidate);
|
|
42
|
+
if (!cwd)
|
|
201
43
|
return normalized;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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": "
|
|
16
|
+
"kibi-usage/SKILL.md": "83567f8ead944457719e0254ad6bc1dbedda3a70d04266d2ff041a670336dcc6",
|
|
17
17
|
"kibi-usage/resources/branch-lifecycle.md": "f1bf359e9826e83c548f3cd0287f8175a62456527b0132b06b3f9f74aa59b7d6",
|
|
18
|
-
"kibi-usage/resources/fact-lanes.md": "
|
|
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": "
|
|
23
|
-
"kibi-usage/resources/relationship-directions.md": "
|
|
24
|
-
"kibi-usage/resources/source-authoring.md": "
|
|
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": "
|
|
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.
|
|
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
|
|
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-
|
|
24
|
-
to: REQ-
|
|
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-
|
|
32
|
-
to: SCEN-
|
|
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-
|
|
40
|
-
to: TEST-
|
|
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-
|
|
48
|
-
to: SCEN-
|
|
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-
|
|
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-
|
|
64
|
-
to: FACT-
|
|
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-
|
|
72
|
-
to: FACT-
|
|
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-
|
|
80
|
-
to: REQ-
|
|
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-
|
|
88
|
-
to: TEST-
|
|
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.
|
|
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"
|