@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,177 @@
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 { createHash } from "node:crypto";
12
+ import { parseLlmMergeOutput, } from "./llm-contract.js";
13
+ import { LLM_MERGE_SYSTEM_PROMPT, buildLlmMergeUserPrompt, } from "./llm-prompt.js";
14
+ /**
15
+ * 默认置信度阈值(spec §5.5)。
16
+ *
17
+ * 低于此值的输出按 escalate 处理 —— 调用方应保留 marker,留给人工解决。
18
+ */
19
+ export const DEFAULT_LLM_CONFIDENCE_THRESHOLD = 0.7;
20
+ /**
21
+ * 默认超时(spec §5.5):15s,merge driver 必须 block 但不能拖死 git pull。
22
+ */
23
+ export const DEFAULT_LLM_TIMEOUT_MS = 15_000;
24
+ /**
25
+ * 默认 token 预算(spec §5.5):input < 1000, output < 200。
26
+ */
27
+ export const DEFAULT_LLM_MAX_OUTPUT_TOKENS = 200;
28
+ /**
29
+ * LLM 仲裁器 —— 把机械规则解决不了的冲突交给 LLM。
30
+ *
31
+ * 调用方:
32
+ * ```ts
33
+ * const arbiter = new LlmArbiter({ client, auditLog, providerName: 'anthropic' });
34
+ * const result = await arbiter.arbitrate(input);
35
+ * if (result.verdict.kind === 'resolved') {
36
+ * applyMerge(result.verdict.output);
37
+ * } else {
38
+ * writeConflictMarkers();
39
+ * }
40
+ * ```
41
+ */
42
+ export class LlmArbiter {
43
+ client;
44
+ confidenceThreshold;
45
+ timeoutMs;
46
+ maxOutputTokens;
47
+ temperature;
48
+ auditLog;
49
+ providerName;
50
+ constructor(config) {
51
+ this.client = config.client;
52
+ this.confidenceThreshold =
53
+ config.confidenceThreshold ?? DEFAULT_LLM_CONFIDENCE_THRESHOLD;
54
+ this.timeoutMs = config.timeoutMs ?? DEFAULT_LLM_TIMEOUT_MS;
55
+ this.maxOutputTokens =
56
+ config.maxOutputTokens ?? DEFAULT_LLM_MAX_OUTPUT_TOKENS;
57
+ this.temperature = config.temperature ?? 0.1;
58
+ this.auditLog = config.auditLog;
59
+ this.providerName = config.providerName;
60
+ }
61
+ async arbitrate(input) {
62
+ const userPrompt = buildLlmMergeUserPrompt(input);
63
+ const fullPrompt = `${LLM_MERGE_SYSTEM_PROMPT}\n\n---\n\n${userPrompt}`;
64
+ const promptHash = hashPrompt(fullPrompt);
65
+ const start = Date.now();
66
+ let raw;
67
+ try {
68
+ raw = await this.client.complete(fullPrompt, {
69
+ maxTokens: this.maxOutputTokens,
70
+ temperature: this.temperature,
71
+ timeoutMs: this.timeoutMs,
72
+ });
73
+ }
74
+ catch (e) {
75
+ const latencyMs = Date.now() - start;
76
+ const msg = e instanceof Error ? e.message : String(e);
77
+ this.auditFailure(input, promptHash, latencyMs, undefined, msg);
78
+ return {
79
+ verdict: { kind: "escalated", reason: "llm_call_failed" },
80
+ latencyMs,
81
+ promptHash,
82
+ };
83
+ }
84
+ const latencyMs = Date.now() - start;
85
+ const parsed = parseLlmMergeOutput(raw);
86
+ if (!parsed.ok) {
87
+ this.auditFailure(input, promptHash, latencyMs, raw, `parse_failed: ${parsed.message}`);
88
+ return {
89
+ verdict: { kind: "escalated", reason: "parse_failed" },
90
+ latencyMs,
91
+ rawResponse: raw,
92
+ parseFailure: parsed,
93
+ promptHash,
94
+ };
95
+ }
96
+ const output = parsed.output;
97
+ // LLM 自己选择 escalate —— 尊重它的判断,但仍是 escalate 结果
98
+ if (output.verdict === "escalate") {
99
+ this.auditSuccess(input, promptHash, latencyMs, output, true);
100
+ return {
101
+ verdict: { kind: "escalated", reason: "verdict_escalate" },
102
+ latencyMs,
103
+ rawResponse: raw,
104
+ promptHash,
105
+ };
106
+ }
107
+ // 置信度阈值检查 —— 低于阈值不执行,降级到 marker
108
+ if (output.confidence < this.confidenceThreshold) {
109
+ this.auditSuccess(input, promptHash, latencyMs, output, true, true);
110
+ return {
111
+ verdict: { kind: "escalated", reason: "low_confidence" },
112
+ latencyMs,
113
+ rawResponse: raw,
114
+ promptHash,
115
+ };
116
+ }
117
+ this.auditSuccess(input, promptHash, latencyMs, output, false);
118
+ return {
119
+ verdict: { kind: "resolved", output },
120
+ latencyMs,
121
+ rawResponse: raw,
122
+ promptHash,
123
+ };
124
+ }
125
+ auditSuccess(input, promptHash, latencyMs, output, escalated, lowConfidence = false) {
126
+ if (!this.auditLog)
127
+ return;
128
+ this.auditLog.append({
129
+ actor: "system",
130
+ action: escalated
131
+ ? "merge_llm_arbitrated_escalated"
132
+ : "merge_llm_arbitrated",
133
+ metadata: {
134
+ path: input.path,
135
+ conflictType: input.conflictType,
136
+ fieldName: input.fieldName,
137
+ promptHash,
138
+ verdict: output.verdict,
139
+ confidence: output.confidence,
140
+ rationale: output.rationale,
141
+ latencyMs,
142
+ provider: this.providerName,
143
+ ...(lowConfidence ? { lowConfidence: true } : {}),
144
+ ...(escalated ? { escalated: true } : {}),
145
+ },
146
+ });
147
+ }
148
+ auditFailure(input, promptHash, latencyMs, rawResponse, errorMessage) {
149
+ if (!this.auditLog)
150
+ return;
151
+ this.auditLog.append({
152
+ actor: "system",
153
+ action: "merge_llm_arbitrated_failed",
154
+ metadata: {
155
+ path: input.path,
156
+ conflictType: input.conflictType,
157
+ fieldName: input.fieldName,
158
+ promptHash,
159
+ latencyMs,
160
+ provider: this.providerName,
161
+ error: errorMessage,
162
+ ...(rawResponse !== undefined
163
+ ? { rawResponseLength: rawResponse.length }
164
+ : {}),
165
+ },
166
+ });
167
+ }
168
+ }
169
+ /**
170
+ * 计算 prompt 短哈希(SHA256 前 12 hex 字符)。
171
+ *
172
+ * 用于 audit + 异常检测:若大量调用的 promptHash 突然变化,说明 prompt 漂移。
173
+ */
174
+ function hashPrompt(prompt) {
175
+ return createHash("sha256").update(prompt).digest("hex").slice(0, 12);
176
+ }
177
+ //# sourceMappingURL=llm-arbiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-arbiter.js","sourceRoot":"","sources":["../../src/merge/llm-arbiter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * LLM merge arbitration contract (spec §5.2, §5.3).
3
+ *
4
+ * Pure types + JSON parsing — no LLM client coupling here.
5
+ * The LlmArbiter (P3.2) consumes these and drives the actual LLM call.
6
+ *
7
+ * @module @co-engram/core/merge
8
+ */
9
+ /**
10
+ * 冲突类型 —— 决定 prompt 上下文与 LLM 介入的成本权衡。
11
+ *
12
+ * - engram_frontmatter:engram 的 YAML 字段冲突(title / domainTags 等)
13
+ * - engram_content:engram 正文段落冲突
14
+ * - synapse_field:synapse 的 YAML 字段冲突
15
+ * - synapse_evidence:synapse.evidence 数组合并冲突
16
+ * - resolution_state:synapse 的 resolutionState 合并冲突
17
+ * - updatedAt_collision:updatedAt 完全一致 + 内容分歧的边界场景
18
+ * - cross_file_inconsistency:跨文件一致性(P3.6 CrossFileCoordinator 触发)
19
+ */
20
+ export type LlmMergeConflictType = "engram_frontmatter" | "engram_content" | "synapse_field" | "synapse_evidence" | "resolution_state" | "updatedAt_collision" | "cross_file_inconsistency";
21
+ /**
22
+ * LLM 仲裁输入(spec §5.2)
23
+ *
24
+ * 调用方负责把 base/ours/theirs 序列化为 JSON-safe 值;LLM 只看结构化字段,
25
+ * 不直接接触原始 markdown / yaml 文本(降低 token、避免 prompt injection)。
26
+ */
27
+ export interface LlmMergeInput {
28
+ readonly conflictType: LlmMergeConflictType;
29
+ readonly path: string;
30
+ readonly fieldName?: string;
31
+ readonly base: unknown;
32
+ readonly ours: unknown;
33
+ readonly theirs: unknown;
34
+ readonly meta: {
35
+ readonly oursUpdatedAt: string;
36
+ readonly theirsUpdatedAt: string;
37
+ readonly oursUpdatedBy: string;
38
+ readonly theirsUpdatedBy: string;
39
+ };
40
+ }
41
+ /**
42
+ * LLM 仲裁输出(spec §5.3)
43
+ *
44
+ * verdict 语义:
45
+ * - "ours" : 取 ours 原值
46
+ * - "theirs" : 取 theirs 原值
47
+ * - "merge" : 综合双方,mergedValue 必填
48
+ * - "escalate" : 无法判定 / 低置信 / 语义不一致 → 留 marker
49
+ *
50
+ * confidence:[0,1] 区间,低于阈值(默认 0.7)时调用方按 escalate 处理。
51
+ */
52
+ export interface LlmMergeOutput {
53
+ readonly verdict: "ours" | "theirs" | "merge" | "escalate";
54
+ readonly mergedValue?: unknown;
55
+ readonly rationale: string;
56
+ readonly confidence: number;
57
+ }
58
+ /**
59
+ * JSON 解析失败原因 —— 调用方据此决定 fallback 行为。
60
+ */
61
+ export type LlmOutputParseErrorReason = "empty_response" | "invalid_json" | "missing_verdict" | "invalid_verdict" | "invalid_confidence" | "missing_rationale" | "missing_merged_value";
62
+ export interface LlmOutputParseFailure {
63
+ readonly ok: false;
64
+ readonly reason: LlmOutputParseErrorReason;
65
+ readonly raw: string;
66
+ readonly message: string;
67
+ }
68
+ export interface LlmOutputParseSuccess {
69
+ readonly ok: true;
70
+ readonly output: LlmMergeOutput;
71
+ }
72
+ export type LlmOutputParseResult = LlmOutputParseSuccess | LlmOutputParseFailure;
73
+ /**
74
+ * 解析 LLM 返回的原始字符串为 LlmMergeOutput。
75
+ *
76
+ * 验证规则:
77
+ * 1. 必须是合法 JSON(允许前后空白 / ```json 代码块包裹)
78
+ * 2. verdict ∈ {ours, theirs, merge, escalate}
79
+ * 3. confidence ∈ [0, 1]
80
+ * 4. rationale 必须是非空字符串
81
+ * 5. verdict='merge' 时 mergedValue 必填
82
+ *
83
+ * 任何不满足都返回 failure,调用方据此降级。
84
+ */
85
+ export declare function parseLlmMergeOutput(raw: string): LlmOutputParseResult;
86
+ //# sourceMappingURL=llm-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-contract.d.ts","sourceRoot":"","sources":["../../src/merge/llm-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,MAAM,oBAAoB,GAC5B,oBAAoB,GACpB,gBAAgB,GAChB,eAAe,GACf,kBAAkB,GAClB,kBAAkB,GAClB,qBAAqB,GACrB,0BAA0B,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;QAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;QACjC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;QAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;KAClC,CAAC;CACH;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;IAC3D,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,MAAM,yBAAyB,GACjC,gBAAgB,GAChB,cAAc,GACd,iBAAiB,GACjB,iBAAiB,GACjB,oBAAoB,GACpB,mBAAmB,GACnB,sBAAsB,CAAC;AAE3B,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,yBAAyB,CAAC;IAC3C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;CACjC;AAED,MAAM,MAAM,oBAAoB,GAC5B,qBAAqB,GACrB,qBAAqB,CAAC;AAI1B;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CA+GrE"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * LLM merge arbitration contract (spec §5.2, §5.3).
3
+ *
4
+ * Pure types + JSON parsing — no LLM client coupling here.
5
+ * The LlmArbiter (P3.2) consumes these and drives the actual LLM call.
6
+ *
7
+ * @module @co-engram/core/merge
8
+ */
9
+ const VALID_VERDICTS = new Set(["ours", "theirs", "merge", "escalate"]);
10
+ /**
11
+ * 解析 LLM 返回的原始字符串为 LlmMergeOutput。
12
+ *
13
+ * 验证规则:
14
+ * 1. 必须是合法 JSON(允许前后空白 / ```json 代码块包裹)
15
+ * 2. verdict ∈ {ours, theirs, merge, escalate}
16
+ * 3. confidence ∈ [0, 1]
17
+ * 4. rationale 必须是非空字符串
18
+ * 5. verdict='merge' 时 mergedValue 必填
19
+ *
20
+ * 任何不满足都返回 failure,调用方据此降级。
21
+ */
22
+ export function parseLlmMergeOutput(raw) {
23
+ const trimmed = stripCodeFence(raw).trim();
24
+ if (trimmed.length === 0) {
25
+ return {
26
+ ok: false,
27
+ reason: "empty_response",
28
+ raw,
29
+ message: "LLM returned empty response",
30
+ };
31
+ }
32
+ let parsed;
33
+ try {
34
+ parsed = JSON.parse(trimmed);
35
+ }
36
+ catch (e) {
37
+ return {
38
+ ok: false,
39
+ reason: "invalid_json",
40
+ raw,
41
+ message: `JSON parse failed: ${e instanceof Error ? e.message : String(e)}`,
42
+ };
43
+ }
44
+ if (typeof parsed !== "object" || parsed === null) {
45
+ return {
46
+ ok: false,
47
+ reason: "invalid_json",
48
+ raw,
49
+ message: "LLM output is not a JSON object",
50
+ };
51
+ }
52
+ const obj = parsed;
53
+ if (!("verdict" in obj)) {
54
+ return {
55
+ ok: false,
56
+ reason: "missing_verdict",
57
+ raw,
58
+ message: "Missing 'verdict' field",
59
+ };
60
+ }
61
+ const verdict = obj.verdict;
62
+ if (typeof verdict !== "string" || !VALID_VERDICTS.has(verdict)) {
63
+ return {
64
+ ok: false,
65
+ reason: "invalid_verdict",
66
+ raw,
67
+ message: `Invalid verdict: ${JSON.stringify(verdict)}`,
68
+ };
69
+ }
70
+ if (!("confidence" in obj)) {
71
+ return {
72
+ ok: false,
73
+ reason: "invalid_confidence",
74
+ raw,
75
+ message: "Missing 'confidence' field",
76
+ };
77
+ }
78
+ const confidence = obj.confidence;
79
+ if (typeof confidence !== "number" ||
80
+ !Number.isFinite(confidence) ||
81
+ confidence < 0 ||
82
+ confidence > 1) {
83
+ return {
84
+ ok: false,
85
+ reason: "invalid_confidence",
86
+ raw,
87
+ message: `Invalid confidence (must be number in [0,1]): ${JSON.stringify(confidence)}`,
88
+ };
89
+ }
90
+ if (!("rationale" in obj) || typeof obj.rationale !== "string") {
91
+ return {
92
+ ok: false,
93
+ reason: "missing_rationale",
94
+ raw,
95
+ message: "Missing or non-string 'rationale'",
96
+ };
97
+ }
98
+ const rationale = obj.rationale.trim();
99
+ if (rationale.length === 0) {
100
+ return {
101
+ ok: false,
102
+ reason: "missing_rationale",
103
+ raw,
104
+ message: "Empty 'rationale'",
105
+ };
106
+ }
107
+ if (verdict === "merge" && !("mergedValue" in obj)) {
108
+ return {
109
+ ok: false,
110
+ reason: "missing_merged_value",
111
+ raw,
112
+ message: "verdict='merge' requires 'mergedValue'",
113
+ };
114
+ }
115
+ return {
116
+ ok: true,
117
+ output: {
118
+ verdict: verdict,
119
+ confidence,
120
+ rationale,
121
+ ...("mergedValue" in obj ? { mergedValue: obj.mergedValue } : {}),
122
+ },
123
+ };
124
+ }
125
+ /**
126
+ * 剥离 markdown 代码块包裹(```json ... ``` 或 ``` ... ```)。
127
+ *
128
+ * LLM 经常无视"只返回 JSON"指令,这里做防御性剥离。
129
+ */
130
+ function stripCodeFence(text) {
131
+ const match = text.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
132
+ return match && match[1] ? match[1] : text;
133
+ }
134
+ //# sourceMappingURL=llm-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-contract.js","sourceRoot":"","sources":["../../src/merge/llm-contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * LLM merge arbitration prompt template (spec §5.4).
3
+ *
4
+ * 模板输入:LlmMergeInput
5
+ * 模板输出:string —— 直接传给 LlmClient.complete()
6
+ *
7
+ * 设计:
8
+ * - 系统提示稳定(可缓存);变量塞进 user 段以便 prompt cache 复用前缀
9
+ * - 输出格式严格 JSON,parser (parseLlmMergeOutput) 会剥离 ```json 包裹
10
+ * - 中性英文,避免 host i18n 干扰 verdict
11
+ *
12
+ * @module @co-engram/core/merge
13
+ */
14
+ import type { LlmMergeInput } from "./llm-contract.js";
15
+ /**
16
+ * 系统提示稳定,适合 prompt cache。LlmClient 调用方应作为 system prompt 传入。
17
+ */
18
+ export declare const LLM_MERGE_SYSTEM_PROMPT = "You are a merge arbitrator for co-engram team memory files.\n\nYour job: given BASE / OURS / THEIRS snapshots of a single field or content block,\ndecide how to resolve the conflict and return strict JSON.\n\nVerdict semantics:\n- \"ours\" \u2014 take OURS as-is\n- \"theirs\" \u2014 take THEIRS as-is\n- \"merge\" \u2014 synthesize; provide mergedValue (must include both sides' intent)\n- \"escalate\" \u2014 cannot decide confidently (low confidence or semantic incoherence)\n\nRules:\n- Preserve both sides' intent when possible (prefer \"merge\" over picking a side).\n- \"escalate\" if low confidence or the two sides are semantically incompatible.\n- Never invent facts not present in either side.\n- Never include markdown / code fences / prose outside the JSON object.\n\nReturn exactly this JSON shape (no other text):\n{\n \"verdict\": \"ours\" | \"theirs\" | \"merge\" | \"escalate\",\n \"mergedValue\": <any> // required only when verdict === \"merge\"\n \"rationale\": \"<one short sentence>\",\n \"confidence\": 0.0\n}";
19
+ /**
20
+ * 构造 LLM 调用的 user prompt。
21
+ *
22
+ * 与 system prompt 分离,让 prompt cache 能复用 system 部分(spec §5.5)。
23
+ */
24
+ export declare function buildLlmMergeUserPrompt(input: LlmMergeInput): string;
25
+ //# sourceMappingURL=llm-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-prompt.d.ts","sourceRoot":"","sources":["../../src/merge/llm-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;GAEG;AACH,eAAO,MAAM,uBAAuB,2hCAuBlC,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAUpE"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * LLM merge arbitration prompt template (spec §5.4).
3
+ *
4
+ * 模板输入:LlmMergeInput
5
+ * 模板输出:string —— 直接传给 LlmClient.complete()
6
+ *
7
+ * 设计:
8
+ * - 系统提示稳定(可缓存);变量塞进 user 段以便 prompt cache 复用前缀
9
+ * - 输出格式严格 JSON,parser (parseLlmMergeOutput) 会剥离 ```json 包裹
10
+ * - 中性英文,避免 host i18n 干扰 verdict
11
+ *
12
+ * @module @co-engram/core/merge
13
+ */
14
+ /**
15
+ * 系统提示稳定,适合 prompt cache。LlmClient 调用方应作为 system prompt 传入。
16
+ */
17
+ export const LLM_MERGE_SYSTEM_PROMPT = `You are a merge arbitrator for co-engram team memory files.
18
+
19
+ Your job: given BASE / OURS / THEIRS snapshots of a single field or content block,
20
+ decide how to resolve the conflict and return strict JSON.
21
+
22
+ Verdict semantics:
23
+ - "ours" — take OURS as-is
24
+ - "theirs" — take THEIRS as-is
25
+ - "merge" — synthesize; provide mergedValue (must include both sides' intent)
26
+ - "escalate" — cannot decide confidently (low confidence or semantic incoherence)
27
+
28
+ Rules:
29
+ - Preserve both sides' intent when possible (prefer "merge" over picking a side).
30
+ - "escalate" if low confidence or the two sides are semantically incompatible.
31
+ - Never invent facts not present in either side.
32
+ - Never include markdown / code fences / prose outside the JSON object.
33
+
34
+ Return exactly this JSON shape (no other text):
35
+ {
36
+ "verdict": "ours" | "theirs" | "merge" | "escalate",
37
+ "mergedValue": <any> // required only when verdict === "merge"
38
+ "rationale": "<one short sentence>",
39
+ "confidence": 0.0
40
+ }`;
41
+ /**
42
+ * 构造 LLM 调用的 user prompt。
43
+ *
44
+ * 与 system prompt 分离,让 prompt cache 能复用 system 部分(spec §5.5)。
45
+ */
46
+ export function buildLlmMergeUserPrompt(input) {
47
+ const fieldNameLine = input.fieldName ? `Field: ${input.fieldName}\n` : "";
48
+ return `Conflict type: ${input.conflictType}
49
+ ${fieldNameLine}Path: ${input.path}
50
+
51
+ BASE (common ancestor): ${safeStringify(input.base)}
52
+ OURS (${input.meta.oursUpdatedBy} at ${input.meta.oursUpdatedAt}): ${safeStringify(input.ours)}
53
+ THEIRS (${input.meta.theirsUpdatedBy} at ${input.meta.theirsUpdatedAt}): ${safeStringify(input.theirs)}
54
+
55
+ Decide and return JSON.`;
56
+ }
57
+ /**
58
+ * 安全序列化:避免 undefined / BigInt / 循环引用导致 JSON.stringify 抛错。
59
+ * 字符串值直接返回(让 prompt 更短、更可读)。
60
+ */
61
+ function safeStringify(value) {
62
+ if (typeof value === "string")
63
+ return value;
64
+ if (value === undefined)
65
+ return "<undefined>";
66
+ try {
67
+ return JSON.stringify(value);
68
+ }
69
+ catch {
70
+ return String(value);
71
+ }
72
+ }
73
+ //# sourceMappingURL=llm-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-prompt.js","sourceRoot":"","sources":["../../src/merge/llm-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH;;GAEG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;EAuBrC,CAAC;AAEH;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAoB;IAC1D,MAAM,aAAa,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3E,OAAO,kBAAkB,KAAK,CAAC,YAAY;EAC3C,aAAa,SAAS,KAAK,CAAC,IAAI;;0BAER,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC;QAC3C,KAAK,CAAC,IAAI,CAAC,aAAa,OAAO,KAAK,CAAC,IAAI,CAAC,aAAa,MAAM,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC;UACpF,KAAK,CAAC,IAAI,CAAC,eAAe,OAAO,KAAK,CAAC,IAAI,CAAC,eAAe,MAAM,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC;;wBAE9E,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,aAAa,CAAC;IAC9C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Engram 文件合并入口
3
+ *
4
+ * 组装 frontmatter 合并 + content 合并 + 收尾(contentHash / contentSize 重算,
5
+ * updatedAt 取 max, version 取 max+1, updatedBy='merge-driver')。
6
+ * 失败模式:任一方解析失败 → throw;frontmatter/content escalate → 用 git marker
7
+ * 形式包装输给 driver 写 %A + exit 1。
8
+ *
9
+ * @module @co-engram/core/merge
10
+ */
11
+ import type { AuditLog } from "../observability/audit-log.js";
12
+ import type { LlmArbiter } from "./llm-arbiter.js";
13
+ export interface EngramMergeResult {
14
+ readonly mergedContent: string;
15
+ readonly strategy: string;
16
+ readonly winner: "ours" | "theirs" | null;
17
+ readonly escalated: boolean;
18
+ readonly backupPath?: string;
19
+ }
20
+ export declare function mergeEngramFile(params: {
21
+ baseRaw: string;
22
+ oursRaw: string;
23
+ theirsRaw: string;
24
+ relPath: string;
25
+ dataRoot?: string;
26
+ auditLog?: AuditLog;
27
+ /**
28
+ * 可选 LLM 仲裁器。提供时,frontmatter 在 Layer A escalate 后会调 LLM 兜底。
29
+ * 不提供时,仅走 Layer A(机械规则)—— 行为与 Phase 1 sync 版完全一致。
30
+ */
31
+ llmArbiter?: LlmArbiter;
32
+ }): Promise<EngramMergeResult>;
33
+ //# sourceMappingURL=merge-engram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-engram.d.ts","sourceRoot":"","sources":["../../src/merge/merge-engram.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAYH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAeD,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA6J7B"}