kibi-cli 2.21.2 → 2.22.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.
Files changed (113) hide show
  1. package/dist/cli-register-foundation.d.ts.map +1 -1
  2. package/dist/cli-register-foundation.js +1 -0
  3. package/dist/commands/check.d.ts +0 -1
  4. package/dist/commands/check.d.ts.map +1 -1
  5. package/dist/commands/check.js +47 -111
  6. package/dist/commands/doctor.d.ts.map +1 -1
  7. package/dist/commands/doctor.js +108 -6
  8. package/dist/commands/init-helpers.d.ts +16 -2
  9. package/dist/commands/init-helpers.d.ts.map +1 -1
  10. package/dist/commands/init-helpers.js +52 -10
  11. package/dist/commands/init.d.ts +1 -0
  12. package/dist/commands/init.d.ts.map +1 -1
  13. package/dist/commands/init.js +12 -1
  14. package/dist/commands/legacy-storage-migration.d.ts +46 -1
  15. package/dist/commands/legacy-storage-migration.d.ts.map +1 -1
  16. package/dist/commands/legacy-storage-migration.js +219 -9
  17. package/dist/commands/migrate.d.ts +37 -0
  18. package/dist/commands/migrate.d.ts.map +1 -1
  19. package/dist/commands/migrate.js +72 -188
  20. package/dist/commands/sync/manifest.d.ts.map +1 -1
  21. package/dist/commands/sync/manifest.js +9 -0
  22. package/dist/extractors/symbols-coordinator.js +1 -0
  23. package/dist/intent-search.d.ts.map +1 -1
  24. package/dist/intent-search.js +28 -6
  25. package/dist/operations/migration/inventory-rederive.d.ts +40 -1
  26. package/dist/operations/migration/inventory-rederive.d.ts.map +1 -1
  27. package/dist/operations/migration/inventory-rederive.js +99 -8
  28. package/dist/operations/migration/requirement-status.d.ts +25 -0
  29. package/dist/operations/migration/requirement-status.d.ts.map +1 -0
  30. package/dist/operations/migration/requirement-status.js +105 -0
  31. package/dist/operations/migration/schema6.d.ts +25 -0
  32. package/dist/operations/migration/schema6.d.ts.map +1 -1
  33. package/dist/operations/migration/schema6.js +265 -7
  34. package/dist/operations/migration/symbol-legacy-links.d.ts +51 -0
  35. package/dist/operations/migration/symbol-legacy-links.d.ts.map +1 -0
  36. package/dist/operations/migration/symbol-legacy-links.js +319 -0
  37. package/dist/operations/mutation/context-warning.d.ts +12 -2
  38. package/dist/operations/mutation/context-warning.d.ts.map +1 -1
  39. package/dist/operations/mutation/context-warning.js +6 -6
  40. package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
  41. package/dist/operations/mutation/source-authoring.js +130 -35
  42. package/dist/operations/mutation/types.d.ts +2 -1
  43. package/dist/operations/mutation/types.d.ts.map +1 -1
  44. package/dist/operations/mutation/upsert.d.ts +17 -2
  45. package/dist/operations/mutation/upsert.d.ts.map +1 -1
  46. package/dist/operations/mutation/upsert.js +28 -11
  47. package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
  48. package/dist/operations/mutation/validate-upsert.js +40 -8
  49. package/dist/operations/mutation/validation.d.ts.map +1 -1
  50. package/dist/operations/mutation/validation.js +43 -1
  51. package/dist/operations/planning/apply-plan.d.ts.map +1 -1
  52. package/dist/operations/planning/apply-plan.js +34 -10
  53. package/dist/operations/semantic-advisor/ingestion-boundary.d.ts.map +1 -1
  54. package/dist/operations/semantic-advisor/ingestion-boundary.js +25 -1
  55. package/dist/operations/semantic-advisor/stored-ledger-drift.d.ts +19 -0
  56. package/dist/operations/semantic-advisor/stored-ledger-drift.d.ts.map +1 -0
  57. package/dist/operations/semantic-advisor/stored-ledger-drift.js +78 -0
  58. package/dist/public/impact/diagnostics.d.ts.map +1 -1
  59. package/dist/public/impact/diagnostics.js +24 -14
  60. package/dist/public/operations/catalog.d.ts +3 -3
  61. package/dist/public/operations/check-executor.d.ts.map +1 -1
  62. package/dist/public/operations/check-executor.js +3 -0
  63. package/dist/public/operations/contracts.d.ts.map +1 -1
  64. package/dist/public/operations/contracts.js +6 -1
  65. package/dist/public/operations/decision-firmness.d.ts +3 -1
  66. package/dist/public/operations/decision-firmness.d.ts.map +1 -1
  67. package/dist/public/operations/decision-firmness.js +13 -3
  68. package/dist/public/operations/discovery-executors.d.ts +2 -0
  69. package/dist/public/operations/discovery-executors.d.ts.map +1 -1
  70. package/dist/public/operations/discovery-executors.js +24 -2
  71. package/dist/public/operations/migration-plan.d.ts +15 -0
  72. package/dist/public/operations/migration-plan.d.ts.map +1 -1
  73. package/dist/public/operations/migration-plan.js +130 -17
  74. package/dist/public/operations/result-envelope.d.ts.map +1 -1
  75. package/dist/public/operations/result-envelope.js +27 -1
  76. package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
  77. package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
  78. package/dist/public/operations/specs/check-rules.generated.js +2 -1
  79. package/dist/public/operations/specs/check.d.ts +1 -1
  80. package/dist/public/operations/specs/planning.d.ts +2 -2
  81. package/dist/public/operations/specs/planning.js +2 -2
  82. package/dist/public/operations/specs/semantic.d.ts.map +1 -1
  83. package/dist/public/operations/specs/semantic.js +26 -1
  84. package/dist/public/operations/symbol-granularity-check.d.ts +18 -0
  85. package/dist/public/operations/symbol-granularity-check.d.ts.map +1 -0
  86. package/dist/public/operations/symbol-granularity-check.js +175 -0
  87. package/dist/public/skills/kibi-usage/SKILL.md +8 -3
  88. package/dist/public/symbol-granularity.d.ts +17 -0
  89. package/dist/public/symbol-granularity.d.ts.map +1 -1
  90. package/dist/public/symbol-granularity.js +21 -0
  91. package/dist/traceability/evidence-model.d.ts +7 -3
  92. package/dist/traceability/evidence-model.d.ts.map +1 -1
  93. package/dist/traceability/staged-symbols-manifest.js +6 -5
  94. package/dist/traceability/validate.d.ts +14 -1
  95. package/dist/traceability/validate.d.ts.map +1 -1
  96. package/dist/traceability/validate.js +41 -0
  97. package/dist/utils/rule-registry.generated.d.ts +5 -0
  98. package/dist/utils/rule-registry.generated.d.ts.map +1 -1
  99. package/dist/utils/rule-registry.generated.js +6 -0
  100. package/package.json +3 -3
  101. package/src/public/impact/diagnostics.ts +29 -17
  102. package/src/public/operations/check-executor.ts +7 -0
  103. package/src/public/operations/contracts.ts +6 -1
  104. package/src/public/operations/decision-firmness.ts +18 -2
  105. package/src/public/operations/discovery-executors.ts +28 -2
  106. package/src/public/operations/migration-plan.ts +147 -20
  107. package/src/public/operations/result-envelope.ts +34 -1
  108. package/src/public/operations/specs/check-rules.generated.ts +2 -1
  109. package/src/public/operations/specs/planning.ts +2 -2
  110. package/src/public/operations/specs/semantic.ts +37 -2
  111. package/src/public/operations/symbol-granularity-check.ts +233 -0
  112. package/src/public/skills/kibi-usage/SKILL.md +8 -3
  113. package/src/public/symbol-granularity.ts +37 -0
