@co-engram/core 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/dist/i18n/en.d.ts.map +1 -1
  2. package/dist/i18n/en.js +1 -0
  3. package/dist/i18n/en.js.map +1 -1
  4. package/dist/i18n/zh.d.ts +1 -0
  5. package/dist/i18n/zh.d.ts.map +1 -1
  6. package/dist/i18n/zh.js +1 -0
  7. package/dist/i18n/zh.js.map +1 -1
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/merge/anomaly-detector.d.ts +63 -0
  13. package/dist/merge/anomaly-detector.d.ts.map +1 -0
  14. package/dist/merge/anomaly-detector.js +128 -0
  15. package/dist/merge/anomaly-detector.js.map +1 -0
  16. package/dist/merge/arbitration.d.ts +18 -0
  17. package/dist/merge/arbitration.d.ts.map +1 -0
  18. package/dist/merge/arbitration.js +27 -0
  19. package/dist/merge/arbitration.js.map +1 -0
  20. package/dist/merge/auto-onboard.d.ts +56 -0
  21. package/dist/merge/auto-onboard.d.ts.map +1 -0
  22. package/dist/merge/auto-onboard.js +81 -0
  23. package/dist/merge/auto-onboard.js.map +1 -0
  24. package/dist/merge/backup.d.ts +27 -0
  25. package/dist/merge/backup.d.ts.map +1 -0
  26. package/dist/merge/backup.js +49 -0
  27. package/dist/merge/backup.js.map +1 -0
  28. package/dist/merge/content.d.ts +50 -0
  29. package/dist/merge/content.d.ts.map +1 -0
  30. package/dist/merge/content.js +137 -0
  31. package/dist/merge/content.js.map +1 -0
  32. package/dist/merge/cross-file-coordinator.d.ts +52 -0
  33. package/dist/merge/cross-file-coordinator.d.ts.map +1 -0
  34. package/dist/merge/cross-file-coordinator.js +222 -0
  35. package/dist/merge/cross-file-coordinator.js.map +1 -0
  36. package/dist/merge/data-root.d.ts +9 -0
  37. package/dist/merge/data-root.d.ts.map +1 -0
  38. package/dist/merge/data-root.js +42 -0
  39. package/dist/merge/data-root.js.map +1 -0
  40. package/dist/merge/driver-llm.d.ts +92 -0
  41. package/dist/merge/driver-llm.d.ts.map +1 -0
  42. package/dist/merge/driver-llm.js +174 -0
  43. package/dist/merge/driver-llm.js.map +1 -0
  44. package/dist/merge/driver-main.d.ts +29 -0
  45. package/dist/merge/driver-main.d.ts.map +1 -0
  46. package/dist/merge/driver-main.js +220 -0
  47. package/dist/merge/driver-main.js.map +1 -0
  48. package/dist/merge/evidence-union.d.ts +35 -0
  49. package/dist/merge/evidence-union.d.ts.map +1 -0
  50. package/dist/merge/evidence-union.js +88 -0
  51. package/dist/merge/evidence-union.js.map +1 -0
  52. package/dist/merge/frontmatter-rules.d.ts +38 -0
  53. package/dist/merge/frontmatter-rules.d.ts.map +1 -0
  54. package/dist/merge/frontmatter-rules.js +77 -0
  55. package/dist/merge/frontmatter-rules.js.map +1 -0
  56. package/dist/merge/frontmatter.d.ts +52 -0
  57. package/dist/merge/frontmatter.d.ts.map +1 -0
  58. package/dist/merge/frontmatter.js +211 -0
  59. package/dist/merge/frontmatter.js.map +1 -0
  60. package/dist/merge/index.d.ts +31 -0
  61. package/dist/merge/index.d.ts.map +1 -0
  62. package/dist/merge/index.js +31 -0
  63. package/dist/merge/index.js.map +1 -0
  64. package/dist/merge/llm-arbiter.d.ts +85 -0
  65. package/dist/merge/llm-arbiter.d.ts.map +1 -0
  66. package/dist/merge/llm-arbiter.js +177 -0
  67. package/dist/merge/llm-arbiter.js.map +1 -0
  68. package/dist/merge/llm-contract.d.ts +86 -0
  69. package/dist/merge/llm-contract.d.ts.map +1 -0
  70. package/dist/merge/llm-contract.js +134 -0
  71. package/dist/merge/llm-contract.js.map +1 -0
  72. package/dist/merge/llm-prompt.d.ts +25 -0
  73. package/dist/merge/llm-prompt.d.ts.map +1 -0
  74. package/dist/merge/llm-prompt.js +73 -0
  75. package/dist/merge/llm-prompt.js.map +1 -0
  76. package/dist/merge/merge-engram.d.ts +33 -0
  77. package/dist/merge/merge-engram.d.ts.map +1 -0
  78. package/dist/merge/merge-engram.js +164 -0
  79. package/dist/merge/merge-engram.js.map +1 -0
  80. package/dist/merge/merge-stats.d.ts +68 -0
  81. package/dist/merge/merge-stats.d.ts.map +1 -0
  82. package/dist/merge/merge-stats.js +152 -0
  83. package/dist/merge/merge-stats.js.map +1 -0
  84. package/dist/merge/onboard.d.ts +72 -0
  85. package/dist/merge/onboard.d.ts.map +1 -0
  86. package/dist/merge/onboard.js +146 -0
  87. package/dist/merge/onboard.js.map +1 -0
  88. package/dist/merge/post-merge-hook.d.ts +77 -0
  89. package/dist/merge/post-merge-hook.d.ts.map +1 -0
  90. package/dist/merge/post-merge-hook.js +211 -0
  91. package/dist/merge/post-merge-hook.js.map +1 -0
  92. package/dist/merge/resolution-state.d.ts +41 -0
  93. package/dist/merge/resolution-state.d.ts.map +1 -0
  94. package/dist/merge/resolution-state.js +100 -0
  95. package/dist/merge/resolution-state.js.map +1 -0
  96. package/dist/merge/synapse-merger.d.ts +63 -0
  97. package/dist/merge/synapse-merger.d.ts.map +1 -0
  98. package/dist/merge/synapse-merger.js +277 -0
  99. package/dist/merge/synapse-merger.js.map +1 -0
  100. package/dist/merge/synapse-rules.d.ts +66 -0
  101. package/dist/merge/synapse-rules.d.ts.map +1 -0
  102. package/dist/merge/synapse-rules.js +112 -0
  103. package/dist/merge/synapse-rules.js.map +1 -0
  104. package/dist/merge/version.d.ts +10 -0
  105. package/dist/merge/version.d.ts.map +1 -0
  106. package/dist/merge/version.js +10 -0
  107. package/dist/merge/version.js.map +1 -0
  108. package/dist/merge-driver.cjs +9371 -0
  109. package/dist/observability/audit-log.d.ts +4 -1
  110. package/dist/observability/audit-log.d.ts.map +1 -1
  111. package/dist/observability/audit-log.js +3 -0
  112. package/dist/observability/audit-log.js.map +1 -1
  113. package/package.json +6 -2
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Frontmatter 字段分类 + 单字段合并规则
3
+ *
4
+ * 字段语义分类见 spec §4.2。每种分类有独立的合并规则。
5
+ * updatedAt_arbitrated 字段不在此处处理(由 arbitration.ts 接管)。
6
+ *
7
+ * @module @co-engram/core/merge
8
+ */
9
+ const IMMUTABLE_FIELDS = new Set(["id", "createdAt", "createdBy"]);
10
+ const ADDITIVE_FIELDS = new Set([
11
+ "retrievalCount",
12
+ "effectiveRetrievals",
13
+ "failedUses",
14
+ "reinforcementScore",
15
+ "evidenceCount",
16
+ ]);
17
+ const MAX_FIELDS = new Set([
18
+ "updatedAt",
19
+ "lastRetrievedAt",
20
+ "lastEffectiveAt",
21
+ "version",
22
+ ]);
23
+ const RECOMPUTED_FIELDS = new Set(["contentHash", "contentSize"]);
24
+ const LEGACY_DERIVED_FIELDS = new Set([
25
+ "outgoingSynapseCount",
26
+ "incomingSynapseCount",
27
+ "activeContradictionCount",
28
+ ]);
29
+ export function classifyField(fieldName) {
30
+ if (IMMUTABLE_FIELDS.has(fieldName))
31
+ return "immutable";
32
+ if (ADDITIVE_FIELDS.has(fieldName))
33
+ return "additive";
34
+ if (MAX_FIELDS.has(fieldName))
35
+ return "max";
36
+ if (RECOMPUTED_FIELDS.has(fieldName))
37
+ return "recomputed";
38
+ if (LEGACY_DERIVED_FIELDS.has(fieldName))
39
+ return "legacy_derived";
40
+ return "updatedAt_arbitrated";
41
+ }
42
+ export class ImmutableViolationError extends Error {
43
+ fieldName;
44
+ base;
45
+ ours;
46
+ theirs;
47
+ constructor(fieldName, base, ours, theirs) {
48
+ super(`Immutable field "${fieldName}" was modified (base=${JSON.stringify(base)}, ours=${JSON.stringify(ours)}, theirs=${JSON.stringify(theirs)})`);
49
+ this.fieldName = fieldName;
50
+ this.base = base;
51
+ this.ours = ours;
52
+ this.theirs = theirs;
53
+ this.name = "ImmutableViolationError";
54
+ }
55
+ }
56
+ export function mergeImmutableField(params) {
57
+ const { base, ours, theirs, fieldName } = params;
58
+ if (ours !== base || theirs !== base) {
59
+ throw new ImmutableViolationError(fieldName, base, ours, theirs);
60
+ }
61
+ return { value: base, changed: false };
62
+ }
63
+ export function mergeAdditiveField(params) {
64
+ const base = params.base ?? 0;
65
+ const ours = params.ours ?? 0;
66
+ const theirs = params.theirs ?? 0;
67
+ const value = ours + theirs - base;
68
+ const changed = ours !== base || theirs !== base;
69
+ return { value, changed };
70
+ }
71
+ export function mergeMaxField(params) {
72
+ const { base, ours, theirs } = params;
73
+ const value = ours > theirs ? ours : theirs;
74
+ const changed = value !== base;
75
+ return { value, changed };
76
+ }
77
+ //# sourceMappingURL=frontmatter-rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter-rules.js","sourceRoot":"","sources":["../../src/merge/frontmatter-rules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Frontmatter 整体合并入口
3
+ *
4
+ * 遍历 base/ours/theirs 的所有字段 key,按 classifyField 分发到对应规则。
5
+ * updatedAt_arbitrated 字段在双方都改时调 arbitrateByUpdatedAt;
6
+ * 返回 'escalate' 时把字段名记入 escalatedFields(调用方应该 leave markers)。
7
+ *
8
+ * `mergeFrontmatter` 是 sync 版本,只走 Layer A(机械规则)。
9
+ * `mergeFrontmatterAsync` 在 Layer A escalate 后,对每个 escalate 字段
10
+ * 追加 Layer B(LLM)调用,失败的留下 escalatedFields。
11
+ *
12
+ * contentHash / contentSize 不在此处算,由 mergeEngram 在 content 合并后回填。
13
+ *
14
+ * @module @co-engram/core/merge
15
+ */
16
+ import type { EngramFrontmatter } from "../storage/engram-store.js";
17
+ import type { LlmArbiter } from "./llm-arbiter.js";
18
+ import type { LlmMergeInput } from "./llm-contract.js";
19
+ export interface FrontmatterMergeOutcome {
20
+ readonly merged: Record<string, unknown>;
21
+ readonly strategy: string;
22
+ readonly escalatedFields: readonly string[];
23
+ readonly arbitratedWinner: "ours" | "theirs" | null;
24
+ }
25
+ export declare function mergeFrontmatter(params: {
26
+ base: EngramFrontmatter;
27
+ ours: EngramFrontmatter;
28
+ theirs: EngramFrontmatter;
29
+ }): FrontmatterMergeOutcome;
30
+ /**
31
+ * Async 版 frontmatter 合并,在 Layer A escalate 后追加 Layer B(LLM)兜底。
32
+ *
33
+ * 流程(spec §5.6 三层仲裁):
34
+ * 1. 调 sync `mergeFrontmatter` 拿到 Layer A 结果
35
+ * 2. 对每个 escalatedField 单独构造 LlmMergeInput(engram_frontmatter 类型)
36
+ * 3. 调 LlmArbiter.arbitrate → resolved 则替换字段值,从 escalatedFields 移除
37
+ * 4. 仍然 escalate 的字段保留在 escalatedFields,driver 写 marker
38
+ *
39
+ * 调用方需提供:
40
+ * - arbiter:已配置好的 LlmArbiter
41
+ * - path/relPath:engram 相对路径(写 audit + LLM prompt 用)
42
+ * - meta:双边的 updatedBy/updatedAt(LLM prompt 用)
43
+ */
44
+ export declare function mergeFrontmatterAsync(params: {
45
+ base: EngramFrontmatter;
46
+ ours: EngramFrontmatter;
47
+ theirs: EngramFrontmatter;
48
+ arbiter: LlmArbiter;
49
+ path: string;
50
+ meta: LlmMergeInput["meta"];
51
+ }): Promise<FrontmatterMergeOutcome>;
52
+ //# sourceMappingURL=frontmatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/merge/frontmatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AASpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;CACrD;AAYD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IACvC,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,iBAAiB,CAAC;CAC3B,GAAG,uBAAuB,CAyH1B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,UAAU,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC7B,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA+DnC"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Frontmatter 整体合并入口
3
+ *
4
+ * 遍历 base/ours/theirs 的所有字段 key,按 classifyField 分发到对应规则。
5
+ * updatedAt_arbitrated 字段在双方都改时调 arbitrateByUpdatedAt;
6
+ * 返回 'escalate' 时把字段名记入 escalatedFields(调用方应该 leave markers)。
7
+ *
8
+ * `mergeFrontmatter` 是 sync 版本,只走 Layer A(机械规则)。
9
+ * `mergeFrontmatterAsync` 在 Layer A escalate 后,对每个 escalate 字段
10
+ * 追加 Layer B(LLM)调用,失败的留下 escalatedFields。
11
+ *
12
+ * contentHash / contentSize 不在此处算,由 mergeEngram 在 content 合并后回填。
13
+ *
14
+ * @module @co-engram/core/merge
15
+ */
16
+ import { classifyField, mergeImmutableField, mergeAdditiveField, mergeMaxField, ImmutableViolationError, } from "./frontmatter-rules.js";
17
+ import { arbitrateByUpdatedAt } from "./arbitration.js";
18
+ function toRecord(fm) {
19
+ return fm;
20
+ }
21
+ function fieldChanged(base, side, key) {
22
+ return JSON.stringify(side[key]) !== JSON.stringify(base[key]);
23
+ }
24
+ export function mergeFrontmatter(params) {
25
+ const base = toRecord(params.base);
26
+ const ours = toRecord(params.ours);
27
+ const theirs = toRecord(params.theirs);
28
+ const allKeys = new Set([
29
+ ...Object.keys(base),
30
+ ...Object.keys(ours),
31
+ ...Object.keys(theirs),
32
+ ]);
33
+ const merged = {};
34
+ const escalatedFields = [];
35
+ let nAdditive = 0;
36
+ let nMax = 0;
37
+ let nArbitrated = 0;
38
+ let arbitratedWinner = null;
39
+ for (const key of allKeys) {
40
+ const cls = classifyField(key);
41
+ const baseV = base[key];
42
+ const oursV = ours[key];
43
+ const theirsV = theirs[key];
44
+ if (cls === "legacy_derived")
45
+ continue;
46
+ if (cls === "recomputed")
47
+ continue; // filled after content merge
48
+ if (cls === "immutable") {
49
+ try {
50
+ const r = mergeImmutableField({
51
+ base: baseV,
52
+ ours: oursV,
53
+ theirs: theirsV,
54
+ fieldName: key,
55
+ });
56
+ merged[key] = r.value;
57
+ }
58
+ catch (e) {
59
+ if (e instanceof ImmutableViolationError) {
60
+ escalatedFields.push(key);
61
+ merged[key] = baseV; // preserve base; driver will leave markers
62
+ }
63
+ else {
64
+ throw e;
65
+ }
66
+ }
67
+ continue;
68
+ }
69
+ if (cls === "additive") {
70
+ const r = mergeAdditiveField({
71
+ base: baseV,
72
+ ours: oursV,
73
+ theirs: theirsV,
74
+ });
75
+ merged[key] = r.value;
76
+ nAdditive++;
77
+ continue;
78
+ }
79
+ if (cls === "max") {
80
+ const r = mergeMaxField({
81
+ base: baseV,
82
+ ours: oursV,
83
+ theirs: theirsV,
84
+ });
85
+ merged[key] = r.value;
86
+ nMax++;
87
+ continue;
88
+ }
89
+ // updatedAt_arbitrated
90
+ const oursChanged = fieldChanged(base, ours, key);
91
+ const theirsChanged = fieldChanged(base, theirs, key);
92
+ if (!oursChanged && !theirsChanged) {
93
+ merged[key] = baseV;
94
+ continue;
95
+ }
96
+ if (oursChanged && !theirsChanged) {
97
+ merged[key] = oursV;
98
+ nArbitrated++;
99
+ arbitratedWinner = "ours";
100
+ continue;
101
+ }
102
+ if (theirsChanged && !oursChanged) {
103
+ merged[key] = theirsV;
104
+ nArbitrated++;
105
+ arbitratedWinner = "theirs";
106
+ continue;
107
+ }
108
+ // both changed → arbitrate
109
+ const verdict = arbitrateByUpdatedAt({
110
+ oursUpdatedAt: ours.updatedAt,
111
+ theirsUpdatedAt: theirs.updatedAt,
112
+ baseContentHash: base.contentHash,
113
+ oursContentHash: ours.contentHash,
114
+ theirsContentHash: theirs.contentHash,
115
+ });
116
+ nArbitrated++;
117
+ if (verdict === "escalate") {
118
+ escalatedFields.push(key);
119
+ merged[key] = oursV; // placeholder; driver will leave markers
120
+ // Don't update arbitratedWinner on escalate; outcome tracks winner only on resolution
121
+ }
122
+ else {
123
+ merged[key] = verdict === "ours" ? oursV : theirsV;
124
+ arbitratedWinner = verdict;
125
+ }
126
+ }
127
+ const winnerLabel = escalatedFields.length > 0 && nArbitrated > 0 && arbitratedWinner === null
128
+ ? "escalated"
129
+ : (arbitratedWinner ?? "none");
130
+ const strategy = `frontmatter: ${nAdditive} additive + ${nMax} max + ${nArbitrated} arbitrated(${winnerLabel})`;
131
+ return {
132
+ merged,
133
+ strategy,
134
+ escalatedFields,
135
+ arbitratedWinner: escalatedFields.length > 0 ? null : arbitratedWinner,
136
+ };
137
+ }
138
+ /**
139
+ * Async 版 frontmatter 合并,在 Layer A escalate 后追加 Layer B(LLM)兜底。
140
+ *
141
+ * 流程(spec §5.6 三层仲裁):
142
+ * 1. 调 sync `mergeFrontmatter` 拿到 Layer A 结果
143
+ * 2. 对每个 escalatedField 单独构造 LlmMergeInput(engram_frontmatter 类型)
144
+ * 3. 调 LlmArbiter.arbitrate → resolved 则替换字段值,从 escalatedFields 移除
145
+ * 4. 仍然 escalate 的字段保留在 escalatedFields,driver 写 marker
146
+ *
147
+ * 调用方需提供:
148
+ * - arbiter:已配置好的 LlmArbiter
149
+ * - path/relPath:engram 相对路径(写 audit + LLM prompt 用)
150
+ * - meta:双边的 updatedBy/updatedAt(LLM prompt 用)
151
+ */
152
+ export async function mergeFrontmatterAsync(params) {
153
+ const { base, ours, theirs, arbiter, path, meta } = params;
154
+ // Step 1: Layer A (sync)
155
+ const layerA = mergeFrontmatter({ base, ours, theirs });
156
+ if (layerA.escalatedFields.length === 0) {
157
+ return layerA;
158
+ }
159
+ // Step 2: Layer B (LLM) — 对每个 escalate 字段尝试仲裁
160
+ const merged = { ...layerA.merged };
161
+ const stillEscalated = [];
162
+ const baseRec = base;
163
+ const oursRec = ours;
164
+ const theirsRec = theirs;
165
+ for (const fieldName of layerA.escalatedFields) {
166
+ const llmInput = {
167
+ conflictType: "engram_frontmatter",
168
+ path,
169
+ fieldName,
170
+ base: baseRec[fieldName],
171
+ ours: oursRec[fieldName],
172
+ theirs: theirsRec[fieldName],
173
+ meta,
174
+ };
175
+ const result = await arbiter.arbitrate(llmInput);
176
+ if (result.verdict.kind === "resolved") {
177
+ const output = result.verdict.output;
178
+ if (output.verdict === "merge" && "mergedValue" in output) {
179
+ merged[fieldName] = output.mergedValue;
180
+ }
181
+ else if (output.verdict === "ours") {
182
+ merged[fieldName] = oursRec[fieldName];
183
+ }
184
+ else if (output.verdict === "theirs") {
185
+ merged[fieldName] = theirsRec[fieldName];
186
+ }
187
+ // LLM resolved; field leaves escalated set
188
+ }
189
+ else {
190
+ // LLM escalate — preserve placeholder, leave in escalated set
191
+ stillEscalated.push(fieldName);
192
+ }
193
+ }
194
+ if (stillEscalated.length === layerA.escalatedFields.length) {
195
+ // LLM couldn't resolve any — return Layer A outcome unchanged
196
+ return layerA;
197
+ }
198
+ // Recompute strategy + arbitratedWinner
199
+ const resolvedCount = layerA.escalatedFields.length - stillEscalated.length;
200
+ const winnerLabel = stillEscalated.length > 0 ? "partial-llm" : "llm-resolved";
201
+ const strategy = `${layerA.strategy} + llm:${resolvedCount} resolved, ${stillEscalated.length} escalated`;
202
+ return {
203
+ merged,
204
+ strategy,
205
+ escalatedFields: stillEscalated,
206
+ arbitratedWinner: stillEscalated.length > 0 ? null : "ours",
207
+ // Note: 当 LLM 完全解决时设 arbitratedWinner=ours 仅表示 "已解决";
208
+ // 真正的双边 winner 语义由 mergeEngramFile 整合时给 content merge 决定。
209
+ };
210
+ }
211
+ //# sourceMappingURL=frontmatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/merge/frontmatter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @module @co-engram/core/merge
3
+ *
4
+ * Public exports for the git merge driver subsystem.
5
+ * Host packages (openclaw-plugin, claude-code-mcp) consume via this barrel
6
+ * in Phase 2 when wiring auto-onboard.
7
+ */
8
+ export * from "./version.js";
9
+ export * from "./backup.js";
10
+ export * from "./frontmatter-rules.js";
11
+ export * from "./arbitration.js";
12
+ export * from "./frontmatter.js";
13
+ export * from "./content.js";
14
+ export * from "./merge-engram.js";
15
+ export * from "./synapse-rules.js";
16
+ export * from "./evidence-union.js";
17
+ export * from "./resolution-state.js";
18
+ export * from "./synapse-merger.js";
19
+ export * from "./data-root.js";
20
+ export * from "./driver-main.js";
21
+ export * from "./onboard.js";
22
+ export * from "./auto-onboard.js";
23
+ export * from "./llm-contract.js";
24
+ export * from "./llm-prompt.js";
25
+ export * from "./llm-arbiter.js";
26
+ export * from "./driver-llm.js";
27
+ export * from "./cross-file-coordinator.js";
28
+ export * from "./post-merge-hook.js";
29
+ export * from "./merge-stats.js";
30
+ export * from "./anomaly-detector.js";
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/merge/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @module @co-engram/core/merge
3
+ *
4
+ * Public exports for the git merge driver subsystem.
5
+ * Host packages (openclaw-plugin, claude-code-mcp) consume via this barrel
6
+ * in Phase 2 when wiring auto-onboard.
7
+ */
8
+ export * from "./version.js";
9
+ export * from "./backup.js";
10
+ export * from "./frontmatter-rules.js";
11
+ export * from "./arbitration.js";
12
+ export * from "./frontmatter.js";
13
+ export * from "./content.js";
14
+ export * from "./merge-engram.js";
15
+ export * from "./synapse-rules.js";
16
+ export * from "./evidence-union.js";
17
+ export * from "./resolution-state.js";
18
+ export * from "./synapse-merger.js";
19
+ export * from "./data-root.js";
20
+ export * from "./driver-main.js";
21
+ export * from "./onboard.js";
22
+ export * from "./auto-onboard.js";
23
+ export * from "./llm-contract.js";
24
+ export * from "./llm-prompt.js";
25
+ export * from "./llm-arbiter.js";
26
+ export * from "./driver-llm.js";
27
+ export * from "./cross-file-coordinator.js";
28
+ export * from "./post-merge-hook.js";
29
+ export * from "./merge-stats.js";
30
+ export * from "./anomaly-detector.js";
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/merge/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * LLM merge arbitrator (spec §5).
3
+ *
4
+ * 接受 LlmClient + confidence threshold,把 LlmMergeInput 翻译成一次 LLM 调用,
5
+ * 解析输出,应用置信度阈值,失败一律降级到 escalate(留 marker)。
6
+ *
7
+ * 不重试(spec §5.5):失败就降级,backup + audit 兜底。
8
+ *
9
+ * @module @co-engram/core/merge
10
+ */
11
+ import type { LlmClient } from "../observability/necessity-evaluator.js";
12
+ import type { AuditLog } from "../observability/audit-log.js";
13
+ import { type LlmMergeInput, type LlmMergeOutput, type LlmOutputParseFailure } from "./llm-contract.js";
14
+ /**
15
+ * 默认置信度阈值(spec §5.5)。
16
+ *
17
+ * 低于此值的输出按 escalate 处理 —— 调用方应保留 marker,留给人工解决。
18
+ */
19
+ export declare const DEFAULT_LLM_CONFIDENCE_THRESHOLD = 0.7;
20
+ /**
21
+ * 默认超时(spec §5.5):15s,merge driver 必须 block 但不能拖死 git pull。
22
+ */
23
+ export declare const DEFAULT_LLM_TIMEOUT_MS = 15000;
24
+ /**
25
+ * 默认 token 预算(spec §5.5):input < 1000, output < 200。
26
+ */
27
+ export declare const DEFAULT_LLM_MAX_OUTPUT_TOKENS = 200;
28
+ export type LlmArbiterVerdict = {
29
+ readonly kind: "resolved";
30
+ readonly output: LlmMergeOutput;
31
+ } | {
32
+ readonly kind: "escalated";
33
+ readonly reason: EscalationReason;
34
+ };
35
+ export type EscalationReason = "llm_call_failed" | "parse_failed" | "low_confidence" | "verdict_escalate";
36
+ export interface LlmArbiterResult {
37
+ /** 最终裁决(resolved=可执行,escalated=留 marker) */
38
+ readonly verdict: LlmArbiterVerdict;
39
+ /** 实际耗时(ms) */
40
+ readonly latencyMs: number;
41
+ /** LLM 原始返回(诊断用;escalated 时也可能有值) */
42
+ readonly rawResponse?: string;
43
+ /** 解析错误(parse_failed 时填) */
44
+ readonly parseFailure?: LlmOutputParseFailure;
45
+ /** prompt 哈希(短 SHA256,前 12 hex)—— 落 audit 用于 prompt drift 检测 */
46
+ readonly promptHash: string;
47
+ }
48
+ export interface LlmArbiterConfig {
49
+ readonly client: LlmClient;
50
+ readonly confidenceThreshold?: number;
51
+ readonly timeoutMs?: number;
52
+ readonly maxOutputTokens?: number;
53
+ readonly temperature?: number;
54
+ readonly auditLog?: AuditLog;
55
+ /** 用于 audit 记录的 provider 名(如 'anthropic' / 'openai-compatible') */
56
+ readonly providerName?: string;
57
+ }
58
+ /**
59
+ * LLM 仲裁器 —— 把机械规则解决不了的冲突交给 LLM。
60
+ *
61
+ * 调用方:
62
+ * ```ts
63
+ * const arbiter = new LlmArbiter({ client, auditLog, providerName: 'anthropic' });
64
+ * const result = await arbiter.arbitrate(input);
65
+ * if (result.verdict.kind === 'resolved') {
66
+ * applyMerge(result.verdict.output);
67
+ * } else {
68
+ * writeConflictMarkers();
69
+ * }
70
+ * ```
71
+ */
72
+ export declare class LlmArbiter {
73
+ private readonly client;
74
+ private readonly confidenceThreshold;
75
+ private readonly timeoutMs;
76
+ private readonly maxOutputTokens;
77
+ private readonly temperature;
78
+ private readonly auditLog?;
79
+ private readonly providerName?;
80
+ constructor(config: LlmArbiterConfig);
81
+ arbitrate(input: LlmMergeInput): Promise<LlmArbiterResult>;
82
+ private auditSuccess;
83
+ private auditFailure;
84
+ }
85
+ //# sourceMappingURL=llm-arbiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-arbiter.d.ts","sourceRoot":"","sources":["../../src/merge/llm-arbiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC3B,MAAM,mBAAmB,CAAC;AAM3B;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAEpD;;GAEG;AACH,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAEjD,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GAC9D;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAEtE,MAAM,MAAM,gBAAgB,GACxB,iBAAiB,GACjB,cAAc,GACd,gBAAgB,GAChB,kBAAkB,CAAC;AAEvB,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,eAAe;IACf,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,qCAAqC;IACrC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,4BAA4B;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,qBAAqB,CAAC;IAC9C,gEAAgE;IAChE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAC7B,mEAAmE;IACnE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAS;gBAE3B,MAAM,EAAE,gBAAgB;IAY9B,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA4EhE,OAAO,CAAC,YAAY;IA8BpB,OAAO,CAAC,YAAY;CAyBrB"}