kibi-cli 2.6.0 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-operation-metadata.d.ts +1 -1
- package/dist/cli-operation-metadata.js +1 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +15 -0
- package/dist/commands/init-helpers.js +1 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +43 -0
- package/dist/entity-body-context.d.ts +132 -0
- package/dist/entity-body-context.d.ts.map +1 -0
- package/dist/entity-body-context.js +382 -0
- package/dist/extractors/markdown.d.ts +13 -0
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +19 -2
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +4 -4
- package/dist/operations/bootstrap/candidate-helpers.d.ts +18 -0
- package/dist/operations/bootstrap/candidate-helpers.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidate-helpers.js +35 -0
- package/dist/operations/bootstrap/candidates.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidates.js +4 -2
- package/dist/operations/bootstrap/intent-claims.d.ts.map +1 -1
- package/dist/operations/bootstrap/intent-claims.js +59 -4
- package/dist/operations/bootstrap/markdown-candidates.d.ts.map +1 -1
- package/dist/operations/bootstrap/markdown-candidates.js +7 -3
- package/dist/operations/bootstrap/presentation.js +1 -1
- package/dist/operations/migration/entity-body-context.d.ts +57 -0
- package/dist/operations/migration/entity-body-context.d.ts.map +1 -0
- package/dist/operations/migration/entity-body-context.js +261 -0
- package/dist/operations/migration/polarity-values.d.ts.map +1 -1
- package/dist/operations/migration/polarity-values.js +5 -2
- package/dist/operations/migration/schema6.d.ts +2 -0
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +69 -0
- package/dist/operations/modeling/logic-modeling.d.ts.map +1 -1
- package/dist/operations/modeling/logic-modeling.js +3 -1
- package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
- package/dist/operations/modeling/model-requirement.js +7 -9
- package/dist/operations/mutation/context-warning.d.ts +13 -0
- package/dist/operations/mutation/context-warning.d.ts.map +1 -0
- package/dist/operations/mutation/context-warning.js +59 -0
- package/dist/operations/mutation/origin.d.ts +2 -1
- package/dist/operations/mutation/origin.d.ts.map +1 -1
- package/dist/operations/mutation/origin.js +7 -18
- package/dist/operations/mutation/requirement-semantics.d.ts +16 -0
- package/dist/operations/mutation/requirement-semantics.d.ts.map +1 -0
- package/dist/operations/mutation/requirement-semantics.js +64 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +10 -0
- package/dist/operations/mutation/stored-entity.d.ts +20 -0
- package/dist/operations/mutation/stored-entity.d.ts.map +1 -0
- package/dist/operations/mutation/stored-entity.js +51 -0
- package/dist/operations/mutation/upsert.d.ts +3 -2
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +19 -10
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +6 -1
- package/dist/operations/planning/compile-intent.d.ts +9 -0
- package/dist/operations/planning/compile-intent.d.ts.map +1 -1
- package/dist/operations/planning/compile-intent.js +49 -2
- package/dist/operations/semantic-advisor/analyze-prose.d.ts +3 -2
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +3 -41
- package/dist/operations/semantic-advisor/ingestion-boundary.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/ingestion-boundary.js +10 -1
- package/dist/operations/semantic-advisor/proposition-role.d.ts +6 -0
- package/dist/operations/semantic-advisor/proposition-role.d.ts.map +1 -0
- package/dist/operations/semantic-advisor/proposition-role.js +76 -0
- package/dist/public/operations/catalog.d.ts +33 -6
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +3 -0
- package/dist/public/operations/entity-context.d.ts +51 -0
- package/dist/public/operations/entity-context.d.ts.map +1 -0
- package/dist/public/operations/entity-context.js +235 -0
- package/dist/public/operations/origin-review.d.ts +1 -1
- package/dist/public/operations/origin-review.js +2 -2
- package/dist/public/operations/specs/bootstrap.d.ts +14 -2
- package/dist/public/operations/specs/bootstrap.d.ts.map +1 -1
- package/dist/public/operations/specs/bootstrap.js +8 -2
- package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
- package/dist/public/operations/specs/check-rules.generated.js +3 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts +1 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +10 -2
- package/dist/public/operations/specs/planning.d.ts +15 -0
- package/dist/public/operations/specs/planning.d.ts.map +1 -1
- package/dist/public/operations/specs/planning.js +15 -0
- package/dist/public/operations/specs/upsert.d.ts +3 -3
- package/dist/public/operations/specs/upsert.js +2 -2
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +7 -1
- package/dist/public/skills/kibi-bootstrap/SKILL.md +3 -3
- package/dist/public/skills/kibi-bootstrap/resources/bootstrap.md +5 -1
- package/dist/public/skills/kibi-usage/SKILL.md +56 -3
- package/dist/public/skills/kibi-usage/resources/source-authoring.md +5 -1
- package/dist/schemas/entity.schema.json +14 -1
- package/dist/search-ranking.d.ts.map +1 -1
- package/dist/search-ranking.js +7 -4
- package/dist/traceability/staged-consistency.d.ts +25 -0
- package/dist/traceability/staged-consistency.d.ts.map +1 -0
- package/dist/traceability/staged-consistency.js +92 -0
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +5 -0
- package/dist/utils/kb-manifest.d.ts +5 -0
- package/dist/utils/kb-manifest.d.ts.map +1 -1
- package/dist/utils/kb-manifest.js +6 -0
- package/dist/utils/rule-registry.generated.d.ts +11 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +13 -0
- package/dist/utils/schema-version.d.ts +1 -1
- package/dist/utils/schema-version.d.ts.map +1 -1
- package/dist/utils/schema-version.js +3 -2
- package/package.json +2 -2
- package/schema/manifest.json +5 -0
- package/schema/validation.pl +14 -2
- package/src/public/operations/check-executor.ts +6 -0
- package/src/public/operations/entity-context.ts +304 -0
- package/src/public/operations/origin-review.ts +2 -2
- package/src/public/operations/specs/bootstrap.ts +9 -2
- package/src/public/operations/specs/check-rules.generated.ts +3 -1
- package/src/public/operations/specs/mutation-schemas.ts +10 -2
- package/src/public/operations/specs/planning.ts +18 -0
- package/src/public/operations/specs/upsert.ts +2 -2
- package/src/public/schemas/entity.ts +7 -1
- package/src/public/skills/kibi-bootstrap/SKILL.md +3 -3
- package/src/public/skills/kibi-bootstrap/resources/bootstrap.md +5 -1
- package/src/public/skills/kibi-usage/SKILL.md +56 -3
- package/src/public/skills/kibi-usage/resources/source-authoring.md +5 -1
- package/src/schemas/entity.schema.json +14 -1
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Kibi — repo-local, per-branch, queryable long-term memory for software projects
|
|
3
|
+
Copyright (C) 2026 Piotr Franczyk
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Affero General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Entity Markdown bodies carry human and agent context next to, not inside,
|
|
20
|
+
* the checked meaning. This module is the one place that knows which body
|
|
21
|
+
* text is context, so the extractor, the strict check, compile-intent,
|
|
22
|
+
* bootstrap, the migration and search all agree.
|
|
23
|
+
*/
|
|
24
|
+
/** Heading words whose sections hold context rather than normative text. */
|
|
25
|
+
// implements REQ-kb-entity-body-context
|
|
26
|
+
export const CONTEXT_HEADING_WORDS = [
|
|
27
|
+
"context",
|
|
28
|
+
"rationale",
|
|
29
|
+
"why",
|
|
30
|
+
"background",
|
|
31
|
+
"source",
|
|
32
|
+
"notes",
|
|
33
|
+
"evidence",
|
|
34
|
+
];
|
|
35
|
+
/** A context section needs at least this many words of prose. */
|
|
36
|
+
// implements REQ-kb-entity-body-context
|
|
37
|
+
export const MIN_CONTEXT_WORDS = 12;
|
|
38
|
+
/** Token-set Jaccard at or above this value counts as a restatement. */
|
|
39
|
+
// implements REQ-kb-entity-body-context
|
|
40
|
+
export const RESTATEMENT_JACCARD = 0.8;
|
|
41
|
+
/** Tag that marks legacy entities acknowledged as lacking context. */
|
|
42
|
+
// implements REQ-kb-entity-body-context
|
|
43
|
+
export const CONTEXT_MISSING_TAG = "review:context-missing";
|
|
44
|
+
const HEADING_LINE = /^\s{0,3}(#{1,6})(?:[ \t]+(.*?))?[ \t]*$/;
|
|
45
|
+
const CONTEXT_HEADING = new RegExp(`^(?:${CONTEXT_HEADING_WORDS.join("|")})\\b`, "i");
|
|
46
|
+
/** True when a heading's text starts with a context heading word. */
|
|
47
|
+
// implements REQ-kb-entity-body-context
|
|
48
|
+
export function isContextHeading(heading) {
|
|
49
|
+
return CONTEXT_HEADING.test(heading.trim().replace(/^[*_`\s]+/, ""));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Classify every line of a body. A line under a context heading stays in
|
|
53
|
+
* context until the next heading of the same or a higher level, so
|
|
54
|
+
* `### Constraints` below `## Context` is still context.
|
|
55
|
+
*/
|
|
56
|
+
function classifyLines(body) {
|
|
57
|
+
const classified = [];
|
|
58
|
+
let contextLevel = null;
|
|
59
|
+
for (const line of body.replace(/\r\n?/g, "\n").split("\n")) {
|
|
60
|
+
const match = HEADING_LINE.exec(line);
|
|
61
|
+
if (match === null) {
|
|
62
|
+
classified.push({
|
|
63
|
+
line,
|
|
64
|
+
level: 0,
|
|
65
|
+
heading: "",
|
|
66
|
+
inContext: contextLevel !== null,
|
|
67
|
+
});
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const level = match[1]?.length ?? 1;
|
|
71
|
+
const heading = (match[2] ?? "").replace(/[ \t]+#+$/, "").trim();
|
|
72
|
+
if (contextLevel !== null && level <= contextLevel)
|
|
73
|
+
contextLevel = null;
|
|
74
|
+
if (contextLevel === null && isContextHeading(heading)) {
|
|
75
|
+
contextLevel = level;
|
|
76
|
+
}
|
|
77
|
+
classified.push({ line, level, heading, inContext: contextLevel !== null });
|
|
78
|
+
}
|
|
79
|
+
return classified;
|
|
80
|
+
}
|
|
81
|
+
/** Split a Markdown body (front matter removed) into sections by ATX headings. */
|
|
82
|
+
// implements REQ-kb-entity-body-context
|
|
83
|
+
export function parseBodySections(body) {
|
|
84
|
+
const sections = [];
|
|
85
|
+
let current = {
|
|
86
|
+
level: 0,
|
|
87
|
+
heading: "",
|
|
88
|
+
isContext: false,
|
|
89
|
+
};
|
|
90
|
+
let lines = [];
|
|
91
|
+
const flush = () => {
|
|
92
|
+
const text = lines.join("\n").trim();
|
|
93
|
+
if (current.level > 0 || text !== "")
|
|
94
|
+
sections.push({ ...current, text });
|
|
95
|
+
lines = [];
|
|
96
|
+
};
|
|
97
|
+
for (const row of classifyLines(body)) {
|
|
98
|
+
if (row.level === 0) {
|
|
99
|
+
lines.push(row.line);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
flush();
|
|
103
|
+
current = {
|
|
104
|
+
level: row.level,
|
|
105
|
+
heading: row.heading,
|
|
106
|
+
isContext: row.inContext,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
flush();
|
|
110
|
+
return sections;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The body with every line of its context sections removed (other lines are
|
|
114
|
+
* untouched), for deriving the checked meaning.
|
|
115
|
+
*/
|
|
116
|
+
// implements REQ-kb-entity-body-context
|
|
117
|
+
export function withoutContextSections(body) {
|
|
118
|
+
return classifyLines(body)
|
|
119
|
+
.filter((row) => !row.inContext)
|
|
120
|
+
.map((row) => row.line)
|
|
121
|
+
.join("\n");
|
|
122
|
+
}
|
|
123
|
+
/** Text of the context sections of a body, headings excluded. */
|
|
124
|
+
// implements REQ-kb-entity-body-context
|
|
125
|
+
export function contextSectionText(body) {
|
|
126
|
+
return parseBodySections(body)
|
|
127
|
+
.filter((section) => section.isContext && section.text !== "")
|
|
128
|
+
.map((section) => section.text)
|
|
129
|
+
.join("\n\n");
|
|
130
|
+
}
|
|
131
|
+
/** Types whose entities must carry body context. */
|
|
132
|
+
// implements REQ-kb-entity-body-context
|
|
133
|
+
export const CONTEXT_REQUIRED_TYPES = [
|
|
134
|
+
"req",
|
|
135
|
+
"scenario",
|
|
136
|
+
"test",
|
|
137
|
+
"adr",
|
|
138
|
+
"fact",
|
|
139
|
+
];
|
|
140
|
+
/**
|
|
141
|
+
* True when the type needs no body context: symbols, flags and events, and
|
|
142
|
+
* facts of any fact_kind other than observation or meta (their front matter
|
|
143
|
+
* is the content).
|
|
144
|
+
*/
|
|
145
|
+
// implements REQ-kb-entity-body-context
|
|
146
|
+
export function isContextExempt(type, entity) {
|
|
147
|
+
if (type === "fact") {
|
|
148
|
+
return entity.fact_kind !== "observation" && entity.fact_kind !== "meta";
|
|
149
|
+
}
|
|
150
|
+
return !CONTEXT_REQUIRED_TYPES.includes(type);
|
|
151
|
+
}
|
|
152
|
+
function proseWithoutHeadings(body) {
|
|
153
|
+
return parseBodySections(body)
|
|
154
|
+
.map((section) => section.text)
|
|
155
|
+
.filter((text) => text !== "")
|
|
156
|
+
.join("\n");
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* The body prose that counts as context. Requirements: only text under
|
|
160
|
+
* context headings. Scenarios, tests, ADRs and observation or meta facts:
|
|
161
|
+
* all body prose outside headings.
|
|
162
|
+
*/
|
|
163
|
+
// implements REQ-kb-entity-body-context
|
|
164
|
+
export function contextProse(type, body, _entity = {}) {
|
|
165
|
+
return type === "req" ? contextSectionText(body) : proseWithoutHeadings(body);
|
|
166
|
+
}
|
|
167
|
+
function tokens(text) {
|
|
168
|
+
return text
|
|
169
|
+
.toLowerCase()
|
|
170
|
+
.split(/[^\p{L}\p{N}]+/u)
|
|
171
|
+
.filter((token) => token !== "");
|
|
172
|
+
}
|
|
173
|
+
/** Normalized token-set Jaccard similarity of two texts (0 when both empty). */
|
|
174
|
+
// implements REQ-kb-entity-body-context
|
|
175
|
+
export function tokenSetJaccard(left, right) {
|
|
176
|
+
const a = new Set(tokens(left));
|
|
177
|
+
const b = new Set(tokens(right));
|
|
178
|
+
if (a.size === 0 && b.size === 0)
|
|
179
|
+
return 0;
|
|
180
|
+
let shared = 0;
|
|
181
|
+
for (const token of a)
|
|
182
|
+
if (b.has(token))
|
|
183
|
+
shared += 1;
|
|
184
|
+
return shared / (a.size + b.size - shared);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Judge an entity's body context: at least MIN_CONTEXT_WORDS words of
|
|
188
|
+
* context prose that do not restate the title (or, for requirements, the
|
|
189
|
+
* semantic text). Exempt types always pass.
|
|
190
|
+
*/
|
|
191
|
+
// implements REQ-kb-entity-body-context
|
|
192
|
+
export function assessContext(type, body, entity) {
|
|
193
|
+
if (isContextExempt(type, entity))
|
|
194
|
+
return { ok: true, words: 0 };
|
|
195
|
+
const prose = contextProse(type, body, entity);
|
|
196
|
+
const words = tokens(prose).length;
|
|
197
|
+
if (words === 0)
|
|
198
|
+
return { ok: false, reason: "none", words };
|
|
199
|
+
if (words < MIN_CONTEXT_WORDS)
|
|
200
|
+
return { ok: false, reason: "too_short", words };
|
|
201
|
+
const references = [
|
|
202
|
+
typeof entity.title === "string" ? entity.title : "",
|
|
203
|
+
type === "req" && typeof entity.semantic_text === "string"
|
|
204
|
+
? entity.semantic_text
|
|
205
|
+
: "",
|
|
206
|
+
].filter((text) => text.trim() !== "");
|
|
207
|
+
if (references.some((reference) => tokenSetJaccard(prose, reference) >= RESTATEMENT_JACCARD)) {
|
|
208
|
+
return { ok: false, reason: "restatement", words };
|
|
209
|
+
}
|
|
210
|
+
return { ok: true, words };
|
|
211
|
+
}
|
|
212
|
+
/** True when the entity's body states context that is not a restatement. */
|
|
213
|
+
// implements REQ-kb-entity-body-context
|
|
214
|
+
export function hasContext(type, body, entity) {
|
|
215
|
+
return assessContext(type, body, entity).ok;
|
|
216
|
+
}
|
|
217
|
+
const TYPE_LABEL = {
|
|
218
|
+
req: "requirement",
|
|
219
|
+
scenario: "scenario",
|
|
220
|
+
test: "test",
|
|
221
|
+
adr: "ADR",
|
|
222
|
+
fact: "observation fact",
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* The finding for an entity whose body lacks context, or null when it has
|
|
226
|
+
* context, is exempt, or is acknowledged by the schema 8 migration
|
|
227
|
+
* (`acknowledged`, true only for ids the migration recorded in the manifest;
|
|
228
|
+
* the tag alone never exempts). The strict check and the kb_upsert warning
|
|
229
|
+
* share it.
|
|
230
|
+
*/
|
|
231
|
+
// implements REQ-kb-entity-body-context
|
|
232
|
+
export function contextFinding(type, id, body, entity, acknowledged = false) {
|
|
233
|
+
const assessment = assessContext(type, body, entity);
|
|
234
|
+
if (assessment.ok || assessment.reason === undefined)
|
|
235
|
+
return null;
|
|
236
|
+
if (acknowledged)
|
|
237
|
+
return null;
|
|
238
|
+
return {
|
|
239
|
+
type,
|
|
240
|
+
id,
|
|
241
|
+
reason: assessment.reason,
|
|
242
|
+
words: assessment.words,
|
|
243
|
+
description: `${TYPE_LABEL[type] ?? type} ${id} has no body context: ${missingContextDescription(type, assessment.reason)}`,
|
|
244
|
+
suggestion: CONTEXT_MISSING_HINT,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
/** True when the entity's tags acknowledge missing context as legacy. */
|
|
248
|
+
// implements REQ-kb-entity-body-context
|
|
249
|
+
export function isContextAcknowledged(tags) {
|
|
250
|
+
return Array.isArray(tags) && tags.includes(CONTEXT_MISSING_TAG);
|
|
251
|
+
}
|
|
252
|
+
/** What is missing for a type, in the words the check and warnings use. */
|
|
253
|
+
// implements REQ-kb-entity-body-context
|
|
254
|
+
export function missingContextDescription(type, reason) {
|
|
255
|
+
const where = type === "req"
|
|
256
|
+
? "a '## Context' (or Rationale, Why, Background, Source, Notes, Evidence) section"
|
|
257
|
+
: "body prose";
|
|
258
|
+
const what = reason === "restatement"
|
|
259
|
+
? "only restates the title or statement"
|
|
260
|
+
: reason === "too_short"
|
|
261
|
+
? `is shorter than ${MIN_CONTEXT_WORDS} words`
|
|
262
|
+
: "is missing";
|
|
263
|
+
return `${where} that states why this exists ${what}`;
|
|
264
|
+
}
|
|
265
|
+
/** Hint shared by the check finding and the kb_upsert warning. */
|
|
266
|
+
// implements REQ-kb-entity-body-context
|
|
267
|
+
export const CONTEXT_MISSING_HINT = "Add a '## Context' section (requirements) or a prose body (scenarios, tests, ADRs, observation facts) stating why this exists, who asked, the source and anything that does not fit the front matter. Never invent a reason the requester did not give: write who asked, the source and 'Reason not stated' in the Context section instead.";
|
|
268
|
+
/** Suggestion for a review:context-missing tag the schema 8 migration did not set. */
|
|
269
|
+
// implements REQ-kb-entity-body-context
|
|
270
|
+
export const RESERVED_TAG_HINT = "review:context-missing is reserved for entities acknowledged by the schema 8 migration; add context instead: write who asked, the source and 'Reason not stated' in the Context section, and remove the tag.";
|
|
271
|
+
function blockquote(text) {
|
|
272
|
+
return text
|
|
273
|
+
.replace(/\r\n?/g, "\n")
|
|
274
|
+
.trim()
|
|
275
|
+
.split("\n")
|
|
276
|
+
.map((line) => (line.trim() === "" ? ">" : `> ${line}`))
|
|
277
|
+
.join("\n");
|
|
278
|
+
}
|
|
279
|
+
function contextSectionBlock(context) {
|
|
280
|
+
return `## Context\n\n${context.trim()}`;
|
|
281
|
+
}
|
|
282
|
+
function sourceSectionBlock(source) {
|
|
283
|
+
const sourceLines = [];
|
|
284
|
+
const excerpt = source?.excerpt?.trim();
|
|
285
|
+
if (excerpt)
|
|
286
|
+
sourceLines.push(blockquote(excerpt));
|
|
287
|
+
const reference = [source?.title?.trim(), source?.reference?.trim()]
|
|
288
|
+
.filter((part) => part !== undefined && part !== "")
|
|
289
|
+
.join(" - ");
|
|
290
|
+
if (reference)
|
|
291
|
+
sourceLines.push(`Source: ${reference}`);
|
|
292
|
+
return sourceLines.length > 0
|
|
293
|
+
? `## Source\n\n${sourceLines.join("\n\n")}`
|
|
294
|
+
: null;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Render a requirement body: the statement, then `## Context` and
|
|
298
|
+
* `## Source` when given. The statement stays the first, heading-free block
|
|
299
|
+
* so it remains the derived meaning when no `semantic_text` is pinned.
|
|
300
|
+
*/
|
|
301
|
+
// implements REQ-kb-entity-body-context
|
|
302
|
+
export function renderRequirementBody(input) {
|
|
303
|
+
const blocks = [input.statement.trim()];
|
|
304
|
+
const context = input.context?.trim();
|
|
305
|
+
if (context)
|
|
306
|
+
blocks.push(contextSectionBlock(context));
|
|
307
|
+
const source = sourceSectionBlock(input.source);
|
|
308
|
+
if (source !== null)
|
|
309
|
+
blocks.push(source);
|
|
310
|
+
return `${blocks.join("\n\n")}\n`;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Revise a requirement body for a changed statement. The non-context part is
|
|
314
|
+
* replaced by the new statement; every context section is kept byte for byte,
|
|
315
|
+
* except that a supplied `context` replaces the `## Context` section and a
|
|
316
|
+
* supplied source replaces the `## Source` section (each is appended when the
|
|
317
|
+
* body had none).
|
|
318
|
+
*/
|
|
319
|
+
// implements REQ-kb-entity-body-context
|
|
320
|
+
export function reviseRequirementBody(input) {
|
|
321
|
+
const replacements = new Map();
|
|
322
|
+
const context = input.context?.trim();
|
|
323
|
+
if (context)
|
|
324
|
+
replacements.set("context", contextSectionBlock(context));
|
|
325
|
+
const source = sourceSectionBlock(input.source);
|
|
326
|
+
if (source !== null)
|
|
327
|
+
replacements.set("source", source);
|
|
328
|
+
const blocks = [];
|
|
329
|
+
let open = null;
|
|
330
|
+
let openLevel = 0;
|
|
331
|
+
for (const row of classifyLines(input.existingBody)) {
|
|
332
|
+
if (!row.inContext) {
|
|
333
|
+
open = null;
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
const startsBlock = row.level > 0 &&
|
|
337
|
+
isContextHeading(row.heading) &&
|
|
338
|
+
(open === null || row.level <= openLevel);
|
|
339
|
+
if (startsBlock) {
|
|
340
|
+
const word = row.heading
|
|
341
|
+
.trim()
|
|
342
|
+
.replace(/^[*_`\s]+/, "")
|
|
343
|
+
.split(/\W+/, 1)[0];
|
|
344
|
+
open = { key: (word ?? "").toLowerCase(), lines: [] };
|
|
345
|
+
openLevel = row.level;
|
|
346
|
+
blocks.push(open);
|
|
347
|
+
}
|
|
348
|
+
open?.lines.push(row.line);
|
|
349
|
+
}
|
|
350
|
+
const used = new Set();
|
|
351
|
+
const parts = [input.statement.trim()];
|
|
352
|
+
for (const block of blocks) {
|
|
353
|
+
const replacement = replacements.get(block.key);
|
|
354
|
+
if (replacement !== undefined && !used.has(block.key)) {
|
|
355
|
+
used.add(block.key);
|
|
356
|
+
parts.push(replacement);
|
|
357
|
+
}
|
|
358
|
+
else if (replacement === undefined) {
|
|
359
|
+
parts.push(block.lines.join("\n").replace(/\n+$/, ""));
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
for (const [key, replacement] of replacements) {
|
|
363
|
+
if (!used.has(key))
|
|
364
|
+
parts.push(replacement);
|
|
365
|
+
}
|
|
366
|
+
return `${parts.join("\n\n")}\n`;
|
|
367
|
+
}
|
|
368
|
+
function firstLine(text) {
|
|
369
|
+
return text
|
|
370
|
+
.split(/\r?\n/)
|
|
371
|
+
.map((line) => line.trim())
|
|
372
|
+
.find(Boolean);
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* The line a search row shows for a body: the first line of the context
|
|
376
|
+
* prose when the body has any, else the first non-blank body line. With a
|
|
377
|
+
* statement-only body the first line would repeat the title.
|
|
378
|
+
*/
|
|
379
|
+
// implements REQ-kb-entity-body-context
|
|
380
|
+
export function bodySnippetLine(type, body, entity = {}) {
|
|
381
|
+
return firstLine(contextProse(type, body, entity)) ?? firstLine(body);
|
|
382
|
+
}
|
|
@@ -101,6 +101,19 @@ export declare class FrontmatterError extends Error {
|
|
|
101
101
|
});
|
|
102
102
|
toString(): string;
|
|
103
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* The checked meaning derived from a requirement body before schema 8: every
|
|
106
|
+
* line except headings, with list and quote markers removed. Context
|
|
107
|
+
* sections were part of it. Schema 8 pins this value as `semantic_text` for
|
|
108
|
+
* requirements that never stated one, so claim spans and hashes do not move.
|
|
109
|
+
*/
|
|
110
|
+
export declare function legacyRequirementSemanticText(body: string): string;
|
|
111
|
+
/**
|
|
112
|
+
* The checked meaning derived from a requirement body: the legacy derivation
|
|
113
|
+
* over the body with its context sections (Context, Rationale, Why,
|
|
114
|
+
* Background, Source, Notes, Evidence) removed, so context never changes
|
|
115
|
+
* what a requirement means.
|
|
116
|
+
*/
|
|
104
117
|
export declare function requirementSemanticText(body: string): string;
|
|
105
118
|
export declare function detectEmbeddedEntities(data: Record<string, unknown>, entityType: string): string[];
|
|
106
119
|
export declare function extractFromMarkdownString(content: string, filePath: string): ExtractionResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/extractors/markdown.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/extractors/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,6 +19,7 @@ import { createHash } from "node:crypto";
|
|
|
19
19
|
import { readFileSync } from "node:fs";
|
|
20
20
|
import Ajv from "ajv";
|
|
21
21
|
import { load as yamlLoad } from "js-yaml";
|
|
22
|
+
import { withoutContextSections } from "../entity-body-context.js";
|
|
22
23
|
import { semanticClaimKey } from "../operations/semantic-advisor/clauses.js";
|
|
23
24
|
import { normalizeEntityOrigin, } from "../public/entity-origin.js";
|
|
24
25
|
import { PROOF_BINDINGS_SCHEMA, PROOF_CONTRACT_SCHEMA, } from "../public/proof-protocol.js";
|
|
@@ -251,8 +252,14 @@ function parseFrontmatter(content) {
|
|
|
251
252
|
content: parts.slice(2).join("---"),
|
|
252
253
|
};
|
|
253
254
|
}
|
|
254
|
-
|
|
255
|
-
|
|
255
|
+
/**
|
|
256
|
+
* The checked meaning derived from a requirement body before schema 8: every
|
|
257
|
+
* line except headings, with list and quote markers removed. Context
|
|
258
|
+
* sections were part of it. Schema 8 pins this value as `semantic_text` for
|
|
259
|
+
* requirements that never stated one, so claim spans and hashes do not move.
|
|
260
|
+
*/
|
|
261
|
+
// implements REQ-kibi-legacy-migration-preview-v2, REQ-kb-entity-body-context
|
|
262
|
+
export function legacyRequirementSemanticText(body) {
|
|
256
263
|
return body
|
|
257
264
|
.replace(/\r\n?/g, "\n")
|
|
258
265
|
.split("\n")
|
|
@@ -261,6 +268,16 @@ export function requirementSemanticText(body) {
|
|
|
261
268
|
.join("\n")
|
|
262
269
|
.trim();
|
|
263
270
|
}
|
|
271
|
+
/**
|
|
272
|
+
* The checked meaning derived from a requirement body: the legacy derivation
|
|
273
|
+
* over the body with its context sections (Context, Rationale, Why,
|
|
274
|
+
* Background, Source, Notes, Evidence) removed, so context never changes
|
|
275
|
+
* what a requirement means.
|
|
276
|
+
*/
|
|
277
|
+
// implements REQ-kibi-legacy-migration-preview-v2, REQ-kb-entity-body-context
|
|
278
|
+
export function requirementSemanticText(body) {
|
|
279
|
+
return legacyRequirementSemanticText(withoutContextSections(body));
|
|
280
|
+
}
|
|
264
281
|
function hasLikelyUnquotedColonInTitle(content) {
|
|
265
282
|
if (!content.trim().startsWith("---")) {
|
|
266
283
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent-search.d.ts","sourceRoot":"","sources":["../src/intent-search.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"intent-search.d.ts","sourceRoot":"","sources":["../src/intent-search.ts"],"names":[],"mappings":"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"}
|
package/dist/intent-search.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { bodySnippetLine } from "./entity-body-context.js";
|
|
2
3
|
import { escapeAtom, normalizeEntityId, parseTriples } from "./prolog/codec.js";
|
|
3
4
|
import { listSearchCandidates, loadEntityRows, loadSearchCandidates, } from "./public/operations/discovery-entities.js";
|
|
4
5
|
import { loadMarkdownBody } from "./search-ranking.js";
|
|
@@ -418,10 +419,9 @@ export async function rankIntentEntities(entities, options, workspaceRoot, graph
|
|
|
418
419
|
const scored = scoreEntity(entity, allTokens, facets, sourceEvidence, graphEvidence, documentFrequency, entities.length, body, supersededIds.has(entityId));
|
|
419
420
|
if (scored.score < minScore)
|
|
420
421
|
continue;
|
|
421
|
-
const snippet = body
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
.find(Boolean);
|
|
422
|
+
const snippet = body === null
|
|
423
|
+
? undefined
|
|
424
|
+
: bodySnippetLine(String(entity.type ?? ""), body, entity);
|
|
425
425
|
ranked.push({
|
|
426
426
|
entity,
|
|
427
427
|
score: scored.score,
|
|
@@ -10,4 +10,22 @@ export declare function upsert<T extends {
|
|
|
10
10
|
readonly to: string;
|
|
11
11
|
}[]): Readonly<Record<string, unknown>>;
|
|
12
12
|
export declare function strictPlan(writeSet: StrictWriteSet): readonly Readonly<Record<string, unknown>>[];
|
|
13
|
+
/**
|
|
14
|
+
* Attach an authored body to an upsert step so the entity document carries
|
|
15
|
+
* more than its front matter.
|
|
16
|
+
*/
|
|
17
|
+
export declare function withDocumentBody(step: Readonly<Record<string, unknown>>, body: string): Readonly<Record<string, unknown>>;
|
|
18
|
+
/**
|
|
19
|
+
* Where a deterministic bootstrap provider found an entry. No reason was
|
|
20
|
+
* stated in the source, so the sentence records provenance instead of
|
|
21
|
+
* inventing one; later schema versions and reviewers keep the origin.
|
|
22
|
+
*/
|
|
23
|
+
export declare function bootstrapProvenance(provider: string, location: string, confidence: number): string;
|
|
24
|
+
/** Body for a non-requirement entity: its title, then its provenance. */
|
|
25
|
+
export declare function provenanceBody(title: string, provenance: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Body for a requirement found in prose: the statement, the provenance as
|
|
28
|
+
* its Context and the quoted statement with its location as its Source.
|
|
29
|
+
*/
|
|
30
|
+
export declare function provenanceRequirementBody(statement: string, provenance: string, reference: string): string;
|
|
13
31
|
//# sourceMappingURL=candidate-helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"candidate-helpers.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/candidate-helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"candidate-helpers.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/candidate-helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAIrE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,CAMtD;AAED,wBAAgB,MAAM,CACpB,CAAC,SAAS;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,OAAO,CAAA;CAAE,EAE5D,MAAM,EAAE,CAAC,EACT,aAAa,GAAE,SAAS;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB,EAAO,GACP,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAQnC;AAED,wBAAgB,UAAU,CACxB,QAAQ,EAAE,cAAc,GACvB,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CA0C9C;AAED;;;GAGG;AAEH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACvC,IAAI,EAAE,MAAM,GACX,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAEnC;AAED;;;;GAIG;AAEH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAER;AAED,yEAAyE;AAEzE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAExE;AAED;;;GAGG;AAEH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,MAAM,CAMR"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { renderRequirementBody } from "../../entity-body-context.js";
|
|
1
2
|
import { annotateModelRequirementStep } from "../modeling/model-requirement.js";
|
|
2
3
|
import { semanticClaimKey } from "../semantic-advisor/clauses.js";
|
|
3
4
|
export function confidenceBand(value) {
|
|
@@ -60,3 +61,37 @@ export function strictPlan(writeSet) {
|
|
|
60
61
|
logicClaims: [claimKey],
|
|
61
62
|
}));
|
|
62
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Attach an authored body to an upsert step so the entity document carries
|
|
66
|
+
* more than its front matter.
|
|
67
|
+
*/
|
|
68
|
+
// implements REQ-kb-entity-body-context
|
|
69
|
+
export function withDocumentBody(step, body) {
|
|
70
|
+
return { ...step, document: { body } };
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Where a deterministic bootstrap provider found an entry. No reason was
|
|
74
|
+
* stated in the source, so the sentence records provenance instead of
|
|
75
|
+
* inventing one; later schema versions and reviewers keep the origin.
|
|
76
|
+
*/
|
|
77
|
+
// implements REQ-kb-entity-body-context
|
|
78
|
+
export function bootstrapProvenance(provider, location, confidence) {
|
|
79
|
+
return `Recorded deterministically by the ${provider} bootstrap provider from ${location} (confidence ${confidence.toFixed(2)}). The source states no reason for this entry, so it preserves where the knowledge came from for later schema versions and reviewers.`;
|
|
80
|
+
}
|
|
81
|
+
/** Body for a non-requirement entity: its title, then its provenance. */
|
|
82
|
+
// implements REQ-kb-entity-body-context
|
|
83
|
+
export function provenanceBody(title, provenance) {
|
|
84
|
+
return `${title.trim()}\n\n${provenance}\n`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Body for a requirement found in prose: the statement, the provenance as
|
|
88
|
+
* its Context and the quoted statement with its location as its Source.
|
|
89
|
+
*/
|
|
90
|
+
// implements REQ-kb-entity-body-context
|
|
91
|
+
export function provenanceRequirementBody(statement, provenance, reference) {
|
|
92
|
+
return renderRequirementBody({
|
|
93
|
+
statement,
|
|
94
|
+
context: provenance,
|
|
95
|
+
source: { excerpt: statement, reference },
|
|
96
|
+
});
|
|
97
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"candidates.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/candidates.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"candidates.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/candidates.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,YAAY,CAAC;AAuHpB,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,EACtC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,EACrB,sBAAsB,EAAE,OAAO,GAC9B,oBAAoB,CA4DtB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { extractFromManifestString } from "../../extractors/manifest.js";
|
|
3
3
|
import { extractFromMarkdownString } from "../../extractors/markdown.js";
|
|
4
|
-
import { confidenceBand, slug, upsert } from "./candidate-helpers.js";
|
|
4
|
+
import { bootstrapProvenance, confidenceBand, provenanceBody, slug, upsert, withDocumentBody, } from "./candidate-helpers.js";
|
|
5
5
|
import { markdownCandidates, } from "./markdown-candidates.js";
|
|
6
6
|
function typedCandidates(item, existingIds) {
|
|
7
7
|
const results = item.kind === "symbol_manifest"
|
|
@@ -82,7 +82,9 @@ function providerCandidate(item, existingIds, minConfidence) {
|
|
|
82
82
|
confidenceBand: confidenceBand(confidence),
|
|
83
83
|
evidence,
|
|
84
84
|
relationships: [],
|
|
85
|
-
applyPlan: [
|
|
85
|
+
applyPlan: [
|
|
86
|
+
withDocumentBody(upsert(entity), provenanceBody(title, `${bootstrapProvenance(item.provider, relativePath, confidence)}${evidence.length > 0 ? ` Evidence: ${evidence.join("; ")}.` : ""}`)),
|
|
87
|
+
],
|
|
86
88
|
},
|
|
87
89
|
];
|
|
88
90
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent-claims.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/intent-claims.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"intent-claims.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/intent-claims.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,wBAAwB,EAGxB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAQpB,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAClE,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CAAC;AA0NF;;;;;;;GAOG;AAEH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,wBAAwB,EAClC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,GACpB,sBAAsB,CAmJxB"}
|