@tea-agent/loop-agent 0.44.0-next.6 → 0.44.0-next.8

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 (105) hide show
  1. package/CHANGELOG.md +288 -454
  2. package/dist/build-stamp.json +3 -3
  3. package/dist/executors/dag-pi/guards.js +4 -0
  4. package/dist/executors/dag-pi/model-config.js +30 -0
  5. package/dist/{workflows/dag/frontend-plan-completeness.js → executors/dag-pi/plan/facts.js} +25 -41
  6. package/dist/executors/dag-pi/plan/ledger-contract.js +55 -0
  7. package/dist/executors/dag-pi/tools/contract-tools.js +515 -0
  8. package/dist/executors/dag-pi/tools/design-terminal-tools.js +156 -0
  9. package/dist/executors/dag-pi/tools/plan-decision-tools.js +519 -0
  10. package/dist/executors/dag-pi/tools/review-terminal-tools.js +156 -0
  11. package/dist/executors/dag-pi/tools/scout-evidence-tools.js +270 -0
  12. package/dist/executors/dag-pi-executor.js +64 -1907
  13. package/dist/shared/git-workspace-status.js +2 -0
  14. package/dist/task/frontend-preflight.js +1 -1
  15. package/dist/task/source-prepare/semantic-intake.js +1 -1
  16. package/dist/task/source-prepare/source-fidelity-pi.js +1 -1
  17. package/dist/worker/console/chat/assistant-content.js +5 -34
  18. package/dist/worker/console/chat/chat-event-store.js +27 -10
  19. package/dist/worker/console/chat/db-connections.js +72 -8
  20. package/dist/worker/console/chat/pi-runtime/custom-tools/sql-tools.js +52 -24
  21. package/dist/worker/console/chat/pi-runtime.js +34 -0
  22. package/dist/worker/console/chat/routes.js +138 -9
  23. package/dist/worker/console/chat/session-store.js +147 -19
  24. package/dist/worker/console/chat/turn-process.js +69 -23
  25. package/dist/worker/console/chat/user-turn-outline.js +19 -0
  26. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-Brn2sPzL.js → abnfDiagram-N423BO3Z-r1NAPU_5.js} +1 -1
  27. package/dist/worker/console/static/assets/{arc-BIMNTG0W.js → arc-dT5T4sVL.js} +1 -1
  28. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G--WtcgR_A.js → architectureDiagram-T3A2C74G-CP_cOq46.js} +1 -1
  29. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-BT_Ztog1.js → blockDiagram-VBNYF7ZC-sToEZxEf.js} +1 -1
  30. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-C5hbVr-l.js → c4Diagram-5PPSVZJV-DSxwwi2m.js} +1 -1
  31. package/dist/worker/console/static/assets/channel-CyBY_yGk.js +1 -0
  32. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-BKKnyR9Z.js → chunk-2GRJ4B5K-B9fh0IkF.js} +1 -1
  33. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-BHs6biqA.js → chunk-2Q5K7J3B-CAUNl-A6.js} +1 -1
  34. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BdSFy_vP.js → chunk-5RXB4S5H-BomeqbNX.js} +1 -1
  35. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BpJIdTKV.js → chunk-5VM5RSS4-BNAuTOLE.js} +1 -1
  36. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-C_iWJhkT.js → chunk-6Q2QTUOP-DfzjRD5y.js} +1 -1
  37. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-BTbmx3-k.js → chunk-GF5L2VYU-C3uE-yc2.js} +1 -1
  38. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-D4Ee6DmP.js → chunk-JWPE2WC7-C3sQMMYr.js} +1 -1
  39. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-B487SORR.js → chunk-KBJHAD2P-D_AtEYQL.js} +1 -1
  40. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-BKYHjNrr.js → chunk-RYQCIY6F-DW4TwhKv.js} +1 -1
  41. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DrTdoYZG.js → chunk-XXDRQBXY-CTQDmJcp.js} +1 -1
  42. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-D5lN4E_E.js +1 -0
  43. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-D5lN4E_E.js +1 -0
  44. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CttUY_Jo.js → cose-bilkent-JH36ORCC-iMqPuBsL.js} +1 -1
  45. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-B4Rm5gnR.js → cynefin-VYW2F7L2-DktIuDWs.js} +1 -1
  46. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-ByxHBq_S.js → cynefinDiagram-MW4NZA55-BgVnjyEs.js} +1 -1
  47. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-DGrfNFA0.js → dagre-VZM6K2ZE-CR25E4bu.js} +1 -1
  48. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-KjrUPquv.js → diagram-7IWD3JNH-CPM2h5HY.js} +1 -1
  49. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-VS4mlm75.js → diagram-B4RE2ZJO-DqF0x2g1.js} +1 -1
  50. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-BLXYmFTM.js → diagram-LBJQPF4R-G8BYp2eb.js} +1 -1
  51. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-C6xoFAqH.js → diagram-Q27KOJAE-BbC4kT_D.js} +1 -1
  52. package/dist/worker/console/static/assets/{diagram-UB23O5K3-C478dCe7.js → diagram-UB23O5K3-CKZwZ-G5.js} +1 -1
  53. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DHEpW5zN.js → ebnfDiagram-BXEA7PRR-kJDmheia.js} +1 -1
  54. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-CA5GKfo9.js → erDiagram-JOGREHBK-DFTVHyxB.js} +1 -1
  55. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-zysi0Fl-.js → flowDiagram-UKHOOZJN-BqdN5_os.js} +1 -1
  56. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DGzcKA8Y.js → ganttDiagram-PKOTCBZU-SYDjVakh.js} +1 -1
  57. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-CHsuIG1w.js → gitGraphDiagram-DS77QQ5N-Bf8bNpGA.js} +1 -1
  58. package/dist/worker/console/static/assets/index-B28Onmfy.css +1 -0
  59. package/dist/worker/console/static/assets/index-CTMZsDmh.js +486 -0
  60. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BexZHPCp.js → infoDiagram-6WML65LV-DIeAmJ45.js} +1 -1
  61. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-Gkx8q-DB.js → ishikawaDiagram-WSZJBQD7-oikqUAlo.js} +1 -1
  62. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-XDW3qrJ7.js → journeyDiagram-NVQOT4AX-mKEF_xYT.js} +1 -1
  63. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-DJ07eEaN.js → kanban-definition-27J2QSJJ-BdWJHPnN.js} +1 -1
  64. package/dist/worker/console/static/assets/{linear-DL-zeqOn.js → linear-DGRlieMH.js} +1 -1
  65. package/dist/worker/console/static/assets/{mermaid.core-C0HdXtOf.js → mermaid.core-4P9yPC9c.js} +5 -5
  66. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-CqRX0lrt.js → mindmap-definition-FAOFIHXS-5PTSkos6.js} +1 -1
  67. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BVM9JZ2H.js → pegDiagram-VL7TDLO6-DONIFpG5.js} +1 -1
  68. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BA3ozdKk.js → pieDiagram-7S7Q4E2Y-D_Z4S70M.js} +1 -1
  69. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-B-0_p9_4.js → quadrantDiagram-CIZ2JOQS-CAsjh8iY.js} +1 -1
  70. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-DHRzPWFc.js → railroadDiagram-AXF67PYL-Cx4Dd6ac.js} +1 -1
  71. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-9BEC_PcW.js → requirementDiagram-LRYGKXZP-cQb7mwyH.js} +1 -1
  72. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-DMxeW4rN.js → sankeyDiagram-W5VNT64P-Cd-DhUdf.js} +1 -1
  73. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DixP6LIU.js → sequenceDiagram-SI44F4Z6-AlKYRgIk.js} +1 -1
  74. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-B_EifJBo.js → sizeCapture-X5ZJPWSS-CUy_ET4e.js} +1 -1
  75. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-BwikwWbX.js → stateDiagram-OKZ733FA-CTuVe6Sa.js} +1 -1
  76. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BsWhs8O7.js +1 -0
  77. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-C162l9o1.js → swimlanes-SLNWSIFB-ChFLJb-v.js} +2 -2
  78. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CJcioYGH.js +8 -0
  79. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-mpe_u1i4.js → timeline-definition-Z64GVDOM-DZZeiAPr.js} +1 -1
  80. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DyUk54HX.js → vennDiagram-T6HMQDX7-t4O91cZU.js} +1 -1
  81. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-HYyMkzfm.js → wardleyDiagram-T6FBY63Y-CV5qGHZu.js} +1 -1
  82. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-DRoh7skR.js → xychartDiagram-ELKLHX3M-DyXbytUI.js} +1 -1
  83. package/dist/worker/console/static/index.html +2 -2
  84. package/dist/worker/console/static-src/operator-chat/chat-link.js +20 -0
  85. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +58 -3
  86. package/dist/worker/console/static-src/operator-chat/process-label.js +19 -6
  87. package/dist/worker/console/static-src/operator-chat/transcript-mode.js +21 -0
  88. package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +2 -0
  89. package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +13 -5
  90. package/dist/worker/console/static-src/operator-chat/turn-state-projection.js +166 -0
  91. package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +56 -2
  92. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +202 -43
  93. package/dist/worker/console/static-src/operator-chat/useChatStream.js +78 -23
  94. package/dist/worker/console/static-src/operator-chat/useChatThread.js +55 -18
  95. package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +5 -2
  96. package/dist/worker/scheduler/scheduled-goal-dispatch.js +3 -2
  97. package/dist/worker/scheduler/scheduled-goal-evidence.js +6 -1
  98. package/package.json +1 -1
  99. package/dist/worker/console/static/assets/channel-DNWB4hpR.js +0 -1
  100. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-COhFgJji.js +0 -1
  101. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-COhFgJji.js +0 -1
  102. package/dist/worker/console/static/assets/index-CJh6pVLm.js +0 -482
  103. package/dist/worker/console/static/assets/index-C_kvKmFM.css +0 -1
  104. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-S2ZHMo1c.js +0 -1
  105. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BZm4ByfV.js +0 -8
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.44.0-next.6",
4
- "gitSha": "11c9ac87f792e61b1bc31b1ef2aeacb48a6334d4",
5
- "builtAt": "2026-09-16T11:49:07.558Z"
3
+ "version": "0.44.0-next.8",
4
+ "gitSha": "e100bbbeba403ae8cbe6c9a93ccce76cbadf434e",
5
+ "builtAt": "2026-09-16T23:48:41.706Z"
6
6
  }
