kibi-cli 0.2.3 → 0.2.6
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 +55 -45
- 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 +41 -49
- package/dist/extractors/markdown.d.ts +0 -1
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +28 -50
- 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 +10 -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 +6 -2
- package/schema/config.json +161 -0
- package/src/public/extractors/symbols-coordinator.ts +0 -27
- package/src/public/prolog/index.ts +0 -27
- package/src/public/schemas/entity.ts +10 -27
- package/src/public/schemas/relationship.ts +0 -27
- package/src/schemas/entity.schema.json +11 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/query/service.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAQlD,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,kBAAkB,UAS9B,CAAC;AAEF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAqClE;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,WAAW,CAAC,CAmCtB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,YAAY,GACpB,MAAM,CAkBR"}
|
|
@@ -0,0 +1,149 @@
|
|
|
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
|
+
import { escapeAtom, parseEntityFromBinding, parseEntityFromList, parseListOfLists, } from "../prolog/codec.js";
|
|
11
|
+
export const VALID_ENTITY_TYPES = [
|
|
12
|
+
"req",
|
|
13
|
+
"scenario",
|
|
14
|
+
"test",
|
|
15
|
+
"adr",
|
|
16
|
+
"flag",
|
|
17
|
+
"event",
|
|
18
|
+
"symbol",
|
|
19
|
+
"fact",
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Build a Prolog query goal from filters.
|
|
23
|
+
*/
|
|
24
|
+
export function buildEntityQueryGoal(filters) {
|
|
25
|
+
const { type, id, sourceFile, tags } = filters;
|
|
26
|
+
if (sourceFile) {
|
|
27
|
+
const safeSource = escapeAtom(sourceFile);
|
|
28
|
+
if (type) {
|
|
29
|
+
const safeType = escapeAtom(type);
|
|
30
|
+
return `findall([Id,'${safeType}',Props], (kb_entities_by_source('${safeSource}', SourceIds), member(Id, SourceIds), kb_entity(Id, '${safeType}', Props)), Results)`;
|
|
31
|
+
}
|
|
32
|
+
return `findall([Id,Type,Props], (kb_entities_by_source('${safeSource}', SourceIds), member(Id, SourceIds), kb_entity(Id, Type, Props)), Results)`;
|
|
33
|
+
}
|
|
34
|
+
if (id && type) {
|
|
35
|
+
const safeId = escapeAtom(id);
|
|
36
|
+
const safeType = escapeAtom(type);
|
|
37
|
+
return `findall(['${safeId}','${safeType}',Props], kb_entity('${safeId}', '${safeType}', Props), Results)`;
|
|
38
|
+
}
|
|
39
|
+
if (id) {
|
|
40
|
+
const safeId = escapeAtom(id);
|
|
41
|
+
return `findall(['${safeId}',Type,Props], kb_entity('${safeId}', Type, Props), Results)`;
|
|
42
|
+
}
|
|
43
|
+
if (tags && tags.length > 0) {
|
|
44
|
+
if (type) {
|
|
45
|
+
const safeType = escapeAtom(type);
|
|
46
|
+
return `findall([Id,'${safeType}',Props], kb_entity(Id, '${safeType}', Props), Results)`;
|
|
47
|
+
}
|
|
48
|
+
return "findall([Id,Type,Props], kb_entity(Id, Type, Props), Results)";
|
|
49
|
+
}
|
|
50
|
+
if (type) {
|
|
51
|
+
const safeType = escapeAtom(type);
|
|
52
|
+
return `findall([Id,'${safeType}',Props], kb_entity(Id, '${safeType}', Props), Results)`;
|
|
53
|
+
}
|
|
54
|
+
return "findall([Id,Type,Props], kb_entity(Id, Type, Props), Results)";
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Execute a filtered entity query against the KB.
|
|
58
|
+
*/
|
|
59
|
+
export async function queryEntities(prolog, filters) {
|
|
60
|
+
const { tags, limit = 100, offset = 0 } = filters;
|
|
61
|
+
const goal = buildEntityQueryGoal(filters);
|
|
62
|
+
const queryResult = await prolog.query(goal);
|
|
63
|
+
let entities = [];
|
|
64
|
+
if (queryResult.success) {
|
|
65
|
+
if (queryResult.bindings.Results) {
|
|
66
|
+
const entitiesData = parseListOfLists(queryResult.bindings.Results);
|
|
67
|
+
for (const data of entitiesData) {
|
|
68
|
+
const entity = parseEntityFromList(data);
|
|
69
|
+
entities.push(entity);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else if (queryResult.bindings.Result) {
|
|
73
|
+
const entity = parseEntityFromBinding(queryResult.bindings.Result);
|
|
74
|
+
entities = [entity];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
throw new Error(queryResult.error || "Query failed with unknown error");
|
|
79
|
+
}
|
|
80
|
+
// Apply tag filtering client-side if specified
|
|
81
|
+
if (tags && tags.length > 0) {
|
|
82
|
+
entities = dedupeEntities(entities.filter((entity) => hasAnyTag(entity, tags)));
|
|
83
|
+
}
|
|
84
|
+
const totalCount = entities.length;
|
|
85
|
+
const paginated = entities.slice(offset, offset + limit);
|
|
86
|
+
return { entities: paginated, totalCount };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Validate entity type.
|
|
90
|
+
*/
|
|
91
|
+
export function validateEntityType(type) {
|
|
92
|
+
return VALID_ENTITY_TYPES.includes(type);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get validation error message for invalid type.
|
|
96
|
+
*/
|
|
97
|
+
export function getInvalidTypeError(type) {
|
|
98
|
+
return `Invalid type '${type}'. Valid types: ${VALID_ENTITY_TYPES.join(", ")}. Use a single type value, or omit this parameter to query all entities.`;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Build human-readable summary text for query results.
|
|
102
|
+
*/
|
|
103
|
+
export function buildQuerySummaryText(result, filters) {
|
|
104
|
+
const { entities, totalCount } = result;
|
|
105
|
+
const { type, offset, limit } = filters;
|
|
106
|
+
if (totalCount === 0) {
|
|
107
|
+
return `No entities found${type ? ` of type '${type}'` : ""}.`;
|
|
108
|
+
}
|
|
109
|
+
const details = entities
|
|
110
|
+
.map((e) => {
|
|
111
|
+
const id = String(e.id || "").replace(/^file:\/\/.*\//, "");
|
|
112
|
+
const title = String(e.title || "");
|
|
113
|
+
const status = String(e.status || "");
|
|
114
|
+
return `${id} (${title}, status=${status})`;
|
|
115
|
+
})
|
|
116
|
+
.join(", ");
|
|
117
|
+
return `Found ${totalCount} entities${type ? ` of type '${type}'` : ""}. Showing ${entities.length} (offset ${offset}, limit ${limit}): ${details}`;
|
|
118
|
+
}
|
|
119
|
+
function hasAnyTag(entity, requestedTags) {
|
|
120
|
+
const expected = new Set(requestedTags.map(normalizeTagValue));
|
|
121
|
+
const rawTags = entity.tags;
|
|
122
|
+
if (!Array.isArray(rawTags) || rawTags.length === 0) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
for (const tag of rawTags) {
|
|
126
|
+
if (expected.has(normalizeTagValue(tag))) {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
function normalizeTagValue(tag) {
|
|
133
|
+
return String(tag).trim();
|
|
134
|
+
}
|
|
135
|
+
function dedupeEntities(entities) {
|
|
136
|
+
const seen = new Set();
|
|
137
|
+
const deduped = [];
|
|
138
|
+
for (const entity of entities) {
|
|
139
|
+
const id = String(entity.id ?? "");
|
|
140
|
+
const type = String(entity.type ?? "");
|
|
141
|
+
const key = `${type}::${id}`;
|
|
142
|
+
if (seen.has(key)) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
seen.add(key);
|
|
146
|
+
deduped.push(entity);
|
|
147
|
+
}
|
|
148
|
+
return deduped;
|
|
149
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a relationship record stored in shard files.
|
|
3
|
+
*/
|
|
4
|
+
export interface RelationshipRecord {
|
|
5
|
+
id: string;
|
|
6
|
+
type: string;
|
|
7
|
+
from: string;
|
|
8
|
+
to: string;
|
|
9
|
+
created_at: string;
|
|
10
|
+
created_by: string;
|
|
11
|
+
source: string;
|
|
12
|
+
confidence?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Gets the path to the relationships directory for a given KB root.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getRelationshipsDir(kbRoot: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Computes the shard name (first 2 chars of SHA256) for a given entity ID.
|
|
20
|
+
*/
|
|
21
|
+
export declare function shardForFromId(fromId: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Computes the shard path for a given entity ID.
|
|
24
|
+
* Uses first 2 chars of SHA256(entityId) as shard name.
|
|
25
|
+
*/
|
|
26
|
+
export declare function computeShardPath(kbRoot: string, entityId: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Reads a relationship shard file.
|
|
29
|
+
* Returns empty array if file doesn't exist.
|
|
30
|
+
* Throws on parse errors.
|
|
31
|
+
*/
|
|
32
|
+
export declare function readShard(shardPath: string): RelationshipRecord[];
|
|
33
|
+
/**
|
|
34
|
+
* Writes a relationship shard file.
|
|
35
|
+
* Creates parent directories if needed.
|
|
36
|
+
*/
|
|
37
|
+
export declare function writeShard(shardPath: string, records: RelationshipRecord[]): void;
|
|
38
|
+
/**
|
|
39
|
+
* Appends a relationship to the appropriate shard.
|
|
40
|
+
* Returns the shard path and record ID.
|
|
41
|
+
*/
|
|
42
|
+
export declare function appendRelationship(kbRoot: string, relationship: Omit<RelationshipRecord, "id">): {
|
|
43
|
+
shardPath: string;
|
|
44
|
+
recordId: string;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Lists all shard files in the relationships directory.
|
|
48
|
+
*/
|
|
49
|
+
export declare function listShards(kbRoot: string): string[];
|
|
50
|
+
/**
|
|
51
|
+
* Reads all relationships from all shards.
|
|
52
|
+
*/
|
|
53
|
+
export declare function readAllShards(kbRoot: string): RelationshipRecord[];
|
|
54
|
+
/**
|
|
55
|
+
* Removes dangling relationships that reference non-existent entities.
|
|
56
|
+
*/
|
|
57
|
+
export declare function pruneDangling(records: RelationshipRecord[], validEntityIds: Set<string>): RelationshipRecord[];
|
|
58
|
+
/**
|
|
59
|
+
* Generates a deterministic relationship ID.
|
|
60
|
+
*/
|
|
61
|
+
export declare function relationshipIdFor(type: string, from: string, to: string): string;
|
|
62
|
+
/**
|
|
63
|
+
* Merges existing and incoming relationship records.
|
|
64
|
+
* Deduplicates by (type, from, to) tuple.
|
|
65
|
+
* On conflict, keeps the record with newer created_at timestamp.
|
|
66
|
+
*/
|
|
67
|
+
export declare function mergeRecords(existing: RelationshipRecord[], incoming: RelationshipRecord[]): RelationshipRecord[];
|
|
68
|
+
//# sourceMappingURL=shards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shards.d.ts","sourceRoot":"","sources":["../../src/relationships/shards.ts"],"names":[],"mappings":"AAuBA;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGzE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAqFjE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,kBAAkB,EAAE,GAC5B,IAAI,CAoBN;AAqCD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,GAC3C;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CA4BzC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAUnD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAUlE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,kBAAkB,EAAE,EAC7B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,GAC1B,kBAAkB,EAAE,CAKtB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT,MAAM,CAMR;AAID;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,kBAAkB,EAAE,EAC9B,QAAQ,EAAE,kBAAkB,EAAE,GAC7B,kBAAkB,EAAE,CAgCtB"}
|
|
@@ -0,0 +1,263 @@
|
|
|
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 crypto from "node:crypto";
|
|
19
|
+
import * as fs from "node:fs";
|
|
20
|
+
import * as path from "node:path";
|
|
21
|
+
import { load as parseYAML } from "js-yaml";
|
|
22
|
+
/**
|
|
23
|
+
* Gets the path to the relationships directory for a given KB root.
|
|
24
|
+
*/
|
|
25
|
+
export function getRelationshipsDir(kbRoot) {
|
|
26
|
+
return path.join(kbRoot, "relationships");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Computes the shard name (first 2 chars of SHA256) for a given entity ID.
|
|
30
|
+
*/
|
|
31
|
+
export function shardForFromId(fromId) {
|
|
32
|
+
const hash = crypto.createHash("sha256").update(fromId).digest("hex");
|
|
33
|
+
return hash.slice(0, 2);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Computes the shard path for a given entity ID.
|
|
37
|
+
* Uses first 2 chars of SHA256(entityId) as shard name.
|
|
38
|
+
*/
|
|
39
|
+
export function computeShardPath(kbRoot, entityId) {
|
|
40
|
+
const shardName = shardForFromId(entityId);
|
|
41
|
+
return path.join(getRelationshipsDir(kbRoot), `${shardName}.yaml`);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Reads a relationship shard file.
|
|
45
|
+
* Returns empty array if file doesn't exist.
|
|
46
|
+
* Throws on parse errors.
|
|
47
|
+
*/
|
|
48
|
+
export function readShard(shardPath) {
|
|
49
|
+
if (!fs.existsSync(shardPath)) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
const content = fs.readFileSync(shardPath, "utf8");
|
|
53
|
+
if (!content.trim()) {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
const parsed = parseYAML(content);
|
|
57
|
+
if (!parsed || !Array.isArray(parsed.relationships)) {
|
|
58
|
+
throw new Error(`Invalid shard file: missing 'relationships' array at ${shardPath}`);
|
|
59
|
+
}
|
|
60
|
+
return parsed.relationships.map((record, index) => {
|
|
61
|
+
if (typeof record !== "object" || record === null) {
|
|
62
|
+
throw new Error(`Invalid record at ${shardPath}[${index}]: expected object`);
|
|
63
|
+
}
|
|
64
|
+
const rec = record;
|
|
65
|
+
// Validate required fields
|
|
66
|
+
if (typeof rec.id !== "string" || !rec.id) {
|
|
67
|
+
throw new Error(`Missing or invalid 'id' at ${shardPath}[${index}]`);
|
|
68
|
+
}
|
|
69
|
+
if (typeof rec.type !== "string" || !rec.type) {
|
|
70
|
+
throw new Error(`Missing or invalid 'type' at ${shardPath}[${index}]`);
|
|
71
|
+
}
|
|
72
|
+
if (typeof rec.from !== "string" || !rec.from) {
|
|
73
|
+
throw new Error(`Missing or invalid 'from' at ${shardPath}[${index}]`);
|
|
74
|
+
}
|
|
75
|
+
if (typeof rec.to !== "string" || !rec.to) {
|
|
76
|
+
throw new Error(`Missing or invalid 'to' at ${shardPath}[${index}]`);
|
|
77
|
+
}
|
|
78
|
+
// Handle created_at - YAML may auto-convert ISO dates to Date objects
|
|
79
|
+
let createdAt;
|
|
80
|
+
if (rec.created_at instanceof Date) {
|
|
81
|
+
createdAt = rec.created_at.toISOString().replace(/\.000Z$/, 'Z');
|
|
82
|
+
}
|
|
83
|
+
else if (typeof rec.created_at === "string" && rec.created_at) {
|
|
84
|
+
createdAt = rec.created_at;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
throw new Error(`Missing or invalid 'created_at' at ${shardPath}[${index}]`);
|
|
88
|
+
}
|
|
89
|
+
if (typeof rec.created_by !== "string" || !rec.created_by) {
|
|
90
|
+
throw new Error(`Missing or invalid 'created_by' at ${shardPath}[${index}]`);
|
|
91
|
+
}
|
|
92
|
+
if (typeof rec.source !== "string" || !rec.source) {
|
|
93
|
+
throw new Error(`Missing or invalid 'source' at ${shardPath}[${index}]`);
|
|
94
|
+
}
|
|
95
|
+
const result = {
|
|
96
|
+
id: rec.id,
|
|
97
|
+
type: rec.type,
|
|
98
|
+
from: rec.from,
|
|
99
|
+
to: rec.to,
|
|
100
|
+
created_at: createdAt,
|
|
101
|
+
created_by: rec.created_by,
|
|
102
|
+
source: rec.source,
|
|
103
|
+
};
|
|
104
|
+
if (rec.confidence !== undefined) {
|
|
105
|
+
if (typeof rec.confidence !== "number") {
|
|
106
|
+
throw new Error(`Invalid 'confidence' at ${shardPath}[${index}]: expected number`);
|
|
107
|
+
}
|
|
108
|
+
result.confidence = rec.confidence;
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Writes a relationship shard file.
|
|
115
|
+
* Creates parent directories if needed.
|
|
116
|
+
*/
|
|
117
|
+
export function writeShard(shardPath, records) {
|
|
118
|
+
const dir = path.dirname(shardPath);
|
|
119
|
+
if (!fs.existsSync(dir)) {
|
|
120
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
121
|
+
}
|
|
122
|
+
// Sort and dedupe records
|
|
123
|
+
const sorted = sortRecords(records);
|
|
124
|
+
const seen = new Set();
|
|
125
|
+
const unique = [];
|
|
126
|
+
for (const record of sorted) {
|
|
127
|
+
const key = `${record.type}|${record.from}|${record.to}`;
|
|
128
|
+
if (seen.has(key))
|
|
129
|
+
continue;
|
|
130
|
+
seen.add(key);
|
|
131
|
+
unique.push(record);
|
|
132
|
+
}
|
|
133
|
+
const yamlContent = serializeToYAML(unique);
|
|
134
|
+
fs.writeFileSync(shardPath, yamlContent, "utf8");
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Serializes records to YAML format.
|
|
138
|
+
*/
|
|
139
|
+
function serializeToYAML(records) {
|
|
140
|
+
const lines = ["relationships:"];
|
|
141
|
+
for (const record of records) {
|
|
142
|
+
lines.push(` - id: ${record.id}`);
|
|
143
|
+
lines.push(` type: ${record.type}`);
|
|
144
|
+
lines.push(` from: ${record.from}`);
|
|
145
|
+
lines.push(` to: ${record.to}`);
|
|
146
|
+
lines.push(` created_at: "${record.created_at}"`);
|
|
147
|
+
lines.push(` created_by: ${record.created_by}`);
|
|
148
|
+
lines.push(` source: ${record.source}`);
|
|
149
|
+
if (record.confidence !== undefined) {
|
|
150
|
+
lines.push(` confidence: ${record.confidence}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return lines.join("\n") + "\n";
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Sorts records deterministically by from, then type, then to.
|
|
157
|
+
*/
|
|
158
|
+
function sortRecords(records) {
|
|
159
|
+
return [...records].sort((a, b) => {
|
|
160
|
+
const fromCompare = a.from.localeCompare(b.from);
|
|
161
|
+
if (fromCompare !== 0)
|
|
162
|
+
return fromCompare;
|
|
163
|
+
const typeCompare = a.type.localeCompare(b.type);
|
|
164
|
+
if (typeCompare !== 0)
|
|
165
|
+
return typeCompare;
|
|
166
|
+
return a.to.localeCompare(b.to);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Appends a relationship to the appropriate shard.
|
|
171
|
+
* Returns the shard path and record ID.
|
|
172
|
+
*/
|
|
173
|
+
export function appendRelationship(kbRoot, relationship) {
|
|
174
|
+
const shardPath = computeShardPath(kbRoot, relationship.from);
|
|
175
|
+
const existing = readShard(shardPath);
|
|
176
|
+
// Generate deterministic ID
|
|
177
|
+
const recordId = relationshipIdFor(relationship.type, relationship.from, relationship.to);
|
|
178
|
+
// Check if relationship already exists
|
|
179
|
+
const exists = existing.some((r) => r.type === relationship.type &&
|
|
180
|
+
r.from === relationship.from &&
|
|
181
|
+
r.to === relationship.to);
|
|
182
|
+
if (!exists) {
|
|
183
|
+
const newRecord = {
|
|
184
|
+
...relationship,
|
|
185
|
+
id: recordId,
|
|
186
|
+
};
|
|
187
|
+
writeShard(shardPath, [...existing, newRecord]);
|
|
188
|
+
}
|
|
189
|
+
return { shardPath, recordId };
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Lists all shard files in the relationships directory.
|
|
193
|
+
*/
|
|
194
|
+
export function listShards(kbRoot) {
|
|
195
|
+
const relationshipsDir = getRelationshipsDir(kbRoot);
|
|
196
|
+
if (!fs.existsSync(relationshipsDir)) {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
return fs
|
|
200
|
+
.readdirSync(relationshipsDir)
|
|
201
|
+
.filter((f) => f.endsWith(".yaml"))
|
|
202
|
+
.map((f) => path.join(relationshipsDir, f));
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Reads all relationships from all shards.
|
|
206
|
+
*/
|
|
207
|
+
export function readAllShards(kbRoot) {
|
|
208
|
+
const shards = listShards(kbRoot);
|
|
209
|
+
const allRecords = [];
|
|
210
|
+
for (const shardPath of shards) {
|
|
211
|
+
const records = readShard(shardPath);
|
|
212
|
+
allRecords.push(...records);
|
|
213
|
+
}
|
|
214
|
+
return allRecords;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Removes dangling relationships that reference non-existent entities.
|
|
218
|
+
*/
|
|
219
|
+
export function pruneDangling(records, validEntityIds) {
|
|
220
|
+
return records.filter((record) => validEntityIds.has(record.from) && validEntityIds.has(record.to));
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Generates a deterministic relationship ID.
|
|
224
|
+
*/
|
|
225
|
+
export function relationshipIdFor(type, from, to) {
|
|
226
|
+
const hash = crypto
|
|
227
|
+
.createHash("sha256")
|
|
228
|
+
.update(`${type}|${from}|${to}`)
|
|
229
|
+
.digest("hex");
|
|
230
|
+
return `rel-${hash.slice(0, 12)}`;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Merges existing and incoming relationship records.
|
|
234
|
+
* Deduplicates by (type, from, to) tuple.
|
|
235
|
+
* On conflict, keeps the record with newer created_at timestamp.
|
|
236
|
+
*/
|
|
237
|
+
export function mergeRecords(existing, incoming) {
|
|
238
|
+
const recordMap = new Map();
|
|
239
|
+
// Helper to create key from record
|
|
240
|
+
const makeKey = (r) => `${r.type}|${r.from}|${r.to}`;
|
|
241
|
+
// Add existing records
|
|
242
|
+
for (const record of existing) {
|
|
243
|
+
recordMap.set(makeKey(record), record);
|
|
244
|
+
}
|
|
245
|
+
// Merge incoming records
|
|
246
|
+
for (const record of incoming) {
|
|
247
|
+
const key = makeKey(record);
|
|
248
|
+
const existingRecord = recordMap.get(key);
|
|
249
|
+
if (!existingRecord) {
|
|
250
|
+
// New record
|
|
251
|
+
recordMap.set(key, record);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
// Conflict - keep newer based on created_at
|
|
255
|
+
const existingTime = new Date(existingRecord.created_at).getTime();
|
|
256
|
+
const incomingTime = new Date(record.created_at).getTime();
|
|
257
|
+
if (incomingTime >= existingTime) {
|
|
258
|
+
recordMap.set(key, record);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return Array.from(recordMap.values());
|
|
263
|
+
}
|
|
@@ -10,6 +10,9 @@ export interface StagedFile {
|
|
|
10
10
|
hunkRanges: HunkRange[];
|
|
11
11
|
content?: string;
|
|
12
12
|
}
|
|
13
|
+
type ExecFn = (cmd: string, opts: {
|
|
14
|
+
encoding: "utf8";
|
|
15
|
+
}) => string;
|
|
13
16
|
/**
|
|
14
17
|
* Parse null-separated name-status output from git
|
|
15
18
|
*/
|
|
@@ -24,6 +27,6 @@ export declare function parseHunksFromDiff(diffText: string, isNewFile?: boolean
|
|
|
24
27
|
/**
|
|
25
28
|
* Get staged files with statuses, hunks and content.
|
|
26
29
|
*/
|
|
27
|
-
export declare function getStagedFiles(): StagedFile[];
|
|
30
|
+
export declare function getStagedFiles(exec?: ExecFn): StagedFile[];
|
|
28
31
|
export default getStagedFiles;
|
|
29
32
|
//# sourceMappingURL=git-staged.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-staged.d.ts","sourceRoot":"","sources":["../../src/traceability/git-staged.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAE3C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"git-staged.d.ts","sourceRoot":"","sources":["../../src/traceability/git-staged.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAE3C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,MAAM,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,KAAK,MAAM,CAAC;AAalE;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,GACZ,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAS5C;AAsCD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,SAAS,UAAQ,GAChB,SAAS,EAAE,CAoBb;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE,MAAiB,GAAG,UAAU,EAAE,CA4FpE;AAED,eAAe,cAAc,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { execSync } from "node:child_process";
|
|
2
|
-
function runGit(cmd) {
|
|
2
|
+
function runGit(cmd, exec) {
|
|
3
3
|
try {
|
|
4
|
-
return
|
|
4
|
+
return exec(cmd, { encoding: "utf8" });
|
|
5
5
|
}
|
|
6
6
|
catch (err) {
|
|
7
7
|
// wrap common errors
|
|
@@ -35,6 +35,12 @@ const SUPPORTED_EXT = new Set([
|
|
|
35
35
|
".cjs",
|
|
36
36
|
]);
|
|
37
37
|
const ENTITY_MARKDOWN_DIRS = ["/requirements/", "/scenarios/", "/tests/"];
|
|
38
|
+
function shouldLogTraceDebug() {
|
|
39
|
+
return Boolean(process.env.KIBI_TRACE || process.env.KIBI_DEBUG);
|
|
40
|
+
}
|
|
41
|
+
function escapePath(p) {
|
|
42
|
+
return p.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
43
|
+
}
|
|
38
44
|
function hasSupportedExt(p) {
|
|
39
45
|
for (const ext of SUPPORTED_EXT) {
|
|
40
46
|
if (p.endsWith(ext))
|
|
@@ -80,11 +86,11 @@ export function parseHunksFromDiff(diffText, isNewFile = false) {
|
|
|
80
86
|
/**
|
|
81
87
|
* Get staged files with statuses, hunks and content.
|
|
82
88
|
*/
|
|
83
|
-
export function getStagedFiles() {
|
|
89
|
+
export function getStagedFiles(exec = execSync) {
|
|
84
90
|
// 1. get staged name-status -z
|
|
85
91
|
let nameStatus;
|
|
86
92
|
try {
|
|
87
|
-
nameStatus = runGit("git diff --cached --name-status -z --diff-filter=ACMRD");
|
|
93
|
+
nameStatus = runGit("git diff --cached --name-status -z --diff-filter=ACMRD", exec);
|
|
88
94
|
}
|
|
89
95
|
catch (err) {
|
|
90
96
|
throw new Error(`failed to list staged files: ${String(err)}`);
|
|
@@ -95,8 +101,9 @@ export function getStagedFiles() {
|
|
|
95
101
|
const statusRaw = entry.status;
|
|
96
102
|
const status = statusRaw[0] || "M";
|
|
97
103
|
if (status === "D") {
|
|
98
|
-
|
|
99
|
-
|
|
104
|
+
if (shouldLogTraceDebug()) {
|
|
105
|
+
console.debug(`Skipping deleted file (staged): ${entry.parts.join(" -> ")}`);
|
|
106
|
+
}
|
|
100
107
|
continue;
|
|
101
108
|
}
|
|
102
109
|
// handle renames: parts = [old, new]
|
|
@@ -109,17 +116,21 @@ export function getStagedFiles() {
|
|
|
109
116
|
}
|
|
110
117
|
}
|
|
111
118
|
if (!hasSupportedExt(path) && !isEntityMarkdown(path)) {
|
|
112
|
-
|
|
119
|
+
if (shouldLogTraceDebug()) {
|
|
120
|
+
console.debug(`Skipping unsupported extension: ${path}`);
|
|
121
|
+
}
|
|
113
122
|
continue;
|
|
114
123
|
}
|
|
115
124
|
// 4. compute hunks using git diff --cached -U0 -- <path>
|
|
116
125
|
let diffText = "";
|
|
117
126
|
try {
|
|
118
127
|
// use new path for diff; quote the path to handle spaces
|
|
119
|
-
diffText = runGit(`git diff --cached -U0 -- "${path
|
|
128
|
+
diffText = runGit(`git diff --cached -U0 -- "${escapePath(path)}"`, exec);
|
|
120
129
|
}
|
|
121
130
|
catch (err) {
|
|
122
|
-
|
|
131
|
+
if (shouldLogTraceDebug()) {
|
|
132
|
+
console.debug(`Failed to get diff for ${path}: ${String(err)}`);
|
|
133
|
+
}
|
|
123
134
|
diffText = "";
|
|
124
135
|
}
|
|
125
136
|
// determine if new file: status 'A' or diff contains /dev/null in old file path
|
|
@@ -128,13 +139,15 @@ export function getStagedFiles() {
|
|
|
128
139
|
// 5. read staged content using git show :<path>
|
|
129
140
|
let content;
|
|
130
141
|
try {
|
|
131
|
-
content = runGit(`git show :"${path
|
|
142
|
+
content = runGit(`git show :"${escapePath(path)}"`, exec);
|
|
132
143
|
}
|
|
133
144
|
catch (err) {
|
|
134
145
|
// binary or deleted in index
|
|
135
146
|
const e = err;
|
|
136
147
|
const em = e?.message ? String(e.message) : String(err);
|
|
137
|
-
|
|
148
|
+
if (shouldLogTraceDebug()) {
|
|
149
|
+
console.debug(`Skipping binary/deleted or unreadable staged file ${path}: ${em}`);
|
|
150
|
+
}
|
|
138
151
|
continue;
|
|
139
152
|
}
|
|
140
153
|
// If we had a new-file sentinel (end = MAX_SAFE_INTEGER) set a realistic end as content lines
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changeset.d.ts","sourceRoot":"","sources":["../../src/types/changeset.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"changeset.d.ts","sourceRoot":"","sources":["../../src/types/changeset.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,gBAAgB,MAAM,iBAAiB,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,QAAQ,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,QAAQ,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,MAAM,kBAAkB,GAAG,eAAe,GAAG,eAAe,CAAC;AAEnE,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,QAAQ,CAAC,EAAE;QACT,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,eAAe,SAAS,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../../src/types/entities.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../../src/types/entities.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,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,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AACvD,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AACzD,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AACvD,MAAM,MAAM,GAAG,GAAG,UAAU,GAAG;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAC/C,MAAM,MAAM,IAAI,GAAG,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AACjD,MAAM,MAAM,KAAK,GAAG,UAAU,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AACnD,MAAM,MAAM,MAAM,GAAG,UAAU,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AACrD,MAAM,MAAM,IAAI,GAAG,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,MAAM,MAAM,MAAM,GACd,WAAW,GACX,QAAQ,GACR,UAAU,GACV,GAAG,GACH,IAAI,GACJ,KAAK,GACL,MAAM,GACN,IAAI,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../../src/types/relationships.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../../src/types/relationships.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EACA,YAAY,GACZ,cAAc,GACd,aAAa,GACb,YAAY,GACZ,YAAY,GACZ,gBAAgB,GAChB,YAAY,GACZ,mBAAmB,GACnB,QAAQ,GACR,WAAW,GACX,UAAU,GACV,YAAY,GACZ,YAAY,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAe,gBAAgB,CAAC"}
|
|
@@ -56,6 +56,10 @@ export declare function copyCleanSnapshot(sourcePath: string, targetPath: string
|
|
|
56
56
|
*/
|
|
57
57
|
export declare function getVolatileArtifactPatterns(): string[];
|
|
58
58
|
/**
|
|
59
|
+
* @deprecated defaultBranch is deprecated. Branch lifecycle now follows git naturally
|
|
60
|
+
* without requiring a configured default. This function is kept for backward compatibility
|
|
61
|
+
* but should not be used for new code.
|
|
62
|
+
*
|
|
59
63
|
* Resolve the default branch using the following precedence:
|
|
60
64
|
* 1. Configured defaultBranch from config (if set and valid)
|
|
61
65
|
* 2. Git remote HEAD (refs/remotes/origin/HEAD)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/branch-resolver.ts"],"names":[],"mappings":"AA4BA,MAAM,MAAM,uBAAuB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACzD,MAAM,MAAM,qBAAqB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC;AAC7E,MAAM,MAAM,sBAAsB,GAC9B,uBAAuB,GACvB,qBAAqB,CAAC;AAE1B,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,eAAe,GACf,eAAe,GACf,mBAAmB,GACnB,gBAAgB,GAChB,eAAe,CAAC;AA8BpB;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,GAAE,MAAsB,GACpC,sBAAsB,CAmHxB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,aAAa,GAAE,MAAsB,GAAG,OAAO,CAa7E;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,KAAK,EAAE,MAAM,GACZ,MAAM,CAuBR;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAuBvD;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,IAAI,CAUN;AA6BD;;;;;GAKG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,EAAE,CAMtD;AAED
|
|
1
|
+
{"version":3,"file":"branch-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/branch-resolver.ts"],"names":[],"mappings":"AA4BA,MAAM,MAAM,uBAAuB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACzD,MAAM,MAAM,qBAAqB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC;AAC7E,MAAM,MAAM,sBAAsB,GAC9B,uBAAuB,GACvB,qBAAqB,CAAC;AAE1B,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,eAAe,GACf,eAAe,GACf,mBAAmB,GACnB,gBAAgB,GAChB,eAAe,CAAC;AA8BpB;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,GAAE,MAAsB,GACpC,sBAAsB,CAmHxB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,aAAa,GAAE,MAAsB,GAAG,OAAO,CAa7E;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,KAAK,EAAE,MAAM,GACZ,MAAM,CAuBR;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAuBvD;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,IAAI,CAUN;AA6BD;;;;;GAKG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,EAAE,CAMtD;AAED;;;;;;;;;;;;;;;;GAgBG;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,CAqCtD"}
|
|
@@ -261,6 +261,10 @@ export function getVolatileArtifactPatterns() {
|
|
|
261
261
|
];
|
|
262
262
|
}
|
|
263
263
|
/**
|
|
264
|
+
* @deprecated defaultBranch is deprecated. Branch lifecycle now follows git naturally
|
|
265
|
+
* without requiring a configured default. This function is kept for backward compatibility
|
|
266
|
+
* but should not be used for new code.
|
|
267
|
+
*
|
|
264
268
|
* Resolve the default branch using the following precedence:
|
|
265
269
|
* 1. Configured defaultBranch from config (if set and valid)
|
|
266
270
|
* 2. Git remote HEAD (refs/remotes/origin/HEAD)
|