kibi-cli 0.2.3 → 0.2.5
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.js +3 -28
- package/dist/commands/aggregated-checks.d.ts +4 -1
- package/dist/commands/aggregated-checks.d.ts.map +1 -1
- package/dist/commands/aggregated-checks.js +13 -3
- package/dist/commands/branch.d.ts.map +1 -1
- package/dist/commands/branch.js +3 -41
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +54 -44
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +0 -27
- package/dist/commands/gc.d.ts.map +1 -1
- package/dist/commands/gc.js +2 -51
- package/dist/commands/init-helpers.d.ts.map +1 -1
- package/dist/commands/init-helpers.js +23 -36
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +0 -27
- package/dist/commands/query.d.ts.map +1 -1
- package/dist/commands/query.js +7 -288
- package/dist/commands/sync/cache.d.ts +13 -0
- package/dist/commands/sync/cache.d.ts.map +1 -0
- package/dist/commands/sync/cache.js +76 -0
- package/dist/commands/sync/discovery.d.ts +8 -0
- package/dist/commands/sync/discovery.d.ts.map +1 -0
- package/dist/commands/sync/discovery.js +50 -0
- package/dist/commands/sync/extraction.d.ts +11 -0
- package/dist/commands/sync/extraction.d.ts.map +1 -0
- package/dist/commands/sync/extraction.js +69 -0
- package/dist/commands/sync/manifest.d.ts +5 -0
- package/dist/commands/sync/manifest.d.ts.map +1 -0
- package/dist/commands/sync/manifest.js +118 -0
- package/dist/commands/sync/persistence.d.ts +16 -0
- package/dist/commands/sync/persistence.d.ts.map +1 -0
- package/dist/commands/sync/persistence.js +188 -0
- package/dist/commands/sync/staging.d.ts +4 -0
- package/dist/commands/sync/staging.d.ts.map +1 -0
- package/dist/commands/sync/staging.js +86 -0
- package/dist/commands/sync.d.ts +2 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +69 -501
- package/dist/extractors/manifest.d.ts +0 -1
- package/dist/extractors/manifest.d.ts.map +1 -1
- package/dist/extractors/manifest.js +39 -48
- package/dist/extractors/markdown.d.ts +0 -1
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +16 -49
- package/dist/extractors/relationships.d.ts +39 -0
- package/dist/extractors/relationships.d.ts.map +1 -0
- package/dist/extractors/relationships.js +137 -0
- package/dist/extractors/symbols-coordinator.d.ts.map +1 -1
- package/dist/extractors/symbols-coordinator.js +0 -27
- package/dist/extractors/symbols-ts.d.ts.map +1 -1
- package/dist/extractors/symbols-ts.js +0 -27
- package/dist/kb/target-resolver.d.ts +80 -0
- package/dist/kb/target-resolver.d.ts.map +1 -0
- package/dist/kb/target-resolver.js +313 -0
- package/dist/prolog/codec.d.ts +63 -0
- package/dist/prolog/codec.d.ts.map +1 -0
- package/dist/prolog/codec.js +434 -0
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +0 -27
- package/dist/public/extractors/symbols-coordinator.d.ts.map +1 -1
- package/dist/public/extractors/symbols-coordinator.js +0 -27
- package/dist/public/prolog/index.d.ts.map +1 -1
- package/dist/public/prolog/index.js +0 -27
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +0 -27
- package/dist/public/schemas/relationship.d.ts.map +1 -1
- package/dist/public/schemas/relationship.js +0 -27
- package/dist/query/service.d.ts +35 -0
- package/dist/query/service.d.ts.map +1 -0
- package/dist/query/service.js +149 -0
- package/dist/relationships/shards.d.ts +68 -0
- package/dist/relationships/shards.d.ts.map +1 -0
- package/dist/relationships/shards.js +263 -0
- package/dist/traceability/git-staged.d.ts +4 -1
- package/dist/traceability/git-staged.d.ts.map +1 -1
- package/dist/traceability/git-staged.js +24 -11
- package/dist/types/changeset.d.ts.map +1 -1
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/types/relationships.d.ts.map +1 -1
- package/dist/utils/branch-resolver.d.ts +4 -0
- package/dist/utils/branch-resolver.d.ts.map +1 -1
- package/dist/utils/branch-resolver.js +4 -0
- package/dist/utils/config.d.ts +10 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +27 -1
- package/dist/utils/rule-registry.d.ts +47 -0
- package/dist/utils/rule-registry.d.ts.map +1 -0
- package/dist/utils/rule-registry.js +139 -0
- package/package.json +5 -1
- package/schema/config.json +156 -0
- package/src/public/extractors/symbols-coordinator.ts +0 -27
- package/src/public/prolog/index.ts +0 -27
- package/src/public/schemas/entity.ts +0 -27
- package/src/public/schemas/relationship.ts +0 -27
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/extractors/manifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/extractors/manifest.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,CAAC;IACxB,aAAa,EAAE,qBAAqB,EAAE,CAAC;CACxC;AAED,qBAAa,aAAc,SAAQ,KAAK;IAG7B,QAAQ,EAAE,MAAM;gBADvB,OAAO,EAAE,MAAM,EACR,QAAQ,EAAE,MAAM;CAK1B;AAsBD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,CA4FxE"}
|
|
@@ -15,33 +15,6 @@
|
|
|
15
15
|
You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
-
/*
|
|
19
|
-
How to apply this header to source files (examples)
|
|
20
|
-
|
|
21
|
-
1) Prepend header to a single file (POSIX shells):
|
|
22
|
-
|
|
23
|
-
cat LICENSE_HEADER.txt "$FILE" > "$FILE".with-header && mv "$FILE".with-header "$FILE"
|
|
24
|
-
|
|
25
|
-
2) Apply to multiple files (example: the project's main entry files):
|
|
26
|
-
|
|
27
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp packages/cli/src/*.ts packages/mcp/src/*.ts; do
|
|
28
|
-
if [ -f "$f" ]; then
|
|
29
|
-
cp "$f" "$f".bak
|
|
30
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
31
|
-
fi
|
|
32
|
-
done
|
|
33
|
-
|
|
34
|
-
3) Avoid duplicating the header: run a quick guard to only add if missing
|
|
35
|
-
|
|
36
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp; do
|
|
37
|
-
if [ -f "$f" ]; then
|
|
38
|
-
if ! head -n 5 "$f" | grep -q "Copyright (C) 2026 Piotr Franczyk"; then
|
|
39
|
-
cp "$f" "$f".bak
|
|
40
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
41
|
-
fi
|
|
42
|
-
fi
|
|
43
|
-
done
|
|
44
|
-
*/
|
|
45
18
|
import { createHash } from "node:crypto";
|
|
46
19
|
import { readFileSync } from "node:fs";
|
|
47
20
|
import { load as parseYAML } from "js-yaml";
|
|
@@ -65,7 +38,45 @@ export function extractFromManifest(filePath) {
|
|
|
65
38
|
throw new ManifestError("Missing required field: title", filePath);
|
|
66
39
|
}
|
|
67
40
|
const id = symbol.id || generateId(filePath, symbol.title);
|
|
68
|
-
const relationships =
|
|
41
|
+
const relationships = [];
|
|
42
|
+
// Extract relationships from links field
|
|
43
|
+
// Supports both simple strings (treated as implements) and typed objects
|
|
44
|
+
if (Array.isArray(symbol.links)) {
|
|
45
|
+
for (const link of symbol.links) {
|
|
46
|
+
if (typeof link === "string") {
|
|
47
|
+
relationships.push({
|
|
48
|
+
type: "implements",
|
|
49
|
+
from: id,
|
|
50
|
+
to: link,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
else if (link !== null && typeof link === "object") {
|
|
54
|
+
const typedLink = link;
|
|
55
|
+
if (typeof typedLink.type === "string" &&
|
|
56
|
+
typeof typedLink.target === "string") {
|
|
57
|
+
relationships.push({
|
|
58
|
+
type: typedLink.type,
|
|
59
|
+
from: id,
|
|
60
|
+
to: typedLink.target,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Extract relationships from relationships field
|
|
67
|
+
if (Array.isArray(symbol.relationships)) {
|
|
68
|
+
for (const rel of symbol.relationships) {
|
|
69
|
+
if (rel &&
|
|
70
|
+
typeof rel.type === "string" &&
|
|
71
|
+
typeof rel.target === "string") {
|
|
72
|
+
relationships.push({
|
|
73
|
+
type: rel.type,
|
|
74
|
+
from: id,
|
|
75
|
+
to: rel.target,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
69
80
|
return {
|
|
70
81
|
entity: {
|
|
71
82
|
id,
|
|
@@ -79,7 +90,6 @@ export function extractFromManifest(filePath) {
|
|
|
79
90
|
owner: symbol.owner,
|
|
80
91
|
priority: symbol.priority,
|
|
81
92
|
severity: symbol.severity,
|
|
82
|
-
links: symbol.links,
|
|
83
93
|
text_ref: symbol.text_ref,
|
|
84
94
|
},
|
|
85
95
|
relationships,
|
|
@@ -101,22 +111,3 @@ function generateId(filePath, title) {
|
|
|
101
111
|
hash.update(`${filePath}:${title}`);
|
|
102
112
|
return hash.digest("hex").substring(0, 16);
|
|
103
113
|
}
|
|
104
|
-
function extractRelationships(links, fromId) {
|
|
105
|
-
if (!Array.isArray(links))
|
|
106
|
-
return [];
|
|
107
|
-
return links.map((link) => {
|
|
108
|
-
if (typeof link === "string") {
|
|
109
|
-
return {
|
|
110
|
-
type: "relates_to",
|
|
111
|
-
from: fromId,
|
|
112
|
-
to: link,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
const linkObj = link;
|
|
116
|
-
return {
|
|
117
|
-
type: linkObj.type || "relates_to",
|
|
118
|
-
from: fromId,
|
|
119
|
-
to: linkObj.target || linkObj.id || linkObj.to || "",
|
|
120
|
-
};
|
|
121
|
-
});
|
|
122
|
-
}
|
|
@@ -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":"AAsBA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,CAAC;IACxB,aAAa,EAAE,qBAAqB,EAAE,CAAC;CACxC;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IAOhC,QAAQ,EAAE,MAAM;IANlB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;gBAG5B,OAAO,EAAE,MAAM,EACR,QAAQ,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE;QACR,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IASM,QAAQ;CAUlB;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CA8CV;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAmJtE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASjE"}
|
|
@@ -15,33 +15,6 @@
|
|
|
15
15
|
You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
-
/*
|
|
19
|
-
How to apply this header to source files (examples)
|
|
20
|
-
|
|
21
|
-
1) Prepend header to a single file (POSIX shells):
|
|
22
|
-
|
|
23
|
-
cat LICENSE_HEADER.txt "$FILE" > "$FILE".with-header && mv "$FILE".with-header "$FILE"
|
|
24
|
-
|
|
25
|
-
2) Apply to multiple files (example: the project's main entry files):
|
|
26
|
-
|
|
27
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp packages/cli/src/*.ts packages/mcp/src/*.ts; do
|
|
28
|
-
if [ -f "$f" ]; then
|
|
29
|
-
cp "$f" "$f".bak
|
|
30
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
31
|
-
fi
|
|
32
|
-
done
|
|
33
|
-
|
|
34
|
-
3) Avoid duplicating the header: run a quick guard to only add if missing
|
|
35
|
-
|
|
36
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp; do
|
|
37
|
-
if [ -f "$f" ]; then
|
|
38
|
-
if ! head -n 5 "$f" | grep -q "Copyright (C) 2026 Piotr Franczyk"; then
|
|
39
|
-
cp "$f" "$f".bak
|
|
40
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
41
|
-
fi
|
|
42
|
-
fi
|
|
43
|
-
done
|
|
44
|
-
*/
|
|
45
18
|
import { createHash } from "node:crypto";
|
|
46
19
|
import { readFileSync } from "node:fs";
|
|
47
20
|
import matter from "gray-matter";
|
|
@@ -145,11 +118,25 @@ export function extractFromMarkdown(filePath) {
|
|
|
145
118
|
const entityTypes = embeddedEntities.join(" and ");
|
|
146
119
|
throw new FrontmatterError(`Invalid embedded entity: requirement contains ${entityTypes} fields`, filePath, {
|
|
147
120
|
classification: "Embedded Entity Violation",
|
|
148
|
-
hint: `Move ${entityTypes} to separate entity files and link them
|
|
121
|
+
hint: `Move ${entityTypes} to separate entity files and link them via relationship shards in .kb/relationships/.`,
|
|
149
122
|
});
|
|
150
123
|
}
|
|
151
124
|
const id = data.id || generateId(filePath, data.title);
|
|
152
|
-
const relationships =
|
|
125
|
+
const relationships = [];
|
|
126
|
+
if (Array.isArray(data.links)) {
|
|
127
|
+
for (const link of data.links) {
|
|
128
|
+
if (link &&
|
|
129
|
+
typeof link === "object" &&
|
|
130
|
+
typeof link.type === "string" &&
|
|
131
|
+
typeof link.target === "string") {
|
|
132
|
+
relationships.push({
|
|
133
|
+
type: link.type,
|
|
134
|
+
from: id,
|
|
135
|
+
to: link.target,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
153
140
|
return {
|
|
154
141
|
entity: {
|
|
155
142
|
id,
|
|
@@ -163,7 +150,6 @@ export function extractFromMarkdown(filePath) {
|
|
|
163
150
|
owner: data.owner,
|
|
164
151
|
priority: data.priority,
|
|
165
152
|
severity: data.severity,
|
|
166
|
-
links: data.links,
|
|
167
153
|
text_ref: data.text_ref,
|
|
168
154
|
},
|
|
169
155
|
relationships,
|
|
@@ -229,22 +215,3 @@ function generateId(filePath, title) {
|
|
|
229
215
|
hash.update(`${filePath}:${title}`);
|
|
230
216
|
return hash.digest("hex").substring(0, 16);
|
|
231
217
|
}
|
|
232
|
-
function extractRelationships(links, fromId) {
|
|
233
|
-
if (!Array.isArray(links))
|
|
234
|
-
return [];
|
|
235
|
-
return links.map((link) => {
|
|
236
|
-
if (typeof link === "string") {
|
|
237
|
-
return {
|
|
238
|
-
type: "relates_to",
|
|
239
|
-
from: fromId,
|
|
240
|
-
to: link,
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
const linkObj = link;
|
|
244
|
-
return {
|
|
245
|
-
type: linkObj.type || "relates_to",
|
|
246
|
-
from: fromId,
|
|
247
|
-
to: linkObj.target || linkObj.id || linkObj.to || "",
|
|
248
|
-
};
|
|
249
|
-
});
|
|
250
|
-
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface ExtractedRelationship {
|
|
2
|
+
type: string;
|
|
3
|
+
from: string;
|
|
4
|
+
to: string;
|
|
5
|
+
metadata?: {
|
|
6
|
+
created_at?: string;
|
|
7
|
+
created_by?: string;
|
|
8
|
+
source?: string;
|
|
9
|
+
confidence?: number;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface ShardExtractionResult {
|
|
13
|
+
shardPath: string;
|
|
14
|
+
relationships: ExtractedRelationship[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Extracts all relationships from relationship shard files in the given directory.
|
|
18
|
+
*
|
|
19
|
+
* @param relationshipsDir - Path to .kb/relationships directory
|
|
20
|
+
* @returns Array of extraction results, one per shard file
|
|
21
|
+
*/
|
|
22
|
+
export declare function extractFromRelationshipShards(relationshipsDir: string): ShardExtractionResult[];
|
|
23
|
+
/**
|
|
24
|
+
* Gets the path to the relationships directory for a given KB root.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getRelationshipsDir(kbRoot: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Flattens multiple shard extraction results into a single array of relationships.
|
|
29
|
+
*/
|
|
30
|
+
export declare function flattenRelationships(results: ShardExtractionResult[]): ExtractedRelationship[];
|
|
31
|
+
/**
|
|
32
|
+
* Validates that all relationships reference valid entity IDs.
|
|
33
|
+
* Returns validation errors for dangling references.
|
|
34
|
+
*/
|
|
35
|
+
export declare function validateRelationships(relationships: ExtractedRelationship[], validEntityIds: Set<string>): Array<{
|
|
36
|
+
relationship: ExtractedRelationship;
|
|
37
|
+
error: "missing_from" | "missing_to";
|
|
38
|
+
}>;
|
|
39
|
+
//# sourceMappingURL=relationships.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../../src/extractors/relationships.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE;QACT,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,qBAAqB,EAAE,CAAC;CACxC;AAsBD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,gBAAgB,EAAE,MAAM,GACvB,qBAAqB,EAAE,CAyCzB;AA6CD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,qBAAqB,EAAE,GAC/B,qBAAqB,EAAE,CAEzB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,qBAAqB,EAAE,EACtC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,GAC1B,KAAK,CAAC;IACP,YAAY,EAAE,qBAAqB,CAAC;IACpC,KAAK,EAAE,cAAc,GAAG,YAAY,CAAC;CACtC,CAAC,CAgBD"}
|
|
@@ -0,0 +1,137 @@
|
|
|
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 * as fs from "node:fs";
|
|
19
|
+
import * as path from "node:path";
|
|
20
|
+
import { readShard } from "../relationships/shards.js";
|
|
21
|
+
/**
|
|
22
|
+
* Valid relationship types per the Kibi schema.
|
|
23
|
+
*/
|
|
24
|
+
const VALID_RELATIONSHIP_TYPES = new Set([
|
|
25
|
+
"depends_on",
|
|
26
|
+
"specified_by",
|
|
27
|
+
"verified_by",
|
|
28
|
+
"validates",
|
|
29
|
+
"implements",
|
|
30
|
+
"covered_by",
|
|
31
|
+
"constrained_by",
|
|
32
|
+
"constrains",
|
|
33
|
+
"requires_property",
|
|
34
|
+
"guards",
|
|
35
|
+
"publishes",
|
|
36
|
+
"consumes",
|
|
37
|
+
"supersedes",
|
|
38
|
+
"relates_to",
|
|
39
|
+
]);
|
|
40
|
+
/**
|
|
41
|
+
* Extracts all relationships from relationship shard files in the given directory.
|
|
42
|
+
*
|
|
43
|
+
* @param relationshipsDir - Path to .kb/relationships directory
|
|
44
|
+
* @returns Array of extraction results, one per shard file
|
|
45
|
+
*/
|
|
46
|
+
export function extractFromRelationshipShards(relationshipsDir) {
|
|
47
|
+
if (!fs.existsSync(relationshipsDir)) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
const results = [];
|
|
51
|
+
const files = fs.readdirSync(relationshipsDir);
|
|
52
|
+
for (const file of files) {
|
|
53
|
+
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const shardPath = path.join(relationshipsDir, file);
|
|
57
|
+
const stats = fs.statSync(shardPath);
|
|
58
|
+
if (!stats.isFile()) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const records = readShard(shardPath);
|
|
63
|
+
const relationships = records
|
|
64
|
+
.map(convertRecordToRelationship)
|
|
65
|
+
.filter((r) => r !== null);
|
|
66
|
+
results.push({
|
|
67
|
+
shardPath,
|
|
68
|
+
relationships,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
// Re-throw with shard path context
|
|
73
|
+
throw new Error(`Failed to extract relationships from ${shardPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return results;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Converts a RelationshipRecord to an ExtractedRelationship.
|
|
80
|
+
* Returns null if the record is invalid.
|
|
81
|
+
*/
|
|
82
|
+
function convertRecordToRelationship(record) {
|
|
83
|
+
// Validate type
|
|
84
|
+
if (!VALID_RELATIONSHIP_TYPES.has(record.type)) {
|
|
85
|
+
throw new Error(`Invalid relationship type "${record.type}" in record ${record.id}`);
|
|
86
|
+
}
|
|
87
|
+
// Validate from/to are not empty
|
|
88
|
+
if (!record.from || !record.to) {
|
|
89
|
+
throw new Error(`Missing from or to in relationship record ${record.id}`);
|
|
90
|
+
}
|
|
91
|
+
const relationship = {
|
|
92
|
+
type: record.type,
|
|
93
|
+
from: record.from,
|
|
94
|
+
to: record.to,
|
|
95
|
+
};
|
|
96
|
+
// Include metadata if present
|
|
97
|
+
if (record.created_at ||
|
|
98
|
+
record.created_by ||
|
|
99
|
+
record.source ||
|
|
100
|
+
record.confidence !== undefined) {
|
|
101
|
+
relationship.metadata = {
|
|
102
|
+
created_at: record.created_at,
|
|
103
|
+
created_by: record.created_by,
|
|
104
|
+
source: record.source,
|
|
105
|
+
confidence: record.confidence,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return relationship;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Gets the path to the relationships directory for a given KB root.
|
|
112
|
+
*/
|
|
113
|
+
export function getRelationshipsDir(kbRoot) {
|
|
114
|
+
return path.join(kbRoot, "relationships");
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Flattens multiple shard extraction results into a single array of relationships.
|
|
118
|
+
*/
|
|
119
|
+
export function flattenRelationships(results) {
|
|
120
|
+
return results.flatMap((r) => r.relationships);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Validates that all relationships reference valid entity IDs.
|
|
124
|
+
* Returns validation errors for dangling references.
|
|
125
|
+
*/
|
|
126
|
+
export function validateRelationships(relationships, validEntityIds) {
|
|
127
|
+
const errors = [];
|
|
128
|
+
for (const rel of relationships) {
|
|
129
|
+
if (!validEntityIds.has(rel.from)) {
|
|
130
|
+
errors.push({ relationship: rel, error: "missing_from" });
|
|
131
|
+
}
|
|
132
|
+
if (!validEntityIds.has(rel.to)) {
|
|
133
|
+
errors.push({ relationship: rel, error: "missing_to" });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return errors;
|
|
137
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"symbols-coordinator.d.ts","sourceRoot":"","sources":["../../src/extractors/symbols-coordinator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"symbols-coordinator.d.ts","sourceRoot":"","sources":["../../src/extractors/symbols-coordinator.ts"],"names":[],"mappings":"AAoBA,OAAO,EACL,KAAK,mBAAmB,EAEzB,MAAM,iBAAiB,CAAC;AAazB,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,mBAAmB,EAAE,EAC9B,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAmChC"}
|
|
@@ -15,33 +15,6 @@
|
|
|
15
15
|
You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
-
/*
|
|
19
|
-
How to apply this header to source files (examples)
|
|
20
|
-
|
|
21
|
-
1) Prepend header to a single file (POSIX shells):
|
|
22
|
-
|
|
23
|
-
cat LICENSE_HEADER.txt "$FILE" > "$FILE".with-header && mv "$FILE".with-header "$FILE"
|
|
24
|
-
|
|
25
|
-
2) Apply to multiple files (example: the project's main entry files):
|
|
26
|
-
|
|
27
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp packages/cli/src/*.ts packages/mcp/src/*.ts; do
|
|
28
|
-
if [ -f "$f" ]; then
|
|
29
|
-
cp "$f" "$f".bak
|
|
30
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
31
|
-
fi
|
|
32
|
-
done
|
|
33
|
-
|
|
34
|
-
3) Avoid duplicating the header: run a quick guard to only add if missing
|
|
35
|
-
|
|
36
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp; do
|
|
37
|
-
if [ -f "$f" ]; then
|
|
38
|
-
if ! head -n 5 "$f" | grep -q "Copyright (C) 2026 Piotr Franczyk"; then
|
|
39
|
-
cp "$f" "$f".bak
|
|
40
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
41
|
-
fi
|
|
42
|
-
fi
|
|
43
|
-
done
|
|
44
|
-
*/
|
|
45
18
|
import * as fs from "node:fs";
|
|
46
19
|
import * as path from "node:path";
|
|
47
20
|
import { enrichSymbolCoordinatesWithTsMorph, } from "./symbols-ts.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"symbols-ts.d.ts","sourceRoot":"","sources":["../../src/extractors/symbols-ts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"symbols-ts.d.ts","sourceRoot":"","sources":["../../src/extractors/symbols-ts.ts"],"names":[],"mappings":"AA4BA,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAaD,wBAAsB,kCAAkC,CACtD,OAAO,EAAE,mBAAmB,EAAE,EAC9B,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAwDhC"}
|
|
@@ -15,33 +15,6 @@
|
|
|
15
15
|
You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
-
/*
|
|
19
|
-
How to apply this header to source files (examples)
|
|
20
|
-
|
|
21
|
-
1) Prepend header to a single file (POSIX shells):
|
|
22
|
-
|
|
23
|
-
cat LICENSE_HEADER.txt "$FILE" > "$FILE".with-header && mv "$FILE".with-header "$FILE"
|
|
24
|
-
|
|
25
|
-
2) Apply to multiple files (example: the project's main entry files):
|
|
26
|
-
|
|
27
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp packages/cli/src/*.ts packages/mcp/src/*.ts; do
|
|
28
|
-
if [ -f "$f" ]; then
|
|
29
|
-
cp "$f" "$f".bak
|
|
30
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
31
|
-
fi
|
|
32
|
-
done
|
|
33
|
-
|
|
34
|
-
3) Avoid duplicating the header: run a quick guard to only add if missing
|
|
35
|
-
|
|
36
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp; do
|
|
37
|
-
if [ -f "$f" ]; then
|
|
38
|
-
if ! head -n 5 "$f" | grep -q "Copyright (C) 2026 Piotr Franczyk"; then
|
|
39
|
-
cp "$f" "$f".bak
|
|
40
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
41
|
-
fi
|
|
42
|
-
fi
|
|
43
|
-
done
|
|
44
|
-
*/
|
|
45
18
|
import * as fs from "node:fs";
|
|
46
19
|
import * as path from "node:path";
|
|
47
20
|
import { Project, } from "ts-morph";
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export type ResolutionReason = "env" | "kb" | "git" | "cwd";
|
|
2
|
+
export interface WorkspaceInfo {
|
|
3
|
+
root: string;
|
|
4
|
+
reason: ResolutionReason;
|
|
5
|
+
}
|
|
6
|
+
export interface KbTarget {
|
|
7
|
+
workspaceRoot: string;
|
|
8
|
+
branch: string;
|
|
9
|
+
kbPath: string;
|
|
10
|
+
reason: ResolutionReason;
|
|
11
|
+
}
|
|
12
|
+
export type BranchErrorCode = "ENV_OVERRIDE" | "DETACHED_HEAD" | "UNBORN_BRANCH" | "GIT_NOT_AVAILABLE" | "NOT_A_GIT_REPO" | "UNKNOWN_ERROR";
|
|
13
|
+
export interface BranchResolutionSuccess {
|
|
14
|
+
branch: string;
|
|
15
|
+
}
|
|
16
|
+
export interface BranchResolutionError {
|
|
17
|
+
error: string;
|
|
18
|
+
code: BranchErrorCode;
|
|
19
|
+
}
|
|
20
|
+
export type BranchResolutionResult = BranchResolutionSuccess | BranchResolutionError;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve workspace root directory.
|
|
23
|
+
* Priority: env vars > .kb directory > .git directory > cwd
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveWorkspaceRoot(startDir?: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve workspace root with reason for resolution.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveWorkspaceRootInfo(startDir?: string): WorkspaceInfo;
|
|
30
|
+
/**
|
|
31
|
+
* Resolve KB path for a given workspace and branch.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveKbPath(workspaceRoot: string, branch: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Resolve the active branch according to precedence:
|
|
36
|
+
* 1. KIBI_BRANCH env var (if set)
|
|
37
|
+
* 2. Git active branch (from git branch --show-current)
|
|
38
|
+
* 3. Diagnostic failure (no silent fallback)
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolveActiveBranch(workspaceRoot?: string): BranchResolutionResult;
|
|
41
|
+
/**
|
|
42
|
+
* @deprecated defaultBranch is deprecated. Branch lifecycle now follows git naturally.
|
|
43
|
+
* This function is kept for backward compatibility but should not be used for new code.
|
|
44
|
+
*
|
|
45
|
+
* Resolve the default branch using precedence:
|
|
46
|
+
* 1. Configured defaultBranch from config (if set and valid)
|
|
47
|
+
* 2. Git remote HEAD (refs/remotes/origin/HEAD)
|
|
48
|
+
* 3. Fallback to "main"
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveDefaultBranch(cwd?: string, config?: {
|
|
51
|
+
defaultBranch?: string;
|
|
52
|
+
}): {
|
|
53
|
+
branch: string;
|
|
54
|
+
} | {
|
|
55
|
+
error: string;
|
|
56
|
+
code: string;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Resolve complete KB target with all components.
|
|
60
|
+
*/
|
|
61
|
+
export declare function resolveKbTarget(options?: {
|
|
62
|
+
workspaceRoot?: string;
|
|
63
|
+
branch?: string;
|
|
64
|
+
config?: {
|
|
65
|
+
defaultBranch?: string;
|
|
66
|
+
};
|
|
67
|
+
}): KbTarget;
|
|
68
|
+
/**
|
|
69
|
+
* Check if repository is in detached HEAD state.
|
|
70
|
+
*/
|
|
71
|
+
export declare function isDetachedHead(workspaceRoot?: string): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Validate a branch name for safety.
|
|
74
|
+
*/
|
|
75
|
+
export declare function isValidBranchName(name: string): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Get a detailed diagnostic message for branch resolution failures.
|
|
78
|
+
*/
|
|
79
|
+
export declare function getBranchDiagnostic(branch: string | undefined, error: string): string;
|
|
80
|
+
//# sourceMappingURL=target-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"target-resolver.d.ts","sourceRoot":"","sources":["../../src/kb/target-resolver.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,eAAe,GACf,eAAe,GACf,mBAAmB,GACnB,gBAAgB,GAChB,eAAe,CAAC;AAEpB,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,eAAe,CAAC;CACvB;AAED,MAAM,MAAM,sBAAsB,GAC9B,uBAAuB,GACvB,qBAAqB,CAAC;AAE1B;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAiB7E;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,GAAE,MAAsB,GAC/B,aAAa,CAiBf;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAW3E;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,GAAE,MAAsB,GACpC,sBAAsB,CA4GxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,GAAE,MAAsB,EAC3B,MAAM,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAmCtD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrC,GAAG,QAAQ,CAwBX;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,aAAa,GAAE,MAAsB,GAAG,OAAO,CAa7E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAuBvD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,KAAK,EAAE,MAAM,GACZ,MAAM,CAuBR"}
|