@@ -0,0 +1,4 @@
1
+ /** DAG Pi 共享类型守卫:纯叶子模块,零依赖,禁止反向依赖执行器入口。 */
2
+ export function isRecordObject(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
@@ -0,0 +1,30 @@
1
+ /** DAG Pi 模型引用解析:纯配置叶子模块,零依赖,禁止反向依赖执行器入口。 */
2
+ export const DEFAULT_DAG_PI_PROVIDER = "wizard-local";
3
+ export const DAG_PI_MODEL_PROVIDERS = {
4
+ "gpt-5.3-codex-spark": "wizard-local",
5
+ "gpt-5.5": "wizard-local",
6
+ "glm-5.2": "wizard-local",
7
+ "deepseek-v4-flash": "deepseek",
8
+ "deepseek-v4-pro": "deepseek",
9
+ };
10
+ export function resolveDagPiModelConfig(modelReference, options) {
11
+ const separatorIndex = modelReference.indexOf("/");
12
+ const qualified = separatorIndex >= 0;
13
+ const provider = qualified
14
+ ? modelReference.slice(0, separatorIndex)
15
+ : (DAG_PI_MODEL_PROVIDERS[modelReference] ?? DEFAULT_DAG_PI_PROVIDER);
16
+ const model = qualified
17
+ ? modelReference.slice(separatorIndex + 1)
18
+ : modelReference;
19
+ if (!provider || !model) {
20
+ throw new Error(`invalid DAG Pi model reference "${modelReference}": expected non-empty provider/model`);
21
+ }
22
+ const explicitThinking = options?.thinking?.trim();
23
+ const thinking = explicitThinking ??
24
+ (provider === "wizard-local" && model === "gpt-5.5" ? "low" : undefined);
25
+ return {
26
+ provider,
27
+ model,
28
+ ...(thinking ? { thinking } : {}),
29
+ };
30
+ }
@@ -1,14 +1,5 @@
1
- import { collectCanonicalStateFlowNames } from "./frontend-contract-facts.js";
2
- export function enrichFrontendPlanMissingFacts(missing) {
3
- return missing.map((item) => ({
4
- ...item,
5
- owner: "Plan",
6
- repairScope: item.kind === "state-registry" || item.kind === "mock-api"
7
- ? "global-phase"
8
- : item.requirementIds.length > 1 ? "requirement-slice" : "fact",
9
- nextAction: "replace-fact-and-finalize",
10
- }));
11
- }
1
+ /** DAG Pi plan ledger 完整性事实计算:纯类型与纯函数,禁止反向依赖执行器入口。 */
2
+ import { collectCanonicalStateFlowNames } from "../../../workflows/dag/frontend-contract-facts.js";
12
3
  export function committedFactFromPlanRecord(value) {
13
4
  if (!value || typeof value !== "object" || Array.isArray(value))
14
5
  return undefined;
@@ -76,9 +67,16 @@ export function collectFrontendPlanMissingFacts(input) {
76
67
  });
77
68
  continue;
78
69
  }
