kibi-cursor 2.0.1 → 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 +61 -0
- package/README.md +1 -1
- package/agent-plugin/plugin.json +1 -1
- package/agent-plugin/skills/kibi-usage/SKILL.md +7 -3
- package/agent-plugin/skills/kibi-usage/resources/fact-lanes.md +4 -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-runner.js +23 -2
- package/dist/hook-state-storage.js +3 -0
- package/dist/hook-state.d.ts +4 -2
- package/dist/hook-state.js +16 -3
- package/dist/kb-mcp-tools.d.ts +5 -7
- package/dist/kb-mcp-tools.js +6 -146
- package/dist/path-policy.js +17 -188
- package/dist/skills/.canon-hash.json +5 -5
- package/dist/skills/kibi-usage/SKILL.md +7 -3
- package/dist/skills/kibi-usage/resources/fact-lanes.md +4 -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 +5 -5
- package/skills/kibi-usage/SKILL.md +7 -3
- package/skills/kibi-usage/resources/fact-lanes.md +4 -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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-cursor",
|
|
3
3
|
"displayName": "Kibi",
|
|
4
|
-
"version": "2.0
|
|
4
|
+
"version": "2.1.0",
|
|
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,66 @@
|
|
|
1
1
|
# kibi-cursor
|
|
2
2
|
|
|
3
|
+
## 2.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- f01838e: The Cursor plugin now asks the agent to consult Kibi before it edits a file, not only after. Every nudge used to fire once the change was already written — the post-edit message opened with "After editing" twice — so the plugin could only ever prompt repair, never inform the change. Before an edit, the plugin now names only requirements the file explicitly implements and asks for them to be read first, which is the one point where retrieval can still change what gets written.
|
|
8
|
+
|
|
9
|
+
- Emit source-linked pre-edit guidance from `preToolUse` for edit-like tools, resolved synchronously from the symbol manifest so no KB round-trip is added to the edit path.
|
|
10
|
+
- Name up to three `implements` requirement targets for the file, or ask for discovery and ownership when no requirement ownership is known.
|
|
11
|
+
- Narrow the post-edit message to the impact review that only becomes possible once the change exists, and stop repeating the retrieval ask there.
|
|
12
|
+
- Track pre-edit guidance in its own hook-state bucket so it is emitted once per path without suppressing the post-edit review.
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- 35cd120: The ZCode, Codex, and Cursor plugins now recognize Kibi tools when the host
|
|
17
|
+
reports them with a prefix, such as `mcp__kibi__kb_check`. Before this fix,
|
|
18
|
+
an agent that correctly ran an impact check through a prefixed tool name
|
|
19
|
+
still got a stop reminder to run it, because the plugin never saw the check.
|
|
20
|
+
|
|
21
|
+
- `kb-mcp-tools.ts` in each adapter gains `canonicalKbToolName`, which strips
|
|
22
|
+
`mcp__<server>__`, `MCP:`, and `kibi_` prefixes before matching `kb_*`
|
|
23
|
+
operations.
|
|
24
|
+
- The Codex hook bundle is regenerated.
|
|
25
|
+
|
|
26
|
+
- 25f11b1: The badge that `kibi init --github` adds to your README now links to the published explanation of the `% proven` metric at https://looted.github.io/kibi/ instead of the GitHub rendering of the Markdown source. The Kibi documentation site moved to the root of that domain, with the requirement-health report still under `/kibi-report/`. The Cursor and OpenCode package READMEs also link to the published guides, so the links work when you read them on npm.
|
|
27
|
+
|
|
28
|
+
- cli: `KIBI_METRIC_DOCS_URL` points at `https://looted.github.io/kibi/guide/github-integration.html#what-the-badge-means`.
|
|
29
|
+
- cursor, opencode: README setup and troubleshooting links point at the published guide pages instead of repository-relative or GitHub blob URLs.
|
|
30
|
+
- repo tooling (not published): the docs site builds into the GitHub Pages root and renders `llms.txt` as one H2 link list per catalog group from the shared page metadata.
|
|
31
|
+
|
|
32
|
+
- 5a06c03: Kibi's agent plugins now share one fast, consistent implementation for source-path classification, Kibi MCP tool recognition, and symbol-manifest indexing. Codex and ZCode now recognize production code outside `src/`, while Cursor reuses the same size-and-mtime-keyed scanner as Claude instead of parsing the full symbol manifest before an edit.
|
|
33
|
+
|
|
34
|
+
- Add `kibi-agent-core` as the common Node 18-compatible hook-helper package.
|
|
35
|
+
- Keep host adapters thin while preserving their host-specific event and state contracts.
|
|
36
|
+
- Replace Cursor's YAML parser dependency with the shared cached line scanner.
|
|
37
|
+
|
|
38
|
+
- f01838e: Usage telemetry stays off by default for every client, and there is now a supported way to turn it on. Previously the only way to capture usage was to hand-write an MCP command line with `--diagnostic-mode`, which meant anyone using a shipped plugin recorded nothing at all and had no documented alternative. Operators can now opt in with an environment variable, and once they do, each row identifies the host, package version, and checkout that produced it, so behavior can be compared across editors, worktrees, and Kibi versions.
|
|
39
|
+
|
|
40
|
+
- Honor `KIBI_DIAGNOSTIC_MODE=1` alongside the existing `--diagnostic-mode` flag, for hosts where a plugin owns the MCP command line.
|
|
41
|
+
- Stamp `interface`, `host`, `package_version`, and `workspace_root` on every usage row.
|
|
42
|
+
- Set `KIBI_MCP_HOST` from the Cursor and Codex launchers for attribution only; it never enables logging, and installing or enabling a plugin never starts telemetry.
|
|
43
|
+
- Stop the bundled Cursor worktree resolver from hard-coding `--diagnostic-mode`, so a shipped launcher cannot enable capture on an operator's behalf.
|
|
44
|
+
- Document the opt-in, what a row contains, and how to opt out in `docs/mcp-reference.md`.
|
|
45
|
+
|
|
46
|
+
- 0128b56: Kibi now helps agents keep one shared vocabulary instead of letting every requirement invent its own. `kibi check` warns when two unrelated requirements state the same obligation. Units are compared in canonical form, so "30 min" matches "1800 s", and each warning names the exact facts involved. It also flags subject keys copied from a requirement ID, subject keys that don't follow `component.aspect`, predicates whose arguments read like prose, and entity files whose name doesn't match their ID. All of these are non-blocking warnings or info notes, so existing knowledge bases keep passing.
|
|
47
|
+
|
|
48
|
+
When you model a new requirement, Kibi now ranks the subjects that already exist and either reuses one or explicitly declares a new one. It also flags claims that look like possible duplicates. An intentional restatement can be recorded with the new `restates` relationship. Skills and docs now recommend naming entities by the behavior they govern (`REQ-cli-gc`) instead of a sequence number (`REQ-042`). Existing numbered IDs stay valid.
|
|
49
|
+
|
|
50
|
+
Predicate schemas can now declare the allowed values for an argument, plus the old spellings that map onto them. New facts must use those values. `kibi check` reports predicate facts that don't match any schema, and `kibi migrate` can fix the mechanical cases after you approve the plan hash. It moves a fact to the only namespace whose schema matches, and rewrites old spellings to the declared value. Everything that needs judgment stays a review item.
|
|
51
|
+
|
|
52
|
+
- core: new `semantic_quality.pl` (`entity-id-style`, `domain-redundancy`, `domain-implication`, `subject-key-identity`, `subject-key-shape`, `ontology-quality`) and `units.pl`. Unit canonicalization is used for comparison only, and unknown or ambiguous units such as `KB` are never equated. Adds the `restates` req→req relationship and an optional `diagnosticSeverity` in the rule registry. Adds `:- encoding(utf8)` to modules that contain non-ASCII text.
|
|
53
|
+
- cli/mcp: `restates` is wired through the extractors, schemas, and mutation paths. `entity-id-style` warnings are reported on `kb_upsert` creates and on staged added or renamed entity files. `kb_model_requirement` returns `vocabularyAlignment` (subject decision, candidates, redundancy candidates, stamps, `fallbackUsed`). Ontology-quality thresholds can be set with `KIBI_ONTOLOGY_QUALITY_MAX_SINGLETON_RATIO` / `KIBI_ONTOLOGY_QUALITY_MIN_FACTS`. `kb_compile_intent` create mode now keeps a caller-supplied `requirementId`. `kibi check --staged` now also prints its pass line when metadata-only staged changes have only advisory findings, matching the staged-symbol path.
|
|
54
|
+
- cli/mcp: `predicate_schema` facts accept `argument_constants` and `argument_aliases`, stored like `rule_ir` as JSON. `kb_upsert` / `kb_validate_upsert` reject malformed vocabularies and predicate facts that use undeclared values or aliases. `kb_suggest_predicates` binds aliases to their constant and leaves undeclared values unbound. The new advisory TypeScript rule `predicate-schema-conformance` checks predicate facts against project schemas and the built-in catalog. Its mechanical repairs become automatic `predicate_schema_alignment` migration actions that carry the exact `kb_upsert` input and re-read the fact before writing.
|
|
55
|
+
- core: `ontology-quality` findings name the prose-like arguments.
|
|
56
|
+
- plugin-sdk: new `kibi.vocabulary-alignment.v1` capability (`rankSubjects`, `compareClaims`) with result validators.
|
|
57
|
+
- plugin-builtin: deterministic offline provider (IDF-weighted subject ranking and negation- and quantity-aware claim similarity).
|
|
58
|
+
- plugin-jev: Jev-backed provider. It runs in replace, augment, or shadow mode with builtin fallback, and makes network calls only when it is activated for `kb_model_requirement`. `kb_check` never calls a provider.
|
|
59
|
+
- runtime and agent adapters: regenerated skill mirrors with the naming guidance and `restates` direction docs.
|
|
60
|
+
|
|
61
|
+
- Updated dependencies [5a06c03]
|
|
62
|
+
- kibi-agent-core@0.1.0
|
|
63
|
+
|
|
3
64
|
## 2.0.1
|
|
4
65
|
|
|
5
66
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ swipl --version
|
|
|
21
21
|
npm exec -- kibi doctor
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
Full setup: [
|
|
24
|
+
Full setup: [installation guide](https://looted.github.io/kibi/guide/install.html#optional-cursor-plugin).
|
|
25
25
|
|
|
26
26
|
Add this plugin only after the base packages work in your project.
|
|
27
27
|
|
package/agent-plugin/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "kibi",
|
|
4
|
-
"version": "2.0
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"description": "Repo-local, per-branch, queryable knowledge base. Portable Agent Plugin packaging Kibi's Agent Skills and MCP server.",
|
|
6
6
|
"author": { "name": "Kibi" },
|
|
7
7
|
"homepage": "https://github.com/Looted/kibi/blob/develop/docs/install.md",
|
|
@@ -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.
|
|
@@ -160,7 +164,7 @@ Represent implementation ownership with a `symbol` entity that has
|
|
|
160
164
|
`sourceFile`, `implements` to the requirement, and `covered_by` to the test.
|
|
161
165
|
Prolog `symbol-coverage` also requires the test to `validates` the requirement
|
|
162
166
|
(or the requirement `verified_by` the test). `covered_by` alone is not
|
|
163
|
-
enough. Do not rely on legacy `// implements REQ
|
|
167
|
+
enough. Do not rely on legacy `// implements REQ-<area>-<behavior>` comments as the
|
|
164
168
|
traceability record.
|
|
165
169
|
|
|
166
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:
|
|
@@ -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
|
package/bin/launch-kibi-mcp.mjs
CHANGED
|
@@ -362,7 +362,14 @@ export function launchKibiMcp(
|
|
|
362
362
|
[projectLocal.binPath, ...childArgs],
|
|
363
363
|
{
|
|
364
364
|
cwd: workspaceRoot,
|
|
365
|
-
env: {
|
|
365
|
+
env: {
|
|
366
|
+
...env,
|
|
367
|
+
KIBI_WORKSPACE: workspaceRoot,
|
|
368
|
+
// Identify the host on usage rows. This never enables telemetry;
|
|
369
|
+
// KIBI_DIAGNOSTIC_MODE stays the operator's explicit opt-in and is
|
|
370
|
+
// passed through untouched.
|
|
371
|
+
KIBI_MCP_HOST: "cursor",
|
|
372
|
+
},
|
|
366
373
|
stdio: ["inherit", "inherit", "inherit"],
|
|
367
374
|
},
|
|
368
375
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-cursor",
|
|
3
3
|
"displayName": "Kibi",
|
|
4
|
-
"version": "2.0
|
|
4
|
+
"version": "2.1.0",
|
|
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": {
|
|
@@ -362,7 +362,14 @@ export function launchKibiMcp(
|
|
|
362
362
|
[projectLocal.binPath, ...childArgs],
|
|
363
363
|
{
|
|
364
364
|
cwd: workspaceRoot,
|
|
365
|
-
env: {
|
|
365
|
+
env: {
|
|
366
|
+
...env,
|
|
367
|
+
KIBI_WORKSPACE: workspaceRoot,
|
|
368
|
+
// Identify the host on usage rows. This never enables telemetry;
|
|
369
|
+
// KIBI_DIAGNOSTIC_MODE stays the operator's explicit opt-in and is
|
|
370
|
+
// passed through untouched.
|
|
371
|
+
KIBI_MCP_HOST: "cursor",
|
|
372
|
+
},
|
|
366
373
|
stdio: ["inherit", "inherit", "inherit"],
|
|
367
374
|
},
|
|
368
375
|
);
|
package/dist/guidance.d.ts
CHANGED
|
@@ -5,6 +5,17 @@ export type GuidanceContext = {
|
|
|
5
5
|
readonly hasKibi: boolean;
|
|
6
6
|
readonly mcpState: McpState;
|
|
7
7
|
readonly workspaceTrusted: boolean;
|
|
8
|
+
/** Requirements the edited file already owns, when the manifest knows them. */
|
|
9
|
+
readonly linkedRequirementIds?: readonly string[];
|
|
8
10
|
};
|
|
9
11
|
export declare function readGuidance(filePath: string, context: GuidanceContext): string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Guidance emitted before an edit is written.
|
|
14
|
+
*
|
|
15
|
+
* The post-edit and stop messages can only ask for repair once the code is
|
|
16
|
+
* already changed. This is the one point where retrieval can still inform the
|
|
17
|
+
* change, so it names the requirements the file already implements and asks
|
|
18
|
+
* for them to be read before the edit rather than reconciled after it.
|
|
19
|
+
*/
|
|
20
|
+
export declare function preEditGuidance(filePath: string, context: GuidanceContext): string | undefined;
|
|
10
21
|
export declare function writeGuidance(filePath: string, context: GuidanceContext): string | undefined;
|
package/dist/guidance.js
CHANGED
|
@@ -18,6 +18,40 @@ export function readGuidance(filePath, context) {
|
|
|
18
18
|
const advisory = interfaceAdvisory(context.mcpState, context.workspaceTrusted);
|
|
19
19
|
return advisory ? [advisory, ...guidance].join("\n") : guidance.join("\n");
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Guidance emitted before an edit is written.
|
|
23
|
+
*
|
|
24
|
+
* The post-edit and stop messages can only ask for repair once the code is
|
|
25
|
+
* already changed. This is the one point where retrieval can still inform the
|
|
26
|
+
* change, so it names the requirements the file already implements and asks
|
|
27
|
+
* for them to be read before the edit rather than reconciled after it.
|
|
28
|
+
*/
|
|
29
|
+
export function preEditGuidance(filePath, context) {
|
|
30
|
+
if (!context.hasKibi) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
const relativePath = toRepoRelativePath(filePath, context.cwd);
|
|
34
|
+
if (!isMeaningfulTrackedPath(relativePath)) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
if (isDocumentationTrackedPath(relativePath)) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const linkedRequirements = context.linkedRequirementIds ?? [];
|
|
41
|
+
const guidance = linkedRequirements.length > 0
|
|
42
|
+
? [
|
|
43
|
+
`Kibi pre-edit guidance: ${relativePath} already implements ${linkedRequirements.join(", ")}.`,
|
|
44
|
+
`Read those requirements with kb_query before changing behavior here, and widen with kb_query({sourceFile:"${relativePath}"}) for scenarios and tests.`,
|
|
45
|
+
"If the change contradicts an existing requirement, resolve that in Kibi before writing the edit.",
|
|
46
|
+
]
|
|
47
|
+
: [
|
|
48
|
+
`Kibi pre-edit guidance: ${relativePath} has no linked requirement in the symbol manifest.`,
|
|
49
|
+
`Discover existing constraints with kb_search, then kb_query({sourceFile:"${relativePath}"}), before changing behavior here.`,
|
|
50
|
+
"Record the requirement this change serves rather than leaving the symbol unowned.",
|
|
51
|
+
];
|
|
52
|
+
const advisory = interfaceAdvisory(context.mcpState, context.workspaceTrusted);
|
|
53
|
+
return advisory ? [advisory, ...guidance].join("\n") : guidance.join("\n");
|
|
54
|
+
}
|
|
21
55
|
export function writeGuidance(filePath, context) {
|
|
22
56
|
if (!context.hasKibi) {
|
|
23
57
|
return undefined;
|
|
@@ -35,12 +69,12 @@ export function writeGuidance(filePath, context) {
|
|
|
35
69
|
const advisory = interfaceAdvisory(context.mcpState, context.workspaceTrusted);
|
|
36
70
|
return advisory ? [advisory, ...guidance].join("\n") : guidance.join("\n");
|
|
37
71
|
}
|
|
72
|
+
// Retrieval is asked for before the edit; this message stays scoped to the
|
|
73
|
+
// impact review that only becomes possible once the change exists.
|
|
38
74
|
const guidance = [
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"Prefer symbol manifest + executable_for or // implements REQ-xxx for traceability.",
|
|
43
|
-
"Do not read or edit `.kb/` files directly. Query before mutate; run kb_upsert sequentially and kb_check before completion.",
|
|
75
|
+
`Kibi impact review: run kb_check({sourceFiles:["${relativePath}"], includeImpactDiagnostics:true, includeWorkingTreeDiff:true}) while this edit is fresh.`,
|
|
76
|
+
"Check symbol granularity and whether linked requirements, scenarios, and tests still cover the changed behavior.",
|
|
77
|
+
"Prefer symbol manifest + executable_for or // implements REQ-<area>-<behavior> for traceability.",
|
|
44
78
|
];
|
|
45
79
|
const advisory = interfaceAdvisory(context.mcpState, context.workspaceTrusted);
|
|
46
80
|
return advisory ? [advisory, ...guidance].join("\n") : guidance.join("\n");
|
package/dist/hook-runner.js
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
-
import { readGuidance, writeGuidance } from "./guidance.js";
|
|
6
|
+
import { preEditGuidance, readGuidance, writeGuidance } from "./guidance.js";
|
|
7
7
|
import { parseHookInput, parseStdinJson, readStdin } from "./hook-input.js";
|
|
8
8
|
import { addDirtyPaths, clearSessionHookState, hasGuidedPath, loadHookState, recordKbMcpTool, recordPlanDelivered, rememberGuidedPath, resolveStateDir, } from "./hook-state.js";
|
|
9
9
|
import { extractKbMcpToolCall } from "./kb-mcp-tools.js";
|
|
10
10
|
import { BOOTSTRAP_REMINDER, DIRECT_KB_EDIT_WARNING, interfaceAdvisory, stopFollowupMessage, } from "./messages.js";
|
|
11
11
|
import { extractExplicitPathFields, isDirectKbPath, isKbFreshnessRelevantPath, isMeaningfulTrackedPath, toRepoRelativePath, } from "./path-policy.js";
|
|
12
|
+
import { getSourceLinkedRequirementIds } from "./source-linked-requirements.js";
|
|
12
13
|
const editableTools = new Set([
|
|
13
14
|
"Edit",
|
|
14
15
|
"MultiEdit",
|
|
@@ -86,7 +87,27 @@ export async function runHook(rawInput, environment = {}) {
|
|
|
86
87
|
agent_message: DIRECT_KB_EDIT_WARNING,
|
|
87
88
|
};
|
|
88
89
|
}
|
|
89
|
-
|
|
90
|
+
const primaryPath = resolvePrimaryPath(input);
|
|
91
|
+
if (!primaryPath || !kibiReady || !isKnownEditableTool(input.toolName)) {
|
|
92
|
+
return emptyResult();
|
|
93
|
+
}
|
|
94
|
+
const relativePath = toRepoRelativePath(primaryPath, cwd);
|
|
95
|
+
const state = loadHookState(stateDir);
|
|
96
|
+
if (hasGuidedPath(state, "pre-edit", relativePath)) {
|
|
97
|
+
return emptyResult();
|
|
98
|
+
}
|
|
99
|
+
const guidance = preEditGuidance(primaryPath, {
|
|
100
|
+
cwd,
|
|
101
|
+
hasKibi: kibiReady,
|
|
102
|
+
mcpState: state.mcpState,
|
|
103
|
+
workspaceTrusted,
|
|
104
|
+
linkedRequirementIds: getSourceLinkedRequirementIds(cwd, primaryPath, stateDir),
|
|
105
|
+
});
|
|
106
|
+
if (!guidance) {
|
|
107
|
+
return emptyResult();
|
|
108
|
+
}
|
|
109
|
+
rememberGuidedPath(stateDir, "pre-edit", relativePath);
|
|
110
|
+
return { permission: "allow", agent_message: guidance };
|
|
90
111
|
}
|
|
91
112
|
case "beforeReadFile": {
|
|
92
113
|
const primaryPath = resolvePrimaryPath(input);
|
|
@@ -51,6 +51,7 @@ export function emptyHookState() {
|
|
|
51
51
|
mcpState: "unknown",
|
|
52
52
|
dirtyPaths: [],
|
|
53
53
|
guidedReadPaths: [],
|
|
54
|
+
guidedPreEditPaths: [],
|
|
54
55
|
guidedWritePaths: [],
|
|
55
56
|
kbMutationTools: [],
|
|
56
57
|
kbCheckRun: false,
|
|
@@ -164,6 +165,7 @@ function coerceHookState(value) {
|
|
|
164
165
|
: [];
|
|
165
166
|
const dirtyPaths = strings(value.dirtyPaths, normalizePath);
|
|
166
167
|
const guidedReadPaths = strings(value.guidedReadPaths, normalizePath);
|
|
168
|
+
const guidedPreEditPaths = strings(value.guidedPreEditPaths, normalizePath);
|
|
167
169
|
const guidedWritePaths = strings(value.guidedWritePaths, normalizePath);
|
|
168
170
|
const kbMutationTools = strings(value.kbMutationTools, (entry) => entry.trim());
|
|
169
171
|
const impactCheckedPaths = strings(value.impactCheckedPaths, normalizePath);
|
|
@@ -171,6 +173,7 @@ function coerceHookState(value) {
|
|
|
171
173
|
mcpState: value.mcpState === "observed" ? "observed" : "unknown",
|
|
172
174
|
dirtyPaths: [...new Set(dirtyPaths)].slice(-maxDirtyPaths),
|
|
173
175
|
guidedReadPaths: [...new Set(guidedReadPaths)].slice(-maxGuidedPaths),
|
|
176
|
+
guidedPreEditPaths: [...new Set(guidedPreEditPaths)].slice(-maxGuidedPaths),
|
|
174
177
|
guidedWritePaths: [...new Set(guidedWritePaths)].slice(-maxGuidedPaths),
|
|
175
178
|
kbMutationTools: [...new Set(kbMutationTools)].slice(-maxKbMutationTools),
|
|
176
179
|
kbCheckRun: value.kbCheckRun === true,
|
package/dist/hook-state.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { McpState } from "./kb-mcp-tools.js";
|
|
2
2
|
export { loadHookState, resolveStateDir, saveHookState, updateHookState, } from "./hook-state-storage.js";
|
|
3
|
+
export type GuidedPathKind = "read" | "pre-edit" | "write";
|
|
3
4
|
export type HookState = {
|
|
4
5
|
mcpState: McpState;
|
|
5
6
|
dirtyPaths: string[];
|
|
6
7
|
guidedReadPaths: string[];
|
|
8
|
+
guidedPreEditPaths: string[];
|
|
7
9
|
guidedWritePaths: string[];
|
|
8
10
|
kbMutationTools: string[];
|
|
9
11
|
kbCheckRun: boolean;
|
|
@@ -12,8 +14,8 @@ export type HookState = {
|
|
|
12
14
|
planDelivered: boolean;
|
|
13
15
|
};
|
|
14
16
|
export declare function addDirtyPaths(stateDir: string | undefined, dirtyPaths: readonly string[]): HookState;
|
|
15
|
-
export declare function rememberGuidedPath(stateDir: string | undefined, kind:
|
|
16
|
-
export declare function hasGuidedPath(state: HookState, kind:
|
|
17
|
+
export declare function rememberGuidedPath(stateDir: string | undefined, kind: GuidedPathKind, guidedPath: string): HookState;
|
|
18
|
+
export declare function hasGuidedPath(state: HookState, kind: GuidedPathKind, guidedPath: string): boolean;
|
|
17
19
|
export declare function recordPlanDelivered(stateDir: string | undefined): HookState;
|
|
18
20
|
export declare function recordKbMcpTool(stateDir: string | undefined, toolName: string, options?: {
|
|
19
21
|
impactCheckRun?: boolean;
|
package/dist/hook-state.js
CHANGED
|
@@ -15,6 +15,14 @@ export function rememberGuidedPath(stateDir, kind, guidedPath) {
|
|
|
15
15
|
guidedReadPaths: mergeStringPaths(state.guidedReadPaths, [normalized]),
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
|
+
if (kind === "pre-edit") {
|
|
19
|
+
return {
|
|
20
|
+
...state,
|
|
21
|
+
guidedPreEditPaths: mergeStringPaths(state.guidedPreEditPaths, [
|
|
22
|
+
normalized,
|
|
23
|
+
]),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
18
26
|
return {
|
|
19
27
|
...state,
|
|
20
28
|
guidedWritePaths: mergeStringPaths(state.guidedWritePaths, [normalized]),
|
|
@@ -22,9 +30,14 @@ export function rememberGuidedPath(stateDir, kind, guidedPath) {
|
|
|
22
30
|
});
|
|
23
31
|
}
|
|
24
32
|
export function hasGuidedPath(state, kind, guidedPath) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
return guidedBucket(state, kind).includes(normalizePath(guidedPath));
|
|
34
|
+
}
|
|
35
|
+
function guidedBucket(state, kind) {
|
|
36
|
+
if (kind === "read")
|
|
37
|
+
return state.guidedReadPaths;
|
|
38
|
+
if (kind === "pre-edit")
|
|
39
|
+
return state.guidedPreEditPaths;
|
|
40
|
+
return state.guidedWritePaths;
|
|
28
41
|
}
|
|
29
42
|
export function recordPlanDelivered(stateDir) {
|
|
30
43
|
return updateHookState(stateDir, (state) => state.planDelivered ? state : { ...state, planDelivered: true });
|
package/dist/kb-mcp-tools.d.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export type McpState = "observed" | "unknown";
|
|
7
|
-
export type KibiInterface = "mcp" | "cli" | "setup";
|
|
1
|
+
import type { KbMcpToolCall as SharedKbMcpToolCall, KibiInterface as SharedKibiInterface, McpState as SharedMcpState } from "kibi-agent-core/kb-mcp-tools";
|
|
2
|
+
export type KbMcpToolCall = SharedKbMcpToolCall;
|
|
3
|
+
export type McpState = SharedMcpState;
|
|
4
|
+
export type KibiInterface = SharedKibiInterface;
|
|
5
|
+
export declare function canonicalKbToolName(toolName: string | undefined): string | undefined;
|
|
8
6
|
export declare function resolveKibiInterface(mcpState: McpState, workspaceTrusted: boolean): KibiInterface;
|
|
9
7
|
export declare function extractKbMcpToolCall(toolName: string | undefined, toolInput: unknown): KbMcpToolCall | undefined;
|
|
10
8
|
export declare function extractKbMcpToolName(toolName: string | undefined, toolInput: unknown): string | undefined;
|