@@ -0,0 +1,319 @@
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
+ import { createHash } from "node:crypto";
19
+ import { existsSync, readFileSync } from "node:fs";
20
+ import path from "node:path";
21
+ import { isDeepStrictEqual } from "node:util";
22
+ import { load as parseYAML } from "js-yaml";
23
+ import { createTsMorphSourceAnalysisProvider } from "../../extractors/symbols-ts.js";
24
+ import { coarseLinkBehavioralNames, isTraceabilityRelationshipType, } from "../../public/symbol-granularity.js";
25
+ import { extractSymbolsFromStagedFile, } from "../../traceability/symbol-extract.js";
26
+ import { KB_PATHS } from "../../utils/kb-paths.js";
27
+ import { writeFileAtomically } from "./kb-sources.js";
28
+ /**
29
+ * Mark the coarse traceability links of a symbols manifest
30
+ * `granularity_reason: legacy-link`.
31
+ *
32
+ * A link is coarse by the staged granularity gate's own rule
33
+ * (`coarseLinkBehavioralNames`): the source declares behavioral symbols
34
+ * narrower than the manifest symbol, so `kibi check --staged` would block the
35
+ * first commit that touches it. The pass is idempotent and independent of
36
+ * the schema version: it marks whatever the current rule calls coarse and
37
+ * has no reason yet, and a second run finds nothing.
38
+ */
39
+ /** Automatic migration action code of the legacy-link pass. */
40
+ // implements REQ-cli-schema-migration
41
+ export const SYMBOL_LEGACY_LINK_MARK_CODE = "symbol_legacy_link_mark";
42
+ // implements REQ-cli-schema-migration
43
+ export const SYMBOL_LEGACY_LINK_MARK_ACTION_ID = "symbol-legacy-link-mark";
44
+ function isRecord(value) {
45
+ return value !== null && typeof value === "object" && !Array.isArray(value);
46
+ }
47
+ function linkType(link) {
48
+ // A bare string link compiles as `implements`; a typed link keeps its type.
49
+ if (typeof link === "string")
50
+ return "implements";
51
+ return isRecord(link) ? link.type : undefined;
52
+ }
53
+ /** True when the record compiles at least one traceability relationship. */
54
+ function hasTraceabilityRelationship(record) {
55
+ const links = Array.isArray(record.links) ? record.links : [];
56
+ const relationships = Array.isArray(record.relationships)
57
+ ? record.relationships
58
+ : [];
59
+ return [
60
+ ...links.map(linkType),
61
+ ...relationships.map((relationship) => isRecord(relationship) ? relationship.type : undefined),
62
+ ].some(isTraceabilityRelationshipType);
63
+ }
64
+ /**
65
+ * The analyzer the staged gate uses (the built-in ts-morph provider), built
66
+ * once per pass: a provider per file would rebuild the TypeScript project for
67
+ * every source the manifest names.
68
+ */
69
+ function sharedAnalyzer() {
70
+ let provider = null;
71
+ return (filePath, content) => {
72
+ provider ??= createTsMorphSourceAnalysisProvider();
73
+ return provider.supportsFile(filePath)
74
+ ? provider.analyzeText(filePath, content)
75
+ : null;
76
+ };
77
+ }
78
+ function sourceSymbols(workspaceRoot, sourceFile, analyzeText) {
79
+ const absolutePath = path.isAbsolute(sourceFile)
80
+ ? sourceFile
81
+ : path.join(workspaceRoot, sourceFile);
82
+ if (!existsSync(absolutePath))
83
+ return [];
84
+ try {
85
+ return extractSymbolsFromStagedFile({
86
+ path: sourceFile,
87
+ status: "M",
88
+ hunkRanges: [{ start: 1, end: Number.MAX_SAFE_INTEGER }],
89
+ content: readFileSync(absolutePath, "utf8"),
90
+ }, undefined, { analyzeText });
91
+ }
92
+ catch {
93
+ return [];
94
+ }
95
+ }
96
+ function escapeRegExp(value) {
97
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
98
+ }
99
+ /**
100
+ * True when `title` is an exported function, variable (not a class
101
+ * expression), interface, type or enum declaration of the source file
102
+ * and no class of that name exists. The extractor then reports `title`
103
+ * itself and no `title.*` member, so nothing is narrower and the link is not
104
+ * coarse: the full analysis reaches the same answer, only much slower, and a
105
+ * manifest names hundreds of such functions.
106
+ */
107
+ function declaresMemberlessSymbol(workspaceRoot, sourceFile, title, cache) {
108
+ if (!/^[A-Za-z_$][\w$]*$/.test(title))
109
+ return false;
110
+ let content = cache.get(sourceFile);
111
+ if (content === undefined) {
112
+ try {
113
+ content = readFileSync(path.resolve(workspaceRoot, sourceFile), "utf8");
114
+ }
115
+ catch {
116
+ content = null;
117
+ }
118
+ cache.set(sourceFile, content);
119
+ }
120
+ if (content === null)
121
+ return false;
122
+ const name = escapeRegExp(title);
123
+ if (new RegExp(`\\bclass\\s+${name}\\b`).test(content))
124
+ return false;
125
+ return [
126
+ `^export\\s+(?:default\\s+)?(?:async\\s+)?function\\s*\\*?\\s*${name}\\s*[(<]`,
127
+ `^export\\s+(?:declare\\s+)?(?:interface|type|enum|const\\s+enum)\\s+${name}\\b`,
128
+ // A variable, unless its initializer is a class expression (members).
129
+ `^export\\s+(?:const|let|var)\\s+${name}\\s*(?::[^=\\n]*)?=\\s*(?!class\\b)\\S`,
130
+ ].some((pattern) => new RegExp(pattern, "m").test(content));
131
+ }
132
+ function digest(content) {
133
+ return createHash("sha256").update(content, "utf8").digest("hex");
134
+ }
135
+ /**
136
+ * The coarse links of `manifestPath` (default `.kb/symbols.yaml`) that carry
137
+ * no granularity_reason yet. Read-only.
138
+ */
139
+ // implements REQ-cli-schema-migration, REQ-symbol-behavioral-anchors
140
+ export function planSymbolLegacyLinks(workspaceRoot, manifestPath = KB_PATHS.symbolsManifest) {
141
+ const absolute = path.resolve(workspaceRoot, manifestPath);
142
+ let content;
143
+ try {
144
+ content = readFileSync(absolute, "utf8");
145
+ }
146
+ catch {
147
+ return { manifestPath, manifestHash: null, targets: [] };
148
+ }
149
+ const empty = { manifestPath, manifestHash: digest(content), targets: [] };
150
+ let parsed;
151
+ try {
152
+ parsed = parseYAML(content);
153
+ }
154
+ catch {
155
+ // A malformed manifest fails sync with its own diagnostic.
156
+ return empty;
157
+ }
158
+ if (!isRecord(parsed) || !Array.isArray(parsed.symbols))
159
+ return empty;
160
+ const targets = [];
161
+ const symbolsByFile = new Map();
162
+ const analyzeText = sharedAnalyzer();
163
+ const sourceText = new Map();
164
+ for (const record of parsed.symbols) {
165
+ if (!isRecord(record))
166
+ continue;
167
+ if (typeof record.id !== "string" ||
168
+ typeof record.title !== "string" ||
169
+ typeof record.sourceFile !== "string")
170
+ continue;
171
+ if (record.granularity_reason !== undefined)
172
+ continue;
173
+ if (!hasTraceabilityRelationship(record))
174
+ continue;
175
+ if (declaresMemberlessSymbol(workspaceRoot, record.sourceFile, record.title, sourceText))
176
+ continue;
177
+ let symbols = symbolsByFile.get(record.sourceFile);
178
+ if (symbols === undefined) {
179
+ symbols = sourceSymbols(workspaceRoot, record.sourceFile, analyzeText);
180
+ symbolsByFile.set(record.sourceFile, symbols);
181
+ }
182
+ const granularSymbols = coarseLinkBehavioralNames(record.title, symbols);
183
+ if (granularSymbols.length === 0)
184
+ continue;
185
+ targets.push({
186
+ id: record.id,
187
+ title: record.title,
188
+ sourceFile: record.sourceFile,
189
+ granularSymbols,
190
+ });
191
+ }
192
+ return { manifestPath, manifestHash: digest(content), targets };
193
+ }
194
+ function unquoted(value) {
195
+ const trimmed = value.trim();
196
+ if (trimmed.length >= 2 &&
197
+ (trimmed.startsWith('"') || trimmed.startsWith("'")) &&
198
+ trimmed.endsWith(trimmed[0] ?? "")) {
199
+ return trimmed.slice(1, -1);
200
+ }
201
+ return trimmed;
202
+ }
203
+ /**
204
+ * Insert `granularity_reason: legacy-link` into each listed symbol entry,
205
+ * leaving every other byte of the manifest as it was.
206
+ */
207
+ function withLegacyReasons(content, symbolIds) {
208
+ const lines = content.split("\n");
209
+ const output = [];
210
+ let activeId = null;
211
+ let activeHasReason = false;
212
+ let activePropertyIndent = "";
213
+ const flushLegacyReason = () => {
214
+ if (activeId !== null &&
215
+ symbolIds.has(activeId) &&
216
+ !activeHasReason &&
217
+ activePropertyIndent.length > 0) {
218
+ output.push(`${activePropertyIndent}granularity_reason: legacy-link`);
219
+ activeHasReason = true;
220
+ }
221
+ };
222
+ for (const line of lines) {
223
+ const idMatch = line.match(/^(\s*)-\s+id:\s+(.+?)\s*$/);
224
+ if (idMatch) {
225
+ flushLegacyReason();
226
+ activeId = unquoted(idMatch[2] ?? "");
227
+ activeHasReason = false;
228
+ activePropertyIndent = `${idMatch[1] ?? ""} `;
229
+ }
230
+ if (activeId !== null && /^\s+granularity_reason:\s+/.test(line)) {
231
+ activeHasReason = true;
232
+ }
233
+ if (activeId !== null &&
234
+ symbolIds.has(activeId) &&
235
+ !activeHasReason &&
236
+ /^\s+status:\s+/.test(line)) {
237
+ const indent = line.match(/^\s*/)?.[0] ?? "";
238
+ output.push(`${indent}granularity_reason: legacy-link`);
239
+ activeHasReason = true;
240
+ }
241
+ output.push(line);
242
+ }
243
+ flushLegacyReason();
244
+ return output.join("\n");
245
+ }
246
+ /**
247
+ * Mark the coarse links found by `planSymbolLegacyLinks`. With
248
+ * `expectedHash` (a migration plan's evidence), the manifest must still hold
249
+ * the bytes the plan was read from; a manifest whose planned links are all
250
+ * marked already is left alone, so the pass is idempotent. Returns the ids
251
+ * marked, and the planned ones that could not be marked in place (an entry
252
+ * whose `id` is not its first key, for example).
253
+ */
254
+ // implements REQ-cli-schema-migration, REQ-symbol-behavioral-anchors
255
+ export function applySymbolLegacyLinks(workspaceRoot, options = {}) {
256
+ const plan = planSymbolLegacyLinks(workspaceRoot, options.manifestPath ?? KB_PATHS.symbolsManifest);
257
+ if (plan.targets.length === 0)
258
+ return { marked: [], unmarked: [] };
259
+ if (options.expectedHash !== undefined &&
260
+ plan.manifestHash !== options.expectedHash) {
261
+ throw new Error(`${plan.manifestPath} changed since planning; rerun kibi migrate and approve the new plan.`);
262
+ }
263
+ const ids = new Set(plan.targets
264
+ .map((target) => target.id)
265
+ .filter((id) => options.expectedIds === undefined || options.expectedIds.includes(id)));
266
+ if (ids.size === 0)
267
+ return { marked: [], unmarked: [] };
268
+ const absolute = path.resolve(workspaceRoot, plan.manifestPath);
269
+ const content = readFileSync(absolute, "utf8");
270
+ const next = withLegacyReasons(content, ids);
271
+ const marked = markedIds(content, next, ids);
272
+ if (marked === null)
273
+ throw new Error(`${plan.manifestPath}: legacy-link reasons could not be added without changing other symbol fields; add granularity_reason: legacy-link by hand.`);
274
+ if (marked.length > 0)
275
+ writeFileAtomically(absolute, next);
276
+ return {
277
+ marked,
278
+ unmarked: [...ids].filter((id) => !marked.includes(id)).sort(),
279
+ };
280
+ }
281
+ /**
282
+ * The ids whose only change between `before` and `after` is a new
283
+ * `granularity_reason: legacy-link`, or null when anything else changed.
284
+ */
285
+ function markedIds(before, after, ids) {
286
+ try {
287
+ const previous = parseYAML(before);
288
+ const next = parseYAML(after);
289
+ if (!Array.isArray(previous.symbols) ||
290
+ !Array.isArray(next.symbols) ||
291
+ previous.symbols.length !== next.symbols.length)
292
+ return null;
293
+ const marked = [];
294
+ for (const [index, entry] of next.symbols.entries()) {
295
+ const old = previous.symbols[index];
296
+ if (!isRecord(entry) || !isRecord(old)) {
297
+ if (!isDeepStrictEqual(entry, old))
298
+ return null;
299
+ continue;
300
+ }
301
+ const { granularity_reason: reason, ...rest } = entry;
302
+ const { granularity_reason: oldReason, ...oldRest } = old;
303
+ if (!isDeepStrictEqual(rest, oldRest))
304
+ return null;
305
+ if (reason === oldReason)
306
+ continue;
307
+ if (reason !== "legacy-link" ||
308
+ oldReason !== undefined ||
309
+ typeof entry.id !== "string" ||
310
+ !ids.has(entry.id))
311
+ return null;
312
+ marked.push(entry.id);
313
+ }
314
+ return marked.sort();
315
+ }
316
+ catch {
317
+ return null;
318
+ }
319
+ }
@@ -1,13 +1,23 @@
1
1
  import type { UpsertInput } from "./types.js";