79
- const targetIds = Array.isArray(entry.verificationTargetIds)
70
+ // Verification targets are the single authoritative direction. The
71
+ // legacy requirement-side list is accepted only as a fallback while
72
+ // resuming older ledgers; new plans derive it from target.requirementIds.
73
+ const derivedTargetIds = [...verificationTargetRequirements.entries()]
74
+ .filter(([, requirementIds]) => requirementIds.has(id))
75
+ .map(([targetId]) => targetId);
76
+ const legacyTargetIds = Array.isArray(entry.verificationTargetIds)
80
77
  ? entry.verificationTargetIds.filter((value) => typeof value === "string" && value.trim().length > 0)
81
78
  : [];
79
+ const targetIds = derivedTargetIds.length > 0 ? derivedTargetIds : legacyTargetIds;
82
80
  const gap = entry.evidenceGap && typeof entry.evidenceGap === "object"
83
81
  ? entry.evidenceGap
84
82
  : undefined;
@@ -104,7 +102,7 @@ export function collectFrontendPlanMissingFacts(input) {
104
102
  }
105
103
  }
106
104
  }
107
- return enrichFrontendPlanMissingFacts(missing);
105
+ return missing;
108
106
  }
109
107
  /** Completeness checks for phases whose facts are committed incrementally. */
