kibi-cli 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-json-command.d.ts.map +1 -1
- package/dist/cli-json-command.js +2 -2
- package/dist/cli-operation-metadata.d.ts +1 -1
- package/dist/cli-operation-metadata.js +1 -1
- package/dist/cli-register-maintenance.d.ts.map +1 -1
- package/dist/cli-register-maintenance.js +7 -0
- package/dist/commands/merge-driver.d.ts +31 -0
- package/dist/commands/merge-driver.d.ts.map +1 -0
- package/dist/commands/merge-driver.js +268 -0
- package/dist/operations/bootstrap/candidates.js +1 -1
- package/dist/operations/bootstrap/discovery.js +1 -1
- package/dist/operations/bootstrap/generate.d.ts.map +1 -1
- package/dist/operations/bootstrap/generate.js +21 -5
- package/dist/operations/bootstrap/guidance-actions.d.ts.map +1 -1
- package/dist/operations/bootstrap/guidance-actions.js +3 -0
- package/dist/operations/bootstrap/guidance.d.ts.map +1 -1
- package/dist/operations/bootstrap/guidance.js +7 -1
- package/dist/operations/bootstrap/intent-claims.d.ts +17 -0
- package/dist/operations/bootstrap/intent-claims.d.ts.map +1 -0
- package/dist/operations/bootstrap/intent-claims.js +95 -0
- package/dist/operations/bootstrap/presentation.d.ts +2 -0
- package/dist/operations/bootstrap/presentation.d.ts.map +1 -1
- package/dist/operations/bootstrap/presentation.js +60 -1
- package/dist/operations/bootstrap/types.d.ts +28 -0
- package/dist/operations/bootstrap/types.d.ts.map +1 -1
- package/dist/operations/bootstrap/types.js +16 -0
- package/dist/operations/mutation/symbol-refresh.d.ts.map +1 -1
- package/dist/operations/mutation/symbol-refresh.js +4 -1
- package/dist/public/diagnostic-usage.d.ts +14 -0
- package/dist/public/diagnostic-usage.d.ts.map +1 -1
- package/dist/public/diagnostic-usage.js +55 -1
- package/dist/public/operations/catalog.d.ts +73 -1
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/specs/bootstrap.d.ts +73 -1
- package/dist/public/operations/specs/bootstrap.d.ts.map +1 -1
- package/dist/public/operations/specs/bootstrap.js +66 -1
- package/dist/public/operations/symbol-repair-plan.d.ts.map +1 -1
- package/dist/public/operations/symbol-repair-plan.js +3 -1
- package/dist/public/skills/kibi-bootstrap/SKILL.md +47 -11
- package/dist/public/skills/kibi-bootstrap/resources/bootstrap.md +6 -1
- package/dist/public/skills/kibi-usage/SKILL.md +14 -0
- package/dist/public/skills/kibi-usage/resources/operation-access.md +4 -0
- package/dist/public/telemetry-acceptance.d.ts +8 -0
- package/dist/public/telemetry-acceptance.d.ts.map +1 -1
- package/dist/public/telemetry-acceptance.js +10 -0
- package/package.json +1 -1
- package/src/public/diagnostic-usage.ts +59 -1
- package/src/public/operations/specs/bootstrap.ts +78 -4
- package/src/public/operations/symbol-repair-plan.ts +3 -1
- package/src/public/skills/kibi-bootstrap/SKILL.md +47 -11
- package/src/public/skills/kibi-bootstrap/resources/bootstrap.md +6 -1
- package/src/public/skills/kibi-usage/SKILL.md +14 -0
- package/src/public/skills/kibi-usage/resources/operation-access.md +4 -0
- package/src/public/telemetry-acceptance.ts +9 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-json-command.d.ts","sourceRoot":"","sources":["../src/cli-json-command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"cli-json-command.d.ts","sourceRoot":"","sources":["../src/cli-json-command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAGlE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAIpE;AAGD,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS;QAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;KACpC,EAAE,CAAC;CACL,CAAC;AAkDF,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,cAAc,GACzB,OAAO,CAAC,IAAI,CAAC,CAuGf"}
|
package/dist/cli-json-command.js
CHANGED
|
@@ -4,7 +4,7 @@ import { loadInput } from "./cli-input.js";
|
|
|
4
4
|
import { loadOperationSpec } from "./cli-operation-loader.js";
|
|
5
5
|
import { executeOperation as executeProtocolOperation } from "./cli-protocol.js";
|
|
6
6
|
import { prepareOperationInput } from "./cli-validate.js";
|
|
7
|
-
import { appendCliDiagnosticUsage } from "./public/diagnostic-usage.js";
|
|
7
|
+
import { appendCliDiagnosticUsage, diagnosticEnvOptIn, } from "./public/diagnostic-usage.js";
|
|
8
8
|
import { createCliRuntime } from "./runtime/cli-runtime.js";
|
|
9
9
|
export function writeOptionalStderr(stderr) {
|
|
10
10
|
if (stderr !== undefined) {
|
|
@@ -30,7 +30,7 @@ function findInputConflicts(invocation) {
|
|
|
30
30
|
return [...positionalConflicts, ...optionConflicts];
|
|
31
31
|
}
|
|
32
32
|
function diagnosticModeEnabled(command) {
|
|
33
|
-
return (
|
|
33
|
+
return (diagnosticEnvOptIn() ||
|
|
34
34
|
process.argv.includes("--diagnostic-mode") ||
|
|
35
35
|
command.optsWithGlobals().diagnosticMode === true);
|
|
36
36
|
}
|
|
@@ -55,7 +55,7 @@ export declare const CLI_OPERATION_METADATA: readonly [{
|
|
|
55
55
|
}, {
|
|
56
56
|
readonly name: "kb_plan_bootstrap";
|
|
57
57
|
readonly cliName: "plan-bootstrap";
|
|
58
|
-
readonly description: "Generate a deterministic, snapshot-bound kibi.bootstrap-plan.v1 for repository onboarding. Read-only analysis returns evidence, bounded context questions, exact dependency-ordered actions, a canonical plan hash, and no mutation side effects.";
|
|
58
|
+
readonly description: "Generate a deterministic, snapshot-bound kibi.bootstrap-plan.v1 for repository onboarding. Read-only analysis of the repository plus any declared knowledge sources and cited intent claims returns evidence, bounded context questions, exact dependency-ordered actions, a canonical plan hash, and no mutation side effects.";
|
|
59
59
|
}, {
|
|
60
60
|
readonly name: "kb_validate_upsert";
|
|
61
61
|
readonly cliName: "validate-upsert";
|
|
@@ -65,7 +65,7 @@ export const CLI_OPERATION_METADATA = [
|
|
|
65
65
|
{
|
|
66
66
|
name: "kb_plan_bootstrap",
|
|
67
67
|
cliName: "plan-bootstrap",
|
|
68
|
-
description: "Generate a deterministic, snapshot-bound kibi.bootstrap-plan.v1 for repository onboarding. Read-only analysis returns evidence, bounded context questions, exact dependency-ordered actions, a canonical plan hash, and no mutation side effects.",
|
|
68
|
+
description: "Generate a deterministic, snapshot-bound kibi.bootstrap-plan.v1 for repository onboarding. Read-only analysis of the repository plus any declared knowledge sources and cited intent claims returns evidence, bounded context questions, exact dependency-ordered actions, a canonical plan hash, and no mutation side effects.",
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
name: "kb_validate_upsert",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-register-maintenance.d.ts","sourceRoot":"","sources":["../src/cli-register-maintenance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"cli-register-maintenance.d.ts","sourceRoot":"","sources":["../src/cli-register-maintenance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6KlE"}
|
|
@@ -68,6 +68,13 @@ export function registerMaintenanceCommands(program) {
|
|
|
68
68
|
.option("--format <format>", "Output format: json|table", "table")
|
|
69
69
|
.option("--limit <n>", "Limit rendered table rows", "50")
|
|
70
70
|
.action(withExitCode(async (options) => (await import("./commands/usage-remediation.js")).usageRemediationCommand(options)));
|
|
71
|
+
program
|
|
72
|
+
.command("merge-driver")
|
|
73
|
+
.description("Git merge driver: three-way merge .kb/symbols.yaml or a relationship shard by record id")
|
|
74
|
+
.argument("<base>", "Common ancestor version (%O)")
|
|
75
|
+
.argument("<current>", "Current version, overwritten with the result (%A)")
|
|
76
|
+
.argument("<other>", "Other branch's version (%B)")
|
|
77
|
+
.action(withExitCode(async (base, current, other) => (await import("./commands/merge-driver.js")).mergeDriverCommand(base, current, other)));
|
|
71
78
|
program
|
|
72
79
|
.command("branch")
|
|
73
80
|
.description("Manage branch KBs")
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CommandResult } from "../cli-command.js";
|
|
2
|
+
export type KbManifestMergeResult = {
|
|
3
|
+
readonly status: "merged";
|
|
4
|
+
readonly content: string;
|
|
5
|
+
} | {
|
|
6
|
+
readonly status: "conflict";
|
|
7
|
+
readonly conflicts: readonly string[];
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Three-way merge of an id-keyed Kibi manifest (`.kb/symbols.yaml` or a
|
|
11
|
+
* `.kb/relationships/*.yaml` shard).
|
|
12
|
+
*
|
|
13
|
+
* Both sides usually append new records at the end of the list, which Git
|
|
14
|
+
* reports as a conflict although the additions are independent. This merge
|
|
15
|
+
* keeps every record either side added, applies edits made on only one
|
|
16
|
+
* side, honors a deletion made on one side when the other left the record
|
|
17
|
+
* unchanged, and unions concurrent relationship and link additions on one
|
|
18
|
+
* symbol. Anything else both sides changed differently is a real conflict
|
|
19
|
+
* and is reported rather than guessed.
|
|
20
|
+
*/
|
|
21
|
+
export declare function mergeKbManifests(baseContent: string, oursContent: string, theirsContent: string): KbManifestMergeResult;
|
|
22
|
+
/**
|
|
23
|
+
* Git merge driver entry point: `kibi merge-driver %O %A %B`.
|
|
24
|
+
*
|
|
25
|
+
* Writes the merged manifest to the current (`%A`) file and exits 0. On a
|
|
26
|
+
* real conflict it prints each one and falls back to Git's textual merge so
|
|
27
|
+
* the file carries ordinary conflict markers, then exits 1 so Git keeps the
|
|
28
|
+
* path unmerged.
|
|
29
|
+
*/
|
|
30
|
+
export declare function mergeDriverCommand(basePath: string, currentPath: string, otherPath: string): Promise<CommandResult>;
|
|
31
|
+
//# sourceMappingURL=merge-driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-driver.d.ts","sourceRoot":"","sources":["../../src/commands/merge-driver.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAiBvD,MAAM,MAAM,qBAAqB,GAC7B;IAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAoI3E;;;;;;;;;;;GAWG;AAEH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,GACpB,qBAAqB,CAyFvB;AAWD;;;;;;;GAOG;AAEH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC,CA8BxB"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { isMap, isSeq, parseDocument } from "yaml";
|
|
4
|
+
/**
|
|
5
|
+
* Same serialization options as authored manifest writes, so a merge that
|
|
6
|
+
* changes nothing reproduces the input bytes and edits never refold rows.
|
|
7
|
+
*/
|
|
8
|
+
const AUTHORED_YAML_OPTIONS = { lineWidth: 0 };
|
|
9
|
+
/**
|
|
10
|
+
* Top-level lists Kibi keeps keyed by `id`: `.kb/symbols.yaml` and the
|
|
11
|
+
* `.kb/relationships/*.yaml` shards.
|
|
12
|
+
*/
|
|
13
|
+
const ID_KEYED_LISTS = ["symbols", "relationships"];
|
|
14
|
+
/** Record fields whose values are sets: concurrent additions union instead of conflicting. */
|
|
15
|
+
const SET_FIELDS = new Set(["relationships", "links"]);
|
|
16
|
+
function canonical(value) {
|
|
17
|
+
if (Array.isArray(value))
|
|
18
|
+
return `[${value.map(canonical).join(",")}]`;
|
|
19
|
+
if (value && typeof value === "object") {
|
|
20
|
+
const entries = Object.entries(value)
|
|
21
|
+
.filter(([, entry]) => entry !== undefined)
|
|
22
|
+
.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0));
|
|
23
|
+
return `{${entries
|
|
24
|
+
.map(([key, entry]) => `${JSON.stringify(key)}:${canonical(entry)}`)
|
|
25
|
+
.join(",")}}`;
|
|
26
|
+
}
|
|
27
|
+
return JSON.stringify(value) ?? "undefined";
|
|
28
|
+
}
|
|
29
|
+
function same(left, right) {
|
|
30
|
+
return canonical(left) === canonical(right);
|
|
31
|
+
}
|
|
32
|
+
function parseManifest(label, content, conflicts) {
|
|
33
|
+
const doc = parseDocument(content);
|
|
34
|
+
if (doc.errors.length > 0) {
|
|
35
|
+
conflicts.push(`${label}: not valid YAML (${doc.errors[0]?.message})`);
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const top = doc.toJS() ?? {};
|
|
39
|
+
if (typeof top !== "object" || Array.isArray(top)) {
|
|
40
|
+
conflicts.push(`${label}: top level is not a mapping`);
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const listKeys = ID_KEYED_LISTS.filter((key) => key in top);
|
|
44
|
+
if (listKeys.length > 1) {
|
|
45
|
+
conflicts.push(`${label}: holds both ${listKeys.join(" and ")}`);
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const listKey = listKeys[0];
|
|
49
|
+
const rest = { ...top };
|
|
50
|
+
if (listKey)
|
|
51
|
+
delete rest[listKey];
|
|
52
|
+
const records = new Map();
|
|
53
|
+
const order = [];
|
|
54
|
+
const seq = listKey ? doc.get(listKey, true) : undefined;
|
|
55
|
+
if (seq === undefined || seq === null) {
|
|
56
|
+
return { doc, listKey, records, order, rest };
|
|
57
|
+
}
|
|
58
|
+
if (!isSeq(seq)) {
|
|
59
|
+
conflicts.push(`${label}: ${listKey} is not a list`);
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
for (const item of seq.items) {
|
|
63
|
+
const id = isMap(item) ? item.get("id") : undefined;
|
|
64
|
+
if (!isMap(item) || typeof id !== "string" || !id) {
|
|
65
|
+
conflicts.push(`${label}: ${listKey} entry without a string id`);
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
if (records.has(id)) {
|
|
69
|
+
conflicts.push(`${label}: duplicate id ${id}`);
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
records.set(id, { node: item, value: item.toJS(doc) });
|
|
73
|
+
order.push(id);
|
|
74
|
+
}
|
|
75
|
+
return { doc, listKey, records, order, rest };
|
|
76
|
+
}
|
|
77
|
+
/** Three-way merge of a set-valued field: keep ours, drop their removals, add their additions. */
|
|
78
|
+
function mergeSet(base, ours, theirs) {
|
|
79
|
+
const list = (value) => (Array.isArray(value) ? value : []);
|
|
80
|
+
const baseKeys = new Set(list(base).map(canonical));
|
|
81
|
+
const theirKeys = new Set(list(theirs).map(canonical));
|
|
82
|
+
const merged = list(ours).filter((entry) => {
|
|
83
|
+
const key = canonical(entry);
|
|
84
|
+
return !(baseKeys.has(key) && !theirKeys.has(key));
|
|
85
|
+
});
|
|
86
|
+
const mergedKeys = new Set(merged.map(canonical));
|
|
87
|
+
for (const entry of list(theirs)) {
|
|
88
|
+
const key = canonical(entry);
|
|
89
|
+
if (baseKeys.has(key) || mergedKeys.has(key))
|
|
90
|
+
continue;
|
|
91
|
+
merged.push(entry);
|
|
92
|
+
mergedKeys.add(key);
|
|
93
|
+
}
|
|
94
|
+
return merged;
|
|
95
|
+
}
|
|
96
|
+
function mergeRecord(id, base, ours, theirs, conflicts) {
|
|
97
|
+
const merged = {};
|
|
98
|
+
const keys = [
|
|
99
|
+
...Object.keys(ours),
|
|
100
|
+
...Object.keys(theirs).filter((key) => !(key in ours)),
|
|
101
|
+
];
|
|
102
|
+
for (const key of keys) {
|
|
103
|
+
const baseValue = base?.[key];
|
|
104
|
+
const ourValue = ours[key];
|
|
105
|
+
const theirValue = theirs[key];
|
|
106
|
+
let value;
|
|
107
|
+
if (same(ourValue, theirValue) || same(theirValue, baseValue)) {
|
|
108
|
+
value = ourValue;
|
|
109
|
+
}
|
|
110
|
+
else if (same(ourValue, baseValue)) {
|
|
111
|
+
value = theirValue;
|
|
112
|
+
}
|
|
113
|
+
else if (SET_FIELDS.has(key) &&
|
|
114
|
+
[baseValue, ourValue, theirValue].every((entry) => entry === undefined || Array.isArray(entry))) {
|
|
115
|
+
value = mergeSet(baseValue, ourValue, theirValue);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
conflicts.push(`${id}: both sides changed ${key}`);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (value !== undefined)
|
|
122
|
+
merged[key] = value;
|
|
123
|
+
}
|
|
124
|
+
return merged;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Three-way merge of an id-keyed Kibi manifest (`.kb/symbols.yaml` or a
|
|
128
|
+
* `.kb/relationships/*.yaml` shard).
|
|
129
|
+
*
|
|
130
|
+
* Both sides usually append new records at the end of the list, which Git
|
|
131
|
+
* reports as a conflict although the additions are independent. This merge
|
|
132
|
+
* keeps every record either side added, applies edits made on only one
|
|
133
|
+
* side, honors a deletion made on one side when the other left the record
|
|
134
|
+
* unchanged, and unions concurrent relationship and link additions on one
|
|
135
|
+
* symbol. Anything else both sides changed differently is a real conflict
|
|
136
|
+
* and is reported rather than guessed.
|
|
137
|
+
*/
|
|
138
|
+
// implements REQ-cli-kb-merge-driver
|
|
139
|
+
export function mergeKbManifests(baseContent, oursContent, theirsContent) {
|
|
140
|
+
const conflicts = [];
|
|
141
|
+
const base = parseManifest("base", baseContent, conflicts);
|
|
142
|
+
const ours = parseManifest("ours", oursContent, conflicts);
|
|
143
|
+
const theirs = parseManifest("theirs", theirsContent, conflicts);
|
|
144
|
+
if (!base || !ours || !theirs)
|
|
145
|
+
return { status: "conflict", conflicts };
|
|
146
|
+
const listKeys = new Set([base.listKey, ours.listKey, theirs.listKey].filter(Boolean));
|
|
147
|
+
if (listKeys.size > 1) {
|
|
148
|
+
return {
|
|
149
|
+
status: "conflict",
|
|
150
|
+
conflicts: [`sides hold different lists: ${[...listKeys].join(", ")}`],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const listKey = ours.listKey ?? theirs.listKey;
|
|
154
|
+
if (!same(ours.rest, theirs.rest) && !same(theirs.rest, base.rest)) {
|
|
155
|
+
if (!same(ours.rest, base.rest)) {
|
|
156
|
+
return {
|
|
157
|
+
status: "conflict",
|
|
158
|
+
conflicts: ["both sides changed top-level manifest fields"],
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
for (const key of Object.keys(ours.rest)) {
|
|
162
|
+
if (!(key in theirs.rest))
|
|
163
|
+
ours.doc.delete(key);
|
|
164
|
+
}
|
|
165
|
+
for (const [key, value] of Object.entries(theirs.rest)) {
|
|
166
|
+
ours.doc.set(key, value);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (!listKey) {
|
|
170
|
+
return {
|
|
171
|
+
status: "merged",
|
|
172
|
+
content: ours.doc.toString(AUTHORED_YAML_OPTIONS),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const items = [];
|
|
176
|
+
for (const id of ours.order) {
|
|
177
|
+
const ourRecord = ours.records.get(id);
|
|
178
|
+
if (!ourRecord)
|
|
179
|
+
continue;
|
|
180
|
+
const baseRecord = base.records.get(id);
|
|
181
|
+
const theirRecord = theirs.records.get(id);
|
|
182
|
+
if (!theirRecord) {
|
|
183
|
+
if (!baseRecord)
|
|
184
|
+
items.push(ourRecord.node);
|
|
185
|
+
else if (!same(ourRecord.value, baseRecord.value)) {
|
|
186
|
+
conflicts.push(`${id}: changed on ours but deleted on theirs`);
|
|
187
|
+
}
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (same(ourRecord.value, theirRecord.value) ||
|
|
191
|
+
(baseRecord && same(theirRecord.value, baseRecord.value))) {
|
|
192
|
+
items.push(ourRecord.node);
|
|
193
|
+
}
|
|
194
|
+
else if (baseRecord && same(ourRecord.value, baseRecord.value)) {
|
|
195
|
+
items.push(theirRecord.node.clone());
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
const merged = mergeRecord(id, baseRecord?.value, ourRecord.value, theirRecord.value, conflicts);
|
|
199
|
+
items.push(ours.doc.createNode(merged));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
for (const id of theirs.order) {
|
|
203
|
+
if (ours.records.has(id))
|
|
204
|
+
continue;
|
|
205
|
+
const theirRecord = theirs.records.get(id);
|
|
206
|
+
if (!theirRecord)
|
|
207
|
+
continue;
|
|
208
|
+
const baseRecord = base.records.get(id);
|
|
209
|
+
if (!baseRecord)
|
|
210
|
+
items.push(theirRecord.node.clone());
|
|
211
|
+
else if (!same(theirRecord.value, baseRecord.value)) {
|
|
212
|
+
conflicts.push(`${id}: deleted on ours but changed on theirs`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (conflicts.length > 0)
|
|
216
|
+
return { status: "conflict", conflicts };
|
|
217
|
+
const seq = ours.doc.get(listKey, true);
|
|
218
|
+
if (isSeq(seq))
|
|
219
|
+
seq.items = items;
|
|
220
|
+
else
|
|
221
|
+
ours.doc.set(listKey, ours.doc.createNode(items));
|
|
222
|
+
return {
|
|
223
|
+
status: "merged",
|
|
224
|
+
content: ours.doc.toString(AUTHORED_YAML_OPTIONS),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
function readOptional(filePath) {
|
|
228
|
+
try {
|
|
229
|
+
return readFileSync(filePath, "utf8");
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
if (error.code === "ENOENT")
|
|
233
|
+
return "";
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Git merge driver entry point: `kibi merge-driver %O %A %B`.
|
|
239
|
+
*
|
|
240
|
+
* Writes the merged manifest to the current (`%A`) file and exits 0. On a
|
|
241
|
+
* real conflict it prints each one and falls back to Git's textual merge so
|
|
242
|
+
* the file carries ordinary conflict markers, then exits 1 so Git keeps the
|
|
243
|
+
* path unmerged.
|
|
244
|
+
*/
|
|
245
|
+
// implements REQ-cli-kb-merge-driver
|
|
246
|
+
export async function mergeDriverCommand(basePath, currentPath, otherPath) {
|
|
247
|
+
const result = mergeKbManifests(readOptional(basePath), readFileSync(currentPath, "utf8"), readFileSync(otherPath, "utf8"));
|
|
248
|
+
if (result.status === "merged") {
|
|
249
|
+
writeFileSync(currentPath, result.content);
|
|
250
|
+
return { exitCode: 0 };
|
|
251
|
+
}
|
|
252
|
+
for (const conflict of result.conflicts) {
|
|
253
|
+
console.error(`kibi merge-driver: ${conflict}`);
|
|
254
|
+
}
|
|
255
|
+
spawnSync("git", [
|
|
256
|
+
"merge-file",
|
|
257
|
+
"-L",
|
|
258
|
+
"ours",
|
|
259
|
+
"-L",
|
|
260
|
+
"base",
|
|
261
|
+
"-L",
|
|
262
|
+
"theirs",
|
|
263
|
+
currentPath,
|
|
264
|
+
basePath,
|
|
265
|
+
otherPath,
|
|
266
|
+
], { stdio: "inherit" });
|
|
267
|
+
return { exitCode: 1 };
|
|
268
|
+
}
|
|
@@ -91,7 +91,7 @@ function providerCandidate(item, existingIds, minConfidence) {
|
|
|
91
91
|
},
|
|
92
92
|
];
|
|
93
93
|
}
|
|
94
|
-
// implements REQ-
|
|
94
|
+
// implements REQ-KIBI-BOOTSTRAP-PLAN, REQ-kibi-operation-interface-parity
|
|
95
95
|
// implements REQ-KIBI-BOOTSTRAP-PLAN
|
|
96
96
|
export function buildBootstrapCandidates(evidence, existingIds, minConfidence, includeGenericMarkdown) {
|
|
97
97
|
const candidates = [];
|
|
@@ -63,7 +63,7 @@ function frameworks(evidence) {
|
|
|
63
63
|
: [])),
|
|
64
64
|
].sort();
|
|
65
65
|
}
|
|
66
|
-
// implements REQ-
|
|
66
|
+
// implements REQ-KIBI-BOOTSTRAP-PLAN, REQ-kibi-operation-interface-parity
|
|
67
67
|
// implements REQ-KIBI-BOOTSTRAP-PLAN
|
|
68
68
|
export async function discoverBootstrap(context) {
|
|
69
69
|
const scan = await scanEvidence(context);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/generate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/generate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAMjF,OAAO,KAAK,EACV,SAAS,EACT,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EACpC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GACzC,SAAS,gBAAgB,EAAE,CAI7B;AA2BD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAC1C,OAAO,EAAE,MAAM,GACd;IACD,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;CACnE,CAiDA;AA+GD,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,iBAAiB,EACvB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CA4E9B"}
|
|
@@ -5,7 +5,8 @@ import { executeStatus } from "../../public/operations/discovery-executors.js";
|
|
|
5
5
|
import { readWorkspaceSnapshot } from "../../public/operations/workspace-snapshot.js";
|
|
6
6
|
import { buildBootstrapCandidates } from "./candidates.js";
|
|
7
7
|
import { discoverBootstrap } from "./discovery.js";
|
|
8
|
-
import {
|
|
8
|
+
import { buildIntentClaimCandidates } from "./intent-claims.js";
|
|
9
|
+
import { normalizeBootstrapContext, presentBootstrap } from "./presentation.js";
|
|
9
10
|
export function filterSourceOnlySignals(signals, entityTypes) {
|
|
10
11
|
return entityTypes && entityTypes.length > 0
|
|
11
12
|
? signals.filter((signal) => entityTypes.includes(signal.kind))
|
|
@@ -164,7 +165,7 @@ async function expectedSnapshots(context, evidencePaths) {
|
|
|
164
165
|
};
|
|
165
166
|
}
|
|
166
167
|
}
|
|
167
|
-
// implements REQ-
|
|
168
|
+
// implements REQ-KIBI-BOOTSTRAP-PLAN, REQ-kibi-operation-interface-parity
|
|
168
169
|
// implements REQ-KIBI-BOOTSTRAP-PLAN
|
|
169
170
|
export async function executePlanBootstrap(args, context) {
|
|
170
171
|
const includeGenericMarkdown = args.includeGenericMarkdown ?? true;
|
|
@@ -182,8 +183,18 @@ export async function executePlanBootstrap(args, context) {
|
|
|
182
183
|
const built = discovery.activation.allowCandidateGeneration
|
|
183
184
|
? buildBootstrapCandidates(discovery.evidence, existingIds, minConfidence, includeGenericMarkdown)
|
|
184
185
|
: { candidates: [], sourceOnlySignals: [] };
|
|
185
|
-
|
|
186
|
-
|
|
186
|
+
// Intent harvested from declared knowledge sources joins the repository
|
|
187
|
+
// evidence under the same activation policy, filters, and selection.
|
|
188
|
+
const claimed = discovery.activation.allowCandidateGeneration
|
|
189
|
+
? buildIntentClaimCandidates(normalizeBootstrapContext(args.bootstrapContext), existingIds, minConfidence)
|
|
190
|
+
: {
|
|
191
|
+
candidates: [],
|
|
192
|
+
sourceOnlySignals: [],
|
|
193
|
+
suppressed: [],
|
|
194
|
+
diagnostics: [],
|
|
195
|
+
};
|
|
196
|
+
const filteredSignals = filterSourceOnlySignals([...built.sourceOnlySignals, ...claimed.sourceOnlySignals], args.entityTypes);
|
|
197
|
+
const selected = selectBootstrapCandidates([...built.candidates, ...claimed.candidates].filter((candidate) => candidate.confidence >= minConfidence), existingIds, args.entityTypes, maxCandidates);
|
|
187
198
|
const ignored = discovery.ignoredSources.map((sourcePath) => ({
|
|
188
199
|
candidateId: "",
|
|
189
200
|
reason: "ignored_source",
|
|
@@ -201,8 +212,13 @@ export async function executePlanBootstrap(args, context) {
|
|
|
201
212
|
: {}),
|
|
202
213
|
candidates: selected.candidates,
|
|
203
214
|
sourceOnlySignals: filteredSignals,
|
|
204
|
-
suppressedCandidates: [
|
|
215
|
+
suppressedCandidates: [
|
|
216
|
+
...selected.suppressed,
|
|
217
|
+
...claimed.suppressed,
|
|
218
|
+
...ignored,
|
|
219
|
+
],
|
|
205
220
|
expected,
|
|
206
221
|
bindingDiagnostics,
|
|
222
|
+
contextDiagnostics: claimed.diagnostics,
|
|
207
223
|
});
|
|
208
224
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guidance-actions.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/guidance-actions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,wBAAwB,EACxB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"guidance-actions.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/guidance-actions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,wBAAwB,EACxB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAkBpB,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,gBAAgB,EAC5B,QAAQ,EAAE,wBAAwB,EAClC,UAAU,EAAE,SAAS,SAAS,EAAE,EAChC,OAAO,EAAE,SAAS,gBAAgB,EAAE,GACnC,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAuE9C"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
function relative(root, target) {
|
|
3
|
+
// Intent claims cite tickets and URLs, which are not workspace paths.
|
|
4
|
+
if (!path.isAbsolute(target))
|
|
5
|
+
return target;
|
|
3
6
|
const value = path.relative(root, target);
|
|
4
7
|
return value.startsWith("..") || path.isAbsolute(value)
|
|
5
8
|
? target.split(path.sep).join("/")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guidance.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/guidance.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,gBAAgB,EAChB,wBAAwB,EACxB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"guidance.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/guidance.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,gBAAgB,EAChB,wBAAwB,EACxB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAwFpB,wBAAgB,UAAU,CACxB,UAAU,EAAE,gBAAgB,EAC5B,QAAQ,EAAE,wBAAwB,EAClC,UAAU,EAAE,SAAS,SAAS,EAAE,EAChC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EACpC,WAAW,EAAE,MAAM,GAClB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAiEnC;AAGD,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAC;IAC5C,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC9C,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC,GAAG;IACF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;CAChE,CA0BA"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { buildActions } from "./guidance-actions.js";
|
|
3
3
|
function relative(root, target) {
|
|
4
|
+
// Intent claims cite tickets and URLs, which are not workspace paths.
|
|
5
|
+
if (!path.isAbsolute(target))
|
|
6
|
+
return target;
|
|
4
7
|
const value = path.relative(root, target);
|
|
5
8
|
return value.startsWith("..") || path.isAbsolute(value)
|
|
6
9
|
? target.split(path.sep).join("/")
|
|
@@ -28,6 +31,8 @@ function prompt(root, activation, declared, candidates, signals, warnings) {
|
|
|
28
31
|
bullets.push(`- Summary: ${declared.projectSummary}`);
|
|
29
32
|
if (declared.sourceOfTruthPaths.length > 0)
|
|
30
33
|
bullets.push(`- Source of truth: ${summary(declared.sourceOfTruthPaths)}.`);
|
|
34
|
+
if (declared.knowledgeSources)
|
|
35
|
+
bullets.push(`- Knowledge sources: ${summary(declared.knowledgeSources.map((source) => `${source.title} (${source.authority})`))}; ${declared.intentClaims?.length ?? 0} cited intent claim(s).`);
|
|
31
36
|
if (candidates.length > 0) {
|
|
32
37
|
const formatted = Object.entries(counts(candidates))
|
|
33
38
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
@@ -81,7 +86,8 @@ export function confidence(activation, declared, candidates, signals, promptBloc
|
|
|
81
86
|
declared.sourceOfTruthPaths.length +
|
|
82
87
|
declared.sourceOfTruthNotes.length +
|
|
83
88
|
declared.priorityRoots.length +
|
|
84
|
-
declared.verificationAnchors.length
|
|
89
|
+
declared.verificationAnchors.length +
|
|
90
|
+
(declared.knowledgeSources?.length ?? 0) >
|
|
85
91
|
0) {
|
|
86
92
|
score += 0.08;
|
|
87
93
|
reasons.push("Declared bootstrap context grounds the output.");
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { BootstrapDeclaredContext, Candidate, SourceOnlySignal } from "./types.js";
|
|
2
|
+
export type IntentClaimBuildResult = {
|
|
3
|
+
readonly candidates: readonly Candidate[];
|
|
4
|
+
readonly sourceOnlySignals: readonly SourceOnlySignal[];
|
|
5
|
+
readonly suppressed: readonly Readonly<Record<string, unknown>>[];
|
|
6
|
+
readonly diagnostics: readonly string[];
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Turn intent the agent harvested from declared knowledge sources into cited
|
|
10
|
+
* bootstrap candidates. Kibi never contacts those sources: it only records
|
|
11
|
+
* what the agent read, binds it into the plan hash through the declared
|
|
12
|
+
* context, and keeps the citation on every candidate it produces. A claim the
|
|
13
|
+
* strict modeler cannot ground stays an explicit authoring follow-up instead
|
|
14
|
+
* of becoming unverifiable knowledge.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildIntentClaimCandidates(declared: BootstrapDeclaredContext, existingIds: ReadonlySet<string>, minConfidence: number): IntentClaimBuildResult;
|
|
17
|
+
//# sourceMappingURL=intent-claims.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent-claims.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/intent-claims.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,wBAAwB,EAGxB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAQpB,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAClE,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CAAC;AAcF;;;;;;;GAOG;AAEH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,wBAAwB,EAClC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,GACpB,sBAAsB,CAgFxB"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { buildStrictWriteSet } from "../../utils/strict-modeling.js";
|
|
2
|
+
import { confidenceBand, strictPlan } from "./candidate-helpers.js";
|
|
3
|
+
import { claimFor } from "./requirement-claims.js";
|
|
4
|
+
/** How much a claim is trusted follows the authority the human assigned. */
|
|
5
|
+
const AUTHORITY_CONFIDENCE = {
|
|
6
|
+
authoritative: 0.9,
|
|
7
|
+
supporting: 0.82,
|
|
8
|
+
};
|
|
9
|
+
function citation(source, claim) {
|
|
10
|
+
return [
|
|
11
|
+
`intent_claim:${source.id}:${claim.reference}`,
|
|
12
|
+
`knowledge_source:${source.kind}:${source.locator}`,
|
|
13
|
+
`source_authority:${source.authority}`,
|
|
14
|
+
...(source.connector ? [`connector:${source.connector}`] : []),
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Turn intent the agent harvested from declared knowledge sources into cited
|
|
19
|
+
* bootstrap candidates. Kibi never contacts those sources: it only records
|
|
20
|
+
* what the agent read, binds it into the plan hash through the declared
|
|
21
|
+
* context, and keeps the citation on every candidate it produces. A claim the
|
|
22
|
+
* strict modeler cannot ground stays an explicit authoring follow-up instead
|
|
23
|
+
* of becoming unverifiable knowledge.
|
|
24
|
+
*/
|
|
25
|
+
// implements REQ-kibi-bootstrap-knowledge-sources
|
|
26
|
+
export function buildIntentClaimCandidates(declared, existingIds, minConfidence) {
|
|
27
|
+
const sources = new Map((declared.knowledgeSources ?? []).map((source) => [source.id, source]));
|
|
28
|
+
const candidates = [];
|
|
29
|
+
const sourceOnlySignals = [];
|
|
30
|
+
const suppressed = [];
|
|
31
|
+
const diagnostics = [];
|
|
32
|
+
for (const claim of declared.intentClaims ?? []) {
|
|
33
|
+
const source = sources.get(claim.sourceId);
|
|
34
|
+
if (!source) {
|
|
35
|
+
diagnostics.push(`Intent claim cites an undeclared knowledge source "${claim.sourceId}" (${claim.reference}); declare it in knowledgeSources or drop the claim.`);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (source.authority === "stale") {
|
|
39
|
+
suppressed.push({
|
|
40
|
+
candidateId: "",
|
|
41
|
+
reason: "stale_knowledge_source",
|
|
42
|
+
sourcePath: claim.reference,
|
|
43
|
+
entityType: "req",
|
|
44
|
+
statement: claim.statement,
|
|
45
|
+
sourceId: source.id,
|
|
46
|
+
});
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const confidence = AUTHORITY_CONFIDENCE[source.authority];
|
|
50
|
+
const evidence = citation(source, claim);
|
|
51
|
+
const provenance = `${source.id}:${claim.reference}`;
|
|
52
|
+
const modeled = claimFor(claim.statement, `knowledge-source:${source.id}`, confidence, provenance);
|
|
53
|
+
const writeSet = modeled
|
|
54
|
+
? buildStrictWriteSet({ claim: modeled, statement: claim.statement })
|
|
55
|
+
: null;
|
|
56
|
+
if (writeSet?.isStrict &&
|
|
57
|
+
confidence >= minConfidence &&
|
|
58
|
+
!existingIds.has(writeSet.req.id)) {
|
|
59
|
+
candidates.push({
|
|
60
|
+
candidateId: `claim:${source.id}:${writeSet.req.id.toLowerCase()}`,
|
|
61
|
+
entityType: "req",
|
|
62
|
+
title: claim.statement,
|
|
63
|
+
sourceKind: "intent_claim",
|
|
64
|
+
sourcePath: claim.reference,
|
|
65
|
+
confidence,
|
|
66
|
+
confidenceBand: confidenceBand(confidence),
|
|
67
|
+
evidence,
|
|
68
|
+
relationships: writeSet.relationships.map(({ type, from, to }) => ({
|
|
69
|
+
type,
|
|
70
|
+
from,
|
|
71
|
+
to,
|
|
72
|
+
})),
|
|
73
|
+
applyPlan: strictPlan(writeSet),
|
|
74
|
+
});
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (writeSet?.isStrict && existingIds.has(writeSet.req.id)) {
|
|
78
|
+
suppressed.push({
|
|
79
|
+
candidateId: `claim:${source.id}:${writeSet.req.id.toLowerCase()}`,
|
|
80
|
+
reason: "entity_exists",
|
|
81
|
+
sourcePath: claim.reference,
|
|
82
|
+
entityType: "req",
|
|
83
|
+
});
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
sourceOnlySignals.push({
|
|
87
|
+
kind: "req",
|
|
88
|
+
title: `Author requirement from ${source.title} ${claim.reference}: ${claim.statement}`,
|
|
89
|
+
sourcePath: claim.reference,
|
|
90
|
+
confidence,
|
|
91
|
+
evidence,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return { candidates, sourceOnlySignals, suppressed, diagnostics };
|
|
95
|
+
}
|
|
@@ -11,5 +11,7 @@ export declare function presentBootstrap(input: {
|
|
|
11
11
|
readonly suppressedCandidates: readonly Readonly<Record<string, unknown>>[];
|
|
12
12
|
readonly expected: BootstrapPlanV1["expected"];
|
|
13
13
|
readonly bindingDiagnostics?: readonly string[];
|
|
14
|
+
/** Advisory findings about declared context; they never block apply. */
|
|
15
|
+
readonly contextDiagnostics?: readonly string[];
|
|
14
16
|
}): PlanBootstrapResult;
|
|
15
17
|
//# sourceMappingURL=presentation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/presentation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAEhB,gBAAgB,EAChB,wBAAwB,
|
|
1
|
+
{"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/presentation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAEhB,gBAAgB,EAChB,wBAAwB,EAGxB,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAwEpB,wBAAgB,yBAAyB,CACvC,KAAK,CAAC,EAAE,gBAAgB,GACvB,wBAAwB,CAa1B;AAiBD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,oBAAoB,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAC5E,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChD,wEAAwE;IACxE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACjD,GAAG,mBAAmB,CA+KtB"}
|