2
+ /**
3
+ * Where the upsert's authored document lives. `writtenPath` is the file a
4
+ * real write just published; `targetPath` is the file a write would update
5
+ * (a dry run resolves it the same way the write does, because the preview
6
+ * entity's `source` is the runtime marker rather than the authored file).
7
+ */
8
+ export interface UpsertDocumentPaths {
9
+ readonly writtenPath?: string | undefined;
10
+ readonly targetPath?: string | undefined;
11
+ }
2
12
  /**
3
13
  * The body the authored document has, or will have, after this upsert: the
4
14
  * written file when there is one, the supplied body, the preserved body of
5
15
  * the entity's existing document, or the default a new requirement gets.
6
16
  */
7
- export declare function upsertDocumentBody(input: UpsertInput, entity: Readonly<Record<string, unknown>>, workspaceRoot: string, writtenPath?: string): string;
17
+ export declare function upsertDocumentBody(input: UpsertInput, entity: Readonly<Record<string, unknown>>, workspaceRoot: string, paths?: UpsertDocumentPaths): string;
8
18
  /**
9
19
  * kb_upsert warning for a written entity whose body lacks context. The same
10
20
  * finding blocks `kb_check` as entity-context-missing, so agents see it first.
11
21
  */
12
- export declare function entityContextWarnings(input: UpsertInput, entity: Readonly<Record<string, unknown>>, workspaceRoot: string, writtenPath?: string): readonly string[];
22
+ export declare function entityContextWarnings(input: UpsertInput, entity: Readonly<Record<string, unknown>>, workspaceRoot: string, paths?: UpsertDocumentPaths): readonly string[];
13
23
  //# sourceMappingURL=context-warning.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-warning.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/context-warning.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAgB9C;;;;GAIG;AAEH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAYR;AAED;;;GAGG;AAEH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,GACnB,SAAS,MAAM,EAAE,CA2BnB"}
1
+ {"version":3,"file":"context-warning.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/context-warning.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAgB9C;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C;AAED;;;;GAIG;AAEH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,KAAK,GAAE,mBAAwB,GAC9B,MAAM,CAYR;AAED;;;GAGG;AAEH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,KAAK,GAAE,mBAAwB,GAC9B,SAAS,MAAM,EAAE,CA2BnB"}
@@ -20,15 +20,15 @@ function readBody(workspaceRoot, source) {
20
20
  * the entity's existing document, or the default a new requirement gets.
21
21
  */
22
22
  // implements REQ-kb-entity-body-context
23
- export function upsertDocumentBody(input, entity, workspaceRoot, writtenPath) {
24
- if (writtenPath !== undefined) {
25
- const written = readBody(workspaceRoot, writtenPath);
23
+ export function upsertDocumentBody(input, entity, workspaceRoot, paths = {}) {
24
+ if (paths.writtenPath !== undefined) {
25
+ const written = readBody(workspaceRoot, paths.writtenPath);
26
26
  if (written !== undefined)
27
27
  return written;
28
28
  }
29
29
  if (input.document?.body !== undefined)
30
30
  return input.document.body;
31
- const existing = readBody(workspaceRoot, input.document?.path ?? entity.source);
31
+ const existing = readBody(workspaceRoot, input.document?.path ?? paths.targetPath ?? entity.source);
32
32
  if (existing !== undefined)
33
33
  return existing;
34
34
  return input.type === "req" ? `${String(entity.semantic_text ?? "")}\n` : "";
@@ -38,8 +38,8 @@ export function upsertDocumentBody(input, entity, workspaceRoot, writtenPath) {
38
38
  * finding blocks `kb_check` as entity-context-missing, so agents see it first.
39
39
  */
40
40
  // implements REQ-kb-entity-body-context
41
- export function entityContextWarnings(input, entity, workspaceRoot, writtenPath) {
42
- const body = upsertDocumentBody(input, entity, workspaceRoot, writtenPath);
41
+ export function entityContextWarnings(input, entity, workspaceRoot, paths = {}) {
42
+ const body = upsertDocumentBody(input, entity, workspaceRoot, paths);
43
43
  const semanticText = typeof entity.semantic_text === "string" && entity.semantic_text.trim()
44
44
  ? entity.semantic_text
45
45
  : input.type === "req"
@@ -1 +1 @@
1
- {"version":3,"file":"source-authoring.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/source-authoring.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"source-authoring.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/source-authoring.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAOjF,OAAO,KAAK,EAAqB,WAAW,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC,CAAC;AAmBH,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,IAAI,CAiBN;AAED,KAAK,SAAS,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAExD,8EAA8E;AAE9E,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAOpE;AAED;;;;GAIG;AAEH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,SAAS,GAAG,IAAI,GACtB,IAAI,CAON;AAeD;;;;GAIG;AAEH,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,GACnB,IAAI,CAMN;AAED;;;;;;GAMG;AAEH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CA8BT;AAgBD,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,MAAM,CAqCR;AAED,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,MAAM,CAoBR;AAkCD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAYpB;AAED,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,GACX,OAAO,CAET;AAyMD,uFAAuF;AAEvF,eAAO,MAAM,uBAAuB,uGAM1B,CAAC;AA8BX,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,OAAO,GACZ,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAiCzC;AAwRD,wBAAgB,oBAAoB,CAClC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,GACtB;IAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CA6C7C;AAED;;;;;;;GAOG;AACH,wBAAgB,kCAAkC,CAChD,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7D;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CA4DpC;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7D;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAiEpC;AAED;;;;GAIG;AAEH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,YAAY,EAAE,MAAM,GACnB,MAAM,CAsBR;AAED;;;;;;;GAOG;AAEH,wBAAgB,gBAAgB,CAC9B,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAaT;AAED,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC5C,OAAO,CAAC,EAAE,gBAAgB,EAC1B,sBAAsB,CAAC,EAAE,MAAM,GAC9B,OAAO,CAAC;IACT,OAAO,EAAE,kBAAkB,CAAC;IAC5B,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B,GAAG,IAAI,CAAC,CA+IR;AAED,uEAAuE;AACvE,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC3C,MAAM,CAOR"}
@@ -5,7 +5,7 @@ import fs from "node:fs";
5
5
  import path from "node:path";
6
6
  import { isDeepStrictEqual } from "node:util";
7
7
  import { dump as dumpYaml, load as loadYaml } from "js-yaml";
8
- import { parseDocument, stringify } from "yaml";
8
+ import { isCollection, isMap, isNode, isScalar, parseDocument, stringify, } from "yaml";
9
9
  import { OperationError } from "../../cli-errors.js";
10
10
  import { requirementSemanticText } from "../../extractors/markdown.js";
11
11
  import { canonicalFilesystemPath } from "../../utils/canonical-path.js";
@@ -169,22 +169,32 @@ export function normalizeAuthoredSourcePath(workspaceRoot, source) {
169
169
  .relative(path.resolve(workspaceRoot), resolveContainedSourcePath(workspaceRoot, relative))
170
170
  .replaceAll(path.sep, "/");
171
171
  }
172
- function bodyAndFrontmatter(content) {
172
+ /** The raw front matter block of a Markdown document, split at its fences. */
173
+ function frontmatterBlock(content) {
173
174
  if (!content.startsWith("---"))
174
- return { frontmatter: {}, body: content };
175
+ return undefined;
175
176
  const firstEnd = content.indexOf("\n", 3);
176
177
  if (firstEnd < 0)
177
- return { frontmatter: {}, body: content };
178
+ return undefined;
178
179
  const marker = content.indexOf("\n---", firstEnd);
179
180
  if (marker < 0)
181
+ return undefined;
182
+ return {
183
+ opening: content.slice(0, firstEnd + 1),
184
+ raw: content.slice(firstEnd + 1, marker),
185
+ body: content.slice(marker + "\n---".length),
186
+ };
187
+ }
188
+ function bodyAndFrontmatter(content) {
189
+ const block = frontmatterBlock(content);
190
+ if (block === undefined)
180
191
  return { frontmatter: {}, body: content };
181
- const raw = content.slice(firstEnd + 1, marker);
182
- const parsed = loadYaml(raw);
192
+ const parsed = loadYaml(block.raw);
183
193
  return {
184
194
  frontmatter: parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)
185
195
  ? parsed
186
196
  : {},
187
- body: content.slice(marker + "\n---".length),
197
+ body: block.body,
188
198
  };
189
199
  }
190
200
  /**
@@ -238,6 +248,105 @@ function sourcePath(context, input, entity, existing) {
238
248
  }
239
249
  return resolveContainedSourcePath(context.workspaceRoot, relative);
240
250
  }
251
+ /**
252
+ * Front matter keys an upsert never writes: runtime provenance/timestamps
253
+ * belong to the compiled entity, not to the authored source artifact, and
254
+ * relationships live in `links`/shards. Keeping them out also makes the
255
+ * source diff deterministic across CLI and MCP transports.
256
+ */
257
+ const UNAUTHORED_FRONTMATTER_KEYS = new Set([
258
+ "id",
259
+ "type",
260
+ "source",
261
+ "links",
262
+ "relationships",
263
+ "created_at",
264
+ "updated_at",
265
+ ]);
266
+ /** The front matter values an upsert of `entity` sets, in write order. */
267
+ function entityFrontmatterUpdates(entity, existing, body) {
268
+ const updates = Object.fromEntries(Object.entries(entity).filter(([key, value]) => value !== undefined && !UNAUTHORED_FRONTMATTER_KEYS.has(key)));
269
+ updates.id = entity.id;
270
+ if (updates.title === undefined && existing.title === undefined) {
271
+ updates.title = entity.id;
272
+ }
273
+ updates.type = entity.type;
274
+ // The checked meaning is always stated, never derived from a body that now
275
+ // also carries context sections.
276
+ const semanticText = updates.semantic_text ?? existing.semantic_text;
277
+ if (entity.type === "req" &&
278
+ (typeof semanticText !== "string" || semanticText.trim() === "")) {
279
+ const derived = requirementSemanticText(body);
280
+ if (derived !== "")
281
+ updates.semantic_text = derived;
282
+ }
283
+ return updates;
284
+ }
285
+ /**
286
+ * Apply `updates` to an existing front matter block without re-serializing
287
+ * it: only keys whose value actually changes are rewritten (or appended), so
288
+ * every untouched key keeps its authored bytes (quoting, timestamps, flow
289
+ * lists, indentation, comments). Returns undefined when the block is not a
290
+ * plain block mapping that can be patched in place.
291
+ */
292
+ // implements REQ-core-persistence
293
+ function patchFrontmatter(raw, loaded, updates) {
294
+ const doc = parseDocument(raw);
295
+ if (doc.errors.length > 0)
296
+ return undefined;
297
+ const contents = doc.contents;
298
+ if (contents === null && raw.trim() !== "")
299
+ return undefined;
300
+ if (contents !== null && (!isMap(contents) || contents.flow)) {
301
+ return undefined;
302
+ }
303
+ const pairs = contents === null ? [] : contents.items;
304
+ const current = (doc.toJS() ?? {});
305
+ const edits = [];
306
+ const appended = [];
307
+ for (const [key, value] of Object.entries(updates)) {
308
+ const pair = pairs.find((candidate) => isScalar(candidate.key) && String(candidate.key.value) === key);
309
+ if (pair !== undefined &&
310
+ (isDeepStrictEqual(current[key], value) ||
311
+ isDeepStrictEqual(loaded[key], value))) {
312
+ continue;
313
+ }
314
+ const valueNode = pair?.value;
315
+ const flow = isCollection(valueNode) && valueNode.flow === true;
316
+ const text = dumpYaml({ [key]: value }, {
317
+ noRefs: true,
318
+ lineWidth: -1,
319
+ sortKeys: false,
320
+ ...(flow ? { flowLevel: 1 } : {}),
321
+ }).replace(/\n$/, "");
322
+ if (pair === undefined) {
323
+ appended.push(text);
324
+ continue;
325
+ }
326
+ const keyRange = isScalar(pair.key) ? pair.key.range : undefined;
327
+ if (!keyRange)
328
+ return undefined;
329
+ const start = keyRange[0];
330
+ let end = isNode(valueNode) && valueNode.range ? valueNode.range[1] : keyRange[2];
331
+ // `key:` with no value: replace through the end of the key's line.
332
+ if (end <= keyRange[1]) {
333
+ const lineEnd = raw.indexOf("\n", keyRange[1]);
334
+ end = lineEnd < 0 ? raw.length : lineEnd;
335
+ }
336
+ while (end > start && /[\r\n]/.test(raw[end - 1] ?? ""))
337
+ end -= 1;
338
+ edits.push({ start, end, text });
339
+ }
340
+ let patched = raw;
341
+ for (const edit of edits.sort((left, right) => right.start - left.start)) {
342
+ patched = `${patched.slice(0, edit.start)}${edit.text}${patched.slice(edit.end)}`;
343
+ }
344
+ if (appended.length > 0) {
345
+ const separator = patched === "" || patched.endsWith("\n") ? "" : "\n";
346
+ patched = `${patched}${separator}${appended.join("\n")}`;
347
+ }
348
+ return patched;
349
+ }
241
350
  function renderEntityDocument(input, entity, existingContent) {
242
351
  const existing = existingContent
243
352
  ? bodyAndFrontmatter(existingContent)
@@ -249,35 +358,21 @@ function renderEntityDocument(input, entity, existingContent) {
249
358
  : input.type === "req"
250
359
  ? `${String(entity.semantic_text ?? "").trim()}\n`
251
360
  : "\n";
252
- const frontmatter = {
253
- ...existing.frontmatter,
254
- ...Object.fromEntries(Object.entries(entity).filter(([key]) =>
255
- // Runtime provenance/timestamps belong to the compiled entity, not to
256
- // the authored source artifact. Keeping them out also makes the source
257
- // diff deterministic across CLI and MCP transports.
258
- ![
259
- "id",
260
- "type",
261
- "source",
262
- "links",
263
- "relationships",
264
- "created_at",
265
- "updated_at",
266
- ].includes(key))),
267
- };
268
- frontmatter.id = entity.id;
269
- frontmatter.title ??= entity.id;
270
- frontmatter.type = entity.type;
271
- // The checked meaning is always stated, never derived from a body that now
272
- // also carries context sections.
273
- if (entity.type === "req" &&
274
- (typeof frontmatter.semantic_text !== "string" ||
275
- frontmatter.semantic_text.trim() === "")) {
276
- const derived = requirementSemanticText(body);
277
- if (derived !== "")
278
- frontmatter.semantic_text = derived;
361
+ const updates = entityFrontmatterUpdates(entity, existing.frontmatter, body);
362
+ const bodySuffix = `${body.startsWith("\n") ? "" : "\n"}${body}`;
363
+ // An existing document keeps its authored front matter bytes; only the
364
+ // keys this upsert changes are rewritten.
365
+ const block = existingContent !== undefined
366
+ ? frontmatterBlock(existingContent)
367
+ : undefined;
368
+ if (block !== undefined) {
369
+ const patched = patchFrontmatter(block.raw, existing.frontmatter, updates);
370
+ if (patched !== undefined) {
371
+ return `${block.opening}${patched}\n---${bodySuffix}`;
372
+ }
279
373
  }
280
- return `---\n${dumpYaml(frontmatter, { noRefs: true, lineWidth: -1, sortKeys: false })}---${body.startsWith("\n") ? "" : "\n"}${body}`;
374
+ const frontmatter = { ...existing.frontmatter, ...updates };
375
+ return `---\n${dumpYaml(frontmatter, { noRefs: true, lineWidth: -1, sortKeys: false })}---${bodySuffix}`;
281
376
  }
282
377
  /** Generated coordinate fields belong exclusively to `.kb/symbol-coordinates.yaml`. */
283
378
  // implements REQ-generated-coordinate-persistence
@@ -52,7 +52,8 @@ export type UpsertPayload = {
52
52
  readonly updated: number;
53
53
  readonly relationships_created: number;
54
54
  readonly warnings: readonly string[];
55
- readonly semanticAdvisor: SemanticAdvisorReceipt;
55
+ /** The requirement semantic advisor receipt; absent for other entity types. */
56
+ readonly semanticAdvisor?: SemanticAdvisorReceipt;
56
57
  /**
57
58
  * For a fact that carries claim_text: the stored claim_key, derived from
58
59
  * claim_text when the payload did not supply it, so the writer learns the
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/types.ts"],"names":[],"mappings":"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"}