110
108
  export function collectFrontendPlanPhaseMissingFacts(input) {
@@ -123,54 +121,40 @@ export function collectFrontendPlanPhaseMissingFacts(input) {
123
121
  ];
124
122
  }
125
123
  if (input.phase === "ux-local") {
126
- // One snapshot per check: no cross-revision cache to invalidate.
127
- const required = new Set(input.behaviorRequiredRequirementIds ?? []);
128
- const requested = new Set(input.requirementIds.filter(id => required.has(id)));
129
- if (!requested.size)
130
- return [];
131
- const byRequirement = new Map();
132
- for (const fact of facts) {
133
- for (const id of new Set(planFactStringList(fact.scopeRequirementIds))) {
134
- if (!requested.has(id))
135
- continue;
136
- const entries = byRequirement.get(id) ?? [];
137
- entries.push(fact);
138
- byRequirement.set(id, entries);
139
- }
140
- }
141
- const liveStateFlow = collectCanonicalStateFlowNames(facts);
142
124
  const missing = [];
143
- for (const id of input.requirementIds) {
144
- if (!required.has(id))
125
+ // Evaluate each behaviour requirement independently. A fact scoped to AC-1
126
+ // must not accidentally satisfy AC-2 merely because both ids share one
127
+ // UX session; shared facts remain valid when they explicitly list both ids.
128
+ for (const requirementId of input.requirementIds) {
129
+ if (!input.behaviorRequiredRequirementIds?.includes(requirementId))
145
130
  continue;
146
- const scopedFacts = byRequirement.get(id) ?? [];
131
+ const scopedFacts = facts.filter((fact) => planFactScopeIntersects(fact, new Set([requirementId])));
147
132
  const hasChoice = scopedFacts.some((fact) => fact.kind === "component-choice" &&
148
133
  Array.isArray(fact.uiComponentChoices) &&
149
134
  fact.uiComponentChoices.length > 0);
150
135
  const canonicalStateFlow = collectCanonicalStateFlowNames(scopedFacts);
151
- const hasStateFlow = [...canonicalStateFlow.uiStateNames].some(name => liveStateFlow.uiStateNames.has(name)) ||
152
- [...canonicalStateFlow.interactionNames].some(name => liveStateFlow.interactionNames.has(name));
136
+ const hasStateFlow = canonicalStateFlow.uiStateNames.size > 0 ||
137
+ canonicalStateFlow.interactionNames.size > 0;
153
138
  if (!hasChoice) {
154
139
  missing.push({
155
140
  kind: "component-choice",
156
- requirementIds: [id],
141
+ requirementIds: [requirementId],
157
142
  reason: "behaviour-required UX slice has no committed component-choice fact",
158
143
  });
159
144
  }
160
145
  if (!hasStateFlow) {
161
146
  missing.push({
162
147
  kind: "state-flow",
163
- requirementIds: [id],
148
+ requirementIds: [requirementId],
164
149
  reason: "behaviour-required UX slice has no committed state-flow fact",
165
150
  });
166
151
  }
167
152
  }
168
- return enrichFrontendPlanMissingFacts(missing);
153
+ return missing;
169
154
  }
170
155
  const hasMockApi = facts.some((fact) => fact.kind === "mock-api");
171
- const allInteractions = collectCanonicalStateFlowNames(facts).interactionNames;
172
- const requested = new Set(input.requirementIds);
173
- const liveInteractions = new Set([...collectCanonicalStateFlowNames(facts.filter(f => !planFactStringList(f.scopeRequirementIds).length || planFactScopeIntersects(f, requested))).interactionNames].filter(name => allInteractions.has(name)));
156
+ const allInteractions = collectCanonicalStateFlowNames(input.committedFacts).interactionNames;
157
+ const liveInteractions = new Set([...collectCanonicalStateFlowNames(facts.filter(f => !planFactStringList(f.scopeRequirementIds).length || planFactScopeIntersects(f, new Set(input.requirementIds)))).interactionNames].filter(name => allInteractions.has(name)));
174
158
  const coveredInteractions = new Set(facts
175
159
  .filter((fact) => fact.kind === "data-flow")
176
160
  .flatMap((fact) => planFactStringList(fact.interactions)));
@@ -192,5 +176,5 @@ export function collectFrontendPlanPhaseMissingFacts(input) {
192
176
  reason: `interaction ${interaction} has no committed data-flow fact`,
193
177
  });
194
178
  }
195
- return enrichFrontendPlanMissingFacts(missing);
179
+ return missing;
196
180
  }
@@ -0,0 +1,55 @@
1
+ /** DAG Pi plan ledger 契约与来源继承装载:纯类型与纯函数,禁止反向依赖执行器入口。 */
2
+ import path from "node:path";
3
+ import { frontendExecutionSchema } from "../../../workflows/dag/frontend-execution-groups.js";
4
+ /**
5
+ * Source fidelity ledger (AC-005/AC-006): load the contract node's committed
6
+ * requirement facts and build a requirement-id → provenance map. The contract
7
+ * node declared sourceFragmentIds/sourceRefs from the ledger's
8
+ * requirement→fragment mapping; the plan inherits them by id so the compiled
9
+ * canonical contract carries authoritative provenance without the plan
10
+ * re-deriving (or fabricating) it. Best-effort: missing/unreadable contract
11
+ * ledger yields an empty map and the plan compiles as before (the design
12
+ * policy shell will then fail closed on missing provenance).
13
+ */
14
+ export async function loadContractRequirementInheritance(runDir) {
15
+ const { readTypedEventStoreFromJsonl } = await import("../../../workflows/dag/frontend-typed-event-store.js");
16
+ let records;
17
+ try {
18
+ records = await readTypedEventStoreFromJsonl(path.join(runDir, "frontend-contract-pi", "contract-typed-facts.jsonl"));
19
+ }
20
+ catch {
21
+ return new Map();
22
+ }
23
+ const byId = new Map();
24
+ for (const record of records) {
25
+ const fact = record.fact;
26
+ if (!fact || typeof fact !== "object")
27
+ continue;
28
+ const recordFact = fact;
29
+ if (recordFact.origin !== "contract" ||
30
+ recordFact.kind !== "requirement") {
31
+ continue;
32
+ }
33
+ // Contract requirement facts carry id/sourceFragmentIds/sourceRefs on
34
+ // the fact itself (origin=contract, kind=requirement, id, text, ...),
35
+ // not inside an `entry` wrapper.
36
+ const id = typeof recordFact.id === "string" ? recordFact.id : "";
37
+ if (!id)
38
+ continue;
39
+ const sourceFragmentIds = Array.isArray(recordFact.sourceFragmentIds)
40
+ ? recordFact.sourceFragmentIds.filter((value) => typeof value === "string")
41
+ : undefined;
42
+ const sourceRefs = Array.isArray(recordFact.sourceRefs)
43
+ ? recordFact.sourceRefs.filter((value) => typeof value === "string")
44
+ : undefined;
45
+ if (sourceFragmentIds || sourceRefs) {
46
+ byId.set(id, {
47
+ ...(typeof recordFact.text === "string" ? { text: recordFact.text } : {}),
48
+ ...(recordFact.execution !== undefined ? { execution: frontendExecutionSchema.parse(recordFact.execution) } : {}),
49
+ ...(sourceFragmentIds ? { sourceFragmentIds } : {}),
50
+ ...(sourceRefs ? { sourceRefs } : {}),
51
+ });
52
+ }
53
+ }
54
+ return byId;
55
+ }