simfile 0.0.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 (249) hide show
  1. package/README.md +143 -0
  2. package/dist/cli/index.d.ts +3 -0
  3. package/dist/cli/index.d.ts.map +1 -0
  4. package/dist/cli/index.js +348 -0
  5. package/dist/coverage/index.d.ts +2 -0
  6. package/dist/coverage/index.d.ts.map +1 -0
  7. package/dist/coverage/index.js +1 -0
  8. package/dist/coverage/matrix.d.ts +21 -0
  9. package/dist/coverage/matrix.d.ts.map +1 -0
  10. package/dist/coverage/matrix.js +173 -0
  11. package/dist/coverage/render.d.ts +3 -0
  12. package/dist/coverage/render.d.ts.map +1 -0
  13. package/dist/coverage/render.js +26 -0
  14. package/dist/index.d.ts +8 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +7 -0
  17. package/dist/kernel/duration.d.ts +9 -0
  18. package/dist/kernel/duration.d.ts.map +1 -0
  19. package/dist/kernel/duration.js +44 -0
  20. package/dist/kernel/index.d.ts +4 -0
  21. package/dist/kernel/index.d.ts.map +1 -0
  22. package/dist/kernel/index.js +3 -0
  23. package/dist/kernel/range.d.ts +6 -0
  24. package/dist/kernel/range.d.ts.map +1 -0
  25. package/dist/kernel/range.js +16 -0
  26. package/dist/kernel/stochastic.d.ts +10 -0
  27. package/dist/kernel/stochastic.d.ts.map +1 -0
  28. package/dist/kernel/stochastic.js +25 -0
  29. package/dist/ledger/index.d.ts +4 -0
  30. package/dist/ledger/index.d.ts.map +1 -0
  31. package/dist/ledger/index.js +3 -0
  32. package/dist/ledger/markers.d.ts +46 -0
  33. package/dist/ledger/markers.d.ts.map +1 -0
  34. package/dist/ledger/markers.js +108 -0
  35. package/dist/ledger/stable.d.ts +65 -0
  36. package/dist/ledger/stable.d.ts.map +1 -0
  37. package/dist/ledger/stable.js +78 -0
  38. package/dist/ledger/validation.d.ts +16 -0
  39. package/dist/ledger/validation.d.ts.map +1 -0
  40. package/dist/ledger/validation.js +127 -0
  41. package/dist/moltnet/index.d.ts +3 -0
  42. package/dist/moltnet/index.d.ts.map +1 -0
  43. package/dist/moltnet/index.js +2 -0
  44. package/dist/moltnet/transcript-export.d.ts +34 -0
  45. package/dist/moltnet/transcript-export.d.ts.map +1 -0
  46. package/dist/moltnet/transcript-export.js +68 -0
  47. package/dist/moltnet/world-participant.d.ts +77 -0
  48. package/dist/moltnet/world-participant.d.ts.map +1 -0
  49. package/dist/moltnet/world-participant.js +221 -0
  50. package/dist/observe/artifacts.d.ts +16 -0
  51. package/dist/observe/artifacts.d.ts.map +1 -0
  52. package/dist/observe/artifacts.js +31 -0
  53. package/dist/observe/causalStreams.d.ts +19 -0
  54. package/dist/observe/causalStreams.d.ts.map +1 -0
  55. package/dist/observe/causalStreams.js +38 -0
  56. package/dist/observe/compute.d.ts +17 -0
  57. package/dist/observe/compute.d.ts.map +1 -0
  58. package/dist/observe/compute.js +97 -0
  59. package/dist/observe/index.d.ts +11 -0
  60. package/dist/observe/index.d.ts.map +1 -0
  61. package/dist/observe/index.js +10 -0
  62. package/dist/observe/manifest.d.ts +79 -0
  63. package/dist/observe/manifest.d.ts.map +1 -0
  64. package/dist/observe/manifest.js +87 -0
  65. package/dist/observe/memoryBanks.d.ts +38 -0
  66. package/dist/observe/memoryBanks.d.ts.map +1 -0
  67. package/dist/observe/memoryBanks.js +86 -0
  68. package/dist/observe/observe.d.ts +32 -0
  69. package/dist/observe/observe.d.ts.map +1 -0
  70. package/dist/observe/observe.js +73 -0
  71. package/dist/observe/report.d.ts +165 -0
  72. package/dist/observe/report.d.ts.map +1 -0
  73. package/dist/observe/report.js +138 -0
  74. package/dist/observe/seedSpread.d.ts +49 -0
  75. package/dist/observe/seedSpread.d.ts.map +1 -0
  76. package/dist/observe/seedSpread.js +262 -0
  77. package/dist/observe/seedSpreadArtifacts.d.ts +49 -0
  78. package/dist/observe/seedSpreadArtifacts.d.ts.map +1 -0
  79. package/dist/observe/seedSpreadArtifacts.js +118 -0
  80. package/dist/observe/spreadMatcher.d.ts +45 -0
  81. package/dist/observe/spreadMatcher.d.ts.map +1 -0
  82. package/dist/observe/spreadMatcher.js +124 -0
  83. package/dist/report/index.d.ts +4 -0
  84. package/dist/report/index.d.ts.map +1 -0
  85. package/dist/report/index.js +3 -0
  86. package/dist/report/probeArtifact.d.ts +26 -0
  87. package/dist/report/probeArtifact.d.ts.map +1 -0
  88. package/dist/report/probeArtifact.js +119 -0
  89. package/dist/report/probes.d.ts +52 -0
  90. package/dist/report/probes.d.ts.map +1 -0
  91. package/dist/report/probes.js +164 -0
  92. package/dist/report/score.d.ts +27 -0
  93. package/dist/report/score.d.ts.map +1 -0
  94. package/dist/report/score.js +14 -0
  95. package/dist/report/transcripts.d.ts +12 -0
  96. package/dist/report/transcripts.d.ts.map +1 -0
  97. package/dist/report/transcripts.js +17 -0
  98. package/dist/runtime/causal-fixture.d.ts +26 -0
  99. package/dist/runtime/causal-fixture.d.ts.map +1 -0
  100. package/dist/runtime/causal-fixture.js +36 -0
  101. package/dist/runtime/clock.d.ts +25 -0
  102. package/dist/runtime/clock.d.ts.map +1 -0
  103. package/dist/runtime/clock.js +63 -0
  104. package/dist/runtime/condition.d.ts +55 -0
  105. package/dist/runtime/condition.d.ts.map +1 -0
  106. package/dist/runtime/condition.js +122 -0
  107. package/dist/runtime/emit-causal-fixture.d.ts +2 -0
  108. package/dist/runtime/emit-causal-fixture.d.ts.map +1 -0
  109. package/dist/runtime/emit-causal-fixture.js +45 -0
  110. package/dist/runtime/expression.d.ts +11 -0
  111. package/dist/runtime/expression.d.ts.map +1 -0
  112. package/dist/runtime/expression.js +305 -0
  113. package/dist/runtime/numeric.d.ts +7 -0
  114. package/dist/runtime/numeric.d.ts.map +1 -0
  115. package/dist/runtime/numeric.js +11 -0
  116. package/dist/runtime/rule-actions.d.ts +5 -0
  117. package/dist/runtime/rule-actions.d.ts.map +1 -0
  118. package/dist/runtime/rule-actions.js +82 -0
  119. package/dist/runtime/run-record.d.ts +73 -0
  120. package/dist/runtime/run-record.d.ts.map +1 -0
  121. package/dist/runtime/run-record.js +179 -0
  122. package/dist/runtime/step-tick.d.ts +43 -0
  123. package/dist/runtime/step-tick.d.ts.map +1 -0
  124. package/dist/runtime/step-tick.js +177 -0
  125. package/dist/runtime/trace-compile.d.ts +66 -0
  126. package/dist/runtime/trace-compile.d.ts.map +1 -0
  127. package/dist/runtime/trace-compile.js +157 -0
  128. package/dist/runtime/trace-export.d.ts +5 -0
  129. package/dist/runtime/trace-export.d.ts.map +1 -0
  130. package/dist/runtime/trace-export.js +4 -0
  131. package/dist/runtime/trace-run.d.ts +15 -0
  132. package/dist/runtime/trace-run.d.ts.map +1 -0
  133. package/dist/runtime/trace-run.js +92 -0
  134. package/dist/runtime/trace.d.ts +10 -0
  135. package/dist/runtime/trace.d.ts.map +1 -0
  136. package/dist/runtime/trace.js +9 -0
  137. package/dist/runtime/types.d.ts +61 -0
  138. package/dist/runtime/types.d.ts.map +1 -0
  139. package/dist/runtime/types.js +1 -0
  140. package/dist/runtime/viewer-trace.d.ts +64 -0
  141. package/dist/runtime/viewer-trace.d.ts.map +1 -0
  142. package/dist/runtime/viewer-trace.js +164 -0
  143. package/dist/runtime/world-act.d.ts +55 -0
  144. package/dist/runtime/world-act.d.ts.map +1 -0
  145. package/dist/runtime/world-act.js +156 -0
  146. package/dist/schema/binding.d.ts +23 -0
  147. package/dist/schema/binding.d.ts.map +1 -0
  148. package/dist/schema/binding.js +249 -0
  149. package/dist/schema/index.d.ts +5 -0
  150. package/dist/schema/index.d.ts.map +1 -0
  151. package/dist/schema/index.js +4 -0
  152. package/dist/schema/model.d.ts +244 -0
  153. package/dist/schema/model.d.ts.map +1 -0
  154. package/dist/schema/model.js +222 -0
  155. package/dist/schema/parse.d.ts +10 -0
  156. package/dist/schema/parse.d.ts.map +1 -0
  157. package/dist/schema/parse.js +15 -0
  158. package/dist/schema/semantic.d.ts +3 -0
  159. package/dist/schema/semantic.d.ts.map +1 -0
  160. package/dist/schema/semantic.js +135 -0
  161. package/dist/sims/composeRunManifest.d.ts +54 -0
  162. package/dist/sims/composeRunManifest.d.ts.map +1 -0
  163. package/dist/sims/composeRunManifest.js +40 -0
  164. package/dist/sims/composedJungianSimDriver.d.ts +50 -0
  165. package/dist/sims/composedJungianSimDriver.d.ts.map +1 -0
  166. package/dist/sims/composedJungianSimDriver.js +199 -0
  167. package/dist/sims/composedOfficeSimDriver.d.ts +53 -0
  168. package/dist/sims/composedOfficeSimDriver.d.ts.map +1 -0
  169. package/dist/sims/composedOfficeSimDriver.js +162 -0
  170. package/dist/sims/exchangeWait.d.ts +56 -0
  171. package/dist/sims/exchangeWait.d.ts.map +1 -0
  172. package/dist/sims/exchangeWait.js +66 -0
  173. package/dist/sims/index.d.ts +14 -0
  174. package/dist/sims/index.d.ts.map +1 -0
  175. package/dist/sims/index.js +13 -0
  176. package/dist/sims/moltnetRoomClient.d.ts +47 -0
  177. package/dist/sims/moltnetRoomClient.d.ts.map +1 -0
  178. package/dist/sims/moltnetRoomClient.js +41 -0
  179. package/dist/sims/poll.d.ts +19 -0
  180. package/dist/sims/poll.d.ts.map +1 -0
  181. package/dist/sims/poll.js +23 -0
  182. package/dist/sims/spawnfileCli.d.ts +49 -0
  183. package/dist/sims/spawnfileCli.d.ts.map +1 -0
  184. package/dist/sims/spawnfileCli.js +90 -0
  185. package/dist/sims/spawnfileReceipts.d.ts +76 -0
  186. package/dist/sims/spawnfileReceipts.d.ts.map +1 -0
  187. package/dist/sims/spawnfileReceipts.js +107 -0
  188. package/dist/sims/worldDrivenOfficeSimDriver.d.ts +59 -0
  189. package/dist/sims/worldDrivenOfficeSimDriver.d.ts.map +1 -0
  190. package/dist/sims/worldDrivenOfficeSimDriver.js +182 -0
  191. package/dist/sims/worldLedgerWriter.d.ts +32 -0
  192. package/dist/sims/worldLedgerWriter.d.ts.map +1 -0
  193. package/dist/sims/worldLedgerWriter.js +39 -0
  194. package/dist/sims/worldSeedLint.d.ts +42 -0
  195. package/dist/sims/worldSeedLint.d.ts.map +1 -0
  196. package/dist/sims/worldSeedLint.js +73 -0
  197. package/dist/sims/worldTickIngest.d.ts +27 -0
  198. package/dist/sims/worldTickIngest.d.ts.map +1 -0
  199. package/dist/sims/worldTickIngest.js +35 -0
  200. package/dist/sims/worldTickLoop.d.ts +64 -0
  201. package/dist/sims/worldTickLoop.d.ts.map +1 -0
  202. package/dist/sims/worldTickLoop.js +122 -0
  203. package/dist/view/engineProvenance.d.ts +46 -0
  204. package/dist/view/engineProvenance.d.ts.map +1 -0
  205. package/dist/view/engineProvenance.js +76 -0
  206. package/dist/view/index.d.ts +14 -0
  207. package/dist/view/index.d.ts.map +1 -0
  208. package/dist/view/index.js +107 -0
  209. package/dist/view/membranes.d.ts +14 -0
  210. package/dist/view/membranes.d.ts.map +1 -0
  211. package/dist/view/membranes.js +127 -0
  212. package/dist/view/runDetect.d.ts +2 -0
  213. package/dist/view/runDetect.d.ts.map +1 -0
  214. package/dist/view/runDetect.js +47 -0
  215. package/dist/view/runRawArtifacts.d.ts +48 -0
  216. package/dist/view/runRawArtifacts.d.ts.map +1 -0
  217. package/dist/view/runRawArtifacts.js +143 -0
  218. package/dist/view/runTimeline.d.ts +24 -0
  219. package/dist/view/runTimeline.d.ts.map +1 -0
  220. package/dist/view/runTimeline.js +204 -0
  221. package/dist/view/runTimelineRecords.d.ts +42 -0
  222. package/dist/view/runTimelineRecords.d.ts.map +1 -0
  223. package/dist/view/runTimelineRecords.js +244 -0
  224. package/dist/view/runTimelineRefs.d.ts +27 -0
  225. package/dist/view/runTimelineRefs.d.ts.map +1 -0
  226. package/dist/view/runTimelineRefs.js +31 -0
  227. package/dist/view/runTimelineTypes.d.ts +99 -0
  228. package/dist/view/runTimelineTypes.d.ts.map +1 -0
  229. package/dist/view/runTimelineTypes.js +1 -0
  230. package/dist/view/runViewModel.d.ts +21 -0
  231. package/dist/view/runViewModel.d.ts.map +1 -0
  232. package/dist/view/runViewModel.js +66 -0
  233. package/dist/view/runViewModelCompute.d.ts +24 -0
  234. package/dist/view/runViewModelCompute.d.ts.map +1 -0
  235. package/dist/view/runViewModelCompute.js +157 -0
  236. package/dist/view/runViewModelTypes.d.ts +177 -0
  237. package/dist/view/runViewModelTypes.d.ts.map +1 -0
  238. package/dist/view/runViewModelTypes.js +1 -0
  239. package/dist/view/runWorldTrace.d.ts +97 -0
  240. package/dist/view/runWorldTrace.d.ts.map +1 -0
  241. package/dist/view/runWorldTrace.js +88 -0
  242. package/dist/view/server.d.ts +12 -0
  243. package/dist/view/server.d.ts.map +1 -0
  244. package/dist/view/server.js +306 -0
  245. package/package.json +65 -0
  246. package/web/dist/assets/index-CJHLjfsG.js +49 -0
  247. package/web/dist/assets/index-DJOsPsU8.css +1 -0
  248. package/web/dist/index.html +13 -0
  249. package/web/dist/models/AnimatedMushnub.glb +0 -0
@@ -0,0 +1,24 @@
1
+ import type { ElementRef, RunTimeline } from "./runTimelineTypes.js";
2
+ /**
3
+ * One room the run declares (`manifest.world`): a `room:<network>:<room>`
4
+ * ref, its network + bare room id, and its member agent ids. Exported so
5
+ * `server.ts` can tell an OUTER (parent-floor) room from an interior one —
6
+ * a membrane's `interiorRooms` are also entries of this same list — when it
7
+ * builds the outer map's `/api/world` trace (`runWorldTrace.ts`'s
8
+ * `buildRunWorldTrace` `rooms` param).
9
+ */
10
+ export interface WorldRoom {
11
+ ref: ElementRef;
12
+ networkId: string;
13
+ roomId: string;
14
+ members: string[];
15
+ }
16
+ /**
17
+ * Reads and parses `manifest.json`'s `world` field into its declared rooms —
18
+ * the same parse `buildRunTimeline` does internally, exported so `server.ts`
19
+ * can tell an outer (parent-floor) room from an interior one when it builds
20
+ * the outer map's `/api/world` trace, without re-deriving the whole timeline.
21
+ */
22
+ export declare const readWorldRooms: (runDir: string) => Promise<WorldRoom[]>;
23
+ export declare const buildRunTimeline: (runDir: string) => Promise<RunTimeline>;
24
+ //# sourceMappingURL=runTimeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runTimeline.d.ts","sourceRoot":"","sources":["../../src/view/runTimeline.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAA0D,MAAM,uBAAuB,CAAC;AAgE7H;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,UAAU,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAkFD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,SAAS,EAAE,CAGxE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,WAAW,CA6D1E,CAAC"}
@@ -0,0 +1,204 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { collectCausalStreams } from "../observe/causalStreams.js";
4
+ import { parseRunManifest } from "../observe/manifest.js";
5
+ import { readMnemeEventsByBank, readTranscript } from "./runRawArtifacts.js";
6
+ import { agentIdFromStreamId, agentRef, bankFromRelativePath, bankRef, roomRef, stringField } from "./runTimelineRefs.js";
7
+ import { readRunMembranes } from "./membranes.js";
8
+ import { buildBankLogRecord, buildCausalRecord, roomForMoltnetMessage } from "./runTimelineRecords.js";
9
+ /**
10
+ * `buildRunTimeline` merges every causal record in a sealed run directory
11
+ * into one deterministic, scrubbable `RunTimeline` (see `runTimelineTypes.ts`
12
+ * for the shape and `docs/VIEW_DESIGN.md` rule 7). This is the only file that
13
+ * assigns the scrub key `t`; everything downstream (the world-trace adapter,
14
+ * the web store, the chat/minds/portal views) treats `t` as ground truth.
15
+ *
16
+ * The per-authority record-building logic itself lives in
17
+ * `runTimelineRecords.ts` (split out to keep this file, the orchestrator,
18
+ * under 400 lines — `AGENTS.md`); this file owns merge order (`sortRecords`),
19
+ * causal repair, dense `t` assignment, and element enumeration.
20
+ */
21
+ const sortRecords = (records) => [...records].sort((left, right) => {
22
+ const timeDiff = Date.parse(left.recordedAt) - Date.parse(right.recordedAt);
23
+ if (timeDiff !== 0)
24
+ return timeDiff;
25
+ if (left.authority !== right.authority)
26
+ return left.authority.localeCompare(right.authority);
27
+ if (left.streamId !== right.streamId)
28
+ return left.streamId.localeCompare(right.streamId);
29
+ if (left.seq !== right.seq)
30
+ return left.seq - right.seq;
31
+ return left.eventId.localeCompare(right.eventId);
32
+ });
33
+ /**
34
+ * Stable causal-repair pass: an event may not precede any of its own
35
+ * `causeIds`. Repeatedly finds the first record whose latest-known cause
36
+ * sits after it and re-splices it immediately after that cause, restarting
37
+ * the scan after each move (small run sizes at this increment's scale make
38
+ * the O(n^2) worst case negligible; correctness first).
39
+ */
40
+ const causalRepair = (records) => {
41
+ const order = [...records];
42
+ const maxPasses = order.length + 5;
43
+ for (let pass = 0; pass < maxPasses; pass += 1) {
44
+ const indexOf = new Map(order.map((record, index) => [record.eventId, index]));
45
+ let moved = false;
46
+ for (let index = 0; index < order.length; index += 1) {
47
+ const record = order[index];
48
+ let latestCauseIndex = -1;
49
+ for (const causeId of record.causeIds) {
50
+ const causeIndex = indexOf.get(causeId);
51
+ if (causeIndex !== undefined)
52
+ latestCauseIndex = Math.max(latestCauseIndex, causeIndex);
53
+ }
54
+ if (latestCauseIndex > index) {
55
+ order.splice(index, 1);
56
+ order.splice(latestCauseIndex, 0, record);
57
+ moved = true;
58
+ break;
59
+ }
60
+ }
61
+ if (!moved)
62
+ break;
63
+ }
64
+ return order;
65
+ };
66
+ const buildElements = (params) => {
67
+ const elements = new Map();
68
+ for (const room of params.rooms) {
69
+ elements.set(room.ref, { ref: room.ref, kind: "room", label: room.roomId });
70
+ for (const member of room.members) {
71
+ const ref = agentRef(member);
72
+ if (!elements.has(ref))
73
+ elements.set(ref, { ref, kind: "agent", label: member });
74
+ }
75
+ }
76
+ for (const membrane of params.membranes) {
77
+ if (!elements.has(membrane.ref))
78
+ elements.set(membrane.ref, { ref: membrane.ref, kind: "team", label: membrane.label });
79
+ }
80
+ for (const stream of params.streams) {
81
+ if (stream.authority !== "daimon")
82
+ continue;
83
+ for (const event of stream.events) {
84
+ const agentId = agentIdFromStreamId(event.emitter.stream_id);
85
+ if (!agentId)
86
+ continue;
87
+ const ref = agentRef(agentId);
88
+ if (!elements.has(ref))
89
+ elements.set(ref, { ref, kind: "agent", label: agentId });
90
+ }
91
+ }
92
+ for (const bankName of params.mnemeByBank.keys()) {
93
+ const ref = bankRef(bankName);
94
+ if (!elements.has(ref))
95
+ elements.set(ref, { ref, kind: "bank", label: bankName });
96
+ }
97
+ // Increment 4: a variable element per distinct `variable:<id>` subject
98
+ // that actually appears somewhere in this run's own world-authority
99
+ // records (`buildWorldRecord`'s `variable:<id>` subjects, joined from a
100
+ // `rule.fired`/`world.message`/`world.act` event's own `payload.variables`
101
+ // or `payload.target`) — derived purely from what this run's own records
102
+ // name, never from a separate schema/telemetry read.
103
+ for (const record of params.records) {
104
+ for (const subject of record.subjects) {
105
+ if (!subject.startsWith("variable:") || elements.has(subject))
106
+ continue;
107
+ elements.set(subject, { ref: subject, kind: "variable", label: subject.slice("variable:".length) });
108
+ }
109
+ }
110
+ return [...elements.values()];
111
+ };
112
+ const stringMembers = (value) => Array.isArray(value) ? value.filter((member) => typeof member === "string") : [];
113
+ /**
114
+ * Parses `manifest.world` into the run's rooms, supporting both shapes: a
115
+ * single-network run's flat `{network_id, room_id, members}` (office-sim
116
+ * golden) and a multi-network composed run's `{rooms: [{network_id, room_id,
117
+ * members}, ...]}` (the jungian psyche, one entry per network's room).
118
+ */
119
+ const parseWorldRooms = (worldRecord) => {
120
+ const toRoom = (record) => {
121
+ const networkId = stringField(record, "network_id");
122
+ const roomId = stringField(record, "room_id");
123
+ if (!networkId || !roomId)
124
+ return undefined;
125
+ return { ref: roomRef(networkId, roomId), networkId, roomId, members: stringMembers(record?.members) };
126
+ };
127
+ const roomsRaw = worldRecord?.rooms;
128
+ if (Array.isArray(roomsRaw)) {
129
+ return roomsRaw
130
+ .map((entry) => toRoom(typeof entry === "object" && entry !== null ? entry : undefined))
131
+ .filter((room) => room !== undefined);
132
+ }
133
+ const single = toRoom(worldRecord);
134
+ return single ? [single] : [];
135
+ };
136
+ /**
137
+ * Reads and parses `manifest.json`'s `world` field into its declared rooms —
138
+ * the same parse `buildRunTimeline` does internally, exported so `server.ts`
139
+ * can tell an outer (parent-floor) room from an interior one when it builds
140
+ * the outer map's `/api/world` trace, without re-deriving the whole timeline.
141
+ */
142
+ export const readWorldRooms = async (runDir) => {
143
+ const manifest = parseRunManifest(JSON.parse(await readFile(path.join(runDir, "manifest.json"), "utf8")));
144
+ return parseWorldRooms(manifest.world);
145
+ };
146
+ export const buildRunTimeline = async (runDir) => {
147
+ const manifest = parseRunManifest(JSON.parse(await readFile(path.join(runDir, "manifest.json"), "utf8")));
148
+ const worldRecord = manifest.world;
149
+ const rooms = parseWorldRooms(worldRecord);
150
+ const room = rooms[0]?.ref;
151
+ const [streams, mnemeByBank, transcript, membranes] = await Promise.all([
152
+ collectCausalStreams(runDir),
153
+ readMnemeEventsByBank(runDir),
154
+ readTranscript(runDir),
155
+ readRunMembranes(runDir),
156
+ ]);
157
+ const messagesById = new Map(transcript.transcript.map((message) => [message.id, message]));
158
+ const roomsByMessageEventId = new Map();
159
+ for (const stream of streams) {
160
+ if (stream.authority !== "moltnet")
161
+ continue;
162
+ for (const event of stream.events) {
163
+ const messageRoom = roomForMoltnetMessage(event);
164
+ if (messageRoom)
165
+ roomsByMessageEventId.set(event.event_id, messageRoom);
166
+ }
167
+ }
168
+ const memoryContentById = new Map();
169
+ for (const bankEvents of mnemeByBank.values()) {
170
+ for (const event of bankEvents)
171
+ memoryContentById.set(event.id, event.content.text);
172
+ }
173
+ const ctx = { room, messagesById, roomsByMessageEventId, memoryContentById };
174
+ const records = [];
175
+ for (const stream of streams) {
176
+ const bank = bankFromRelativePath(stream.relativePath);
177
+ for (const event of stream.events) {
178
+ records.push(buildCausalRecord(event, stream.authority, bank, ctx));
179
+ }
180
+ }
181
+ for (const [bankName, bankEvents] of mnemeByBank) {
182
+ for (const event of bankEvents)
183
+ records.push(buildBankLogRecord(event, bankName));
184
+ }
185
+ const repaired = causalRepair(sortRecords(records));
186
+ const events = repaired.map((record, index) => ({
187
+ t: index,
188
+ eventId: record.eventId,
189
+ authority: record.authority,
190
+ streamId: record.streamId,
191
+ seq: record.seq,
192
+ type: record.type,
193
+ viewClass: record.viewClass,
194
+ recordedAt: record.recordedAt,
195
+ actor: record.actor,
196
+ subjects: record.subjects,
197
+ causes: record.causeIds,
198
+ text: record.text,
199
+ worldEventId: record.worldEventId,
200
+ payload: record.payload,
201
+ }));
202
+ const elements = buildElements({ rooms, membranes, streams, mnemeByBank, records });
203
+ return { version: "simfile.run-timeline.v1", runId: manifest.run_id, events, elements, membranes };
204
+ };
@@ -0,0 +1,42 @@
1
+ import type { CausalEvent } from "@noopolis/stele";
2
+ import type { RawMnemeEvent, RawTranscriptMessage } from "./runViewModelTypes.js";
3
+ import type { ElementRef, TimelineViewClass } from "./runTimelineTypes.js";
4
+ /**
5
+ * Per-authority (`moltnet`/`daimon`/`mneme`/`world`/mneme-bank-log) raw
6
+ * record builders, split out of `runTimeline.ts` (`AGENTS.md`: split before
7
+ * 400 lines) so the orchestrator (`buildRunTimeline`: merge, sort, causal
8
+ * repair, dense `t` assignment) stays the file that's easy to read
9
+ * end-to-end. `buildCausalRecord` is the one dispatcher every
10
+ * `raw/<authority>/causal.jsonl` record goes through; `buildBankLogRecord`
11
+ * is the parallel path for a mneme bank's `events.jsonl` rows.
12
+ */
13
+ /** Internal pre-`t` record: everything a `TimelineEvent` needs except its dense scrub index. */
14
+ export interface RawRecord {
15
+ eventId: string;
16
+ authority: string;
17
+ streamId: string;
18
+ seq: number;
19
+ type: string;
20
+ viewClass: TimelineViewClass;
21
+ recordedAt: string;
22
+ causeIds: string[];
23
+ actor?: string;
24
+ subjects: ElementRef[];
25
+ text?: string;
26
+ /** See `TimelineEvent.worldEventId`'s doc comment (`runTimelineTypes.ts`). */
27
+ worldEventId?: string;
28
+ payload: unknown;
29
+ }
30
+ export interface JoinContext {
31
+ room?: ElementRef;
32
+ messagesById: ReadonlyMap<string, RawTranscriptMessage>;
33
+ roomsByMessageEventId: ReadonlyMap<string, ElementRef>;
34
+ memoryContentById: ReadonlyMap<string, string>;
35
+ }
36
+ /** Resolves the room a moltnet `message.accepted` event targeted — `buildRunTimeline` uses this directly (not just `buildMoltnetRecord`) to build `roomsByMessageEventId`, the daimon-attribution join surface. */
37
+ export declare const roomForMoltnetMessage: (event: CausalEvent) => ElementRef | undefined;
38
+ /** The one dispatcher every `raw/<authority>/causal.jsonl` record goes through. */
39
+ export declare const buildCausalRecord: (event: CausalEvent, authority: string, bank: string | undefined, ctx: JoinContext) => RawRecord;
40
+ /** The parallel path for a mneme bank's `events.jsonl` rows (the human-readable memory log, distinct from that bank's `causal.jsonl`). */
41
+ export declare const buildBankLogRecord: (event: RawMnemeEvent, bankName: string) => RawRecord;
42
+ //# sourceMappingURL=runTimelineRecords.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runTimelineRecords.d.ts","sourceRoot":"","sources":["../../src/view/runTimelineRecords.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG3E;;;;;;;;GAQG;AAEH,gGAAgG;AAChG,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,iBAAiB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IACxD,qBAAqB,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvD,iBAAiB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChD;AA8BD,mNAAmN;AACnN,eAAO,MAAM,qBAAqB,GAAI,OAAO,WAAW,KAAG,UAAU,GAAG,SAQvE,CAAC;AAuLF,mFAAmF;AACnF,eAAO,MAAM,iBAAiB,GAC5B,OAAO,WAAW,EAClB,WAAW,MAAM,EACjB,MAAM,MAAM,GAAG,SAAS,EACxB,KAAK,WAAW,KACf,SAkBF,CAAC;AAEF,0IAA0I;AAC1I,eAAO,MAAM,kBAAkB,GAAI,OAAO,aAAa,EAAE,UAAU,MAAM,KAAG,SAgB3E,CAAC"}
@@ -0,0 +1,244 @@
1
+ import { agentIdFromStreamId, agentRef, bankRef, isDefined, messageText, networkIdFromStreamId, roomRef, stringField, variableRef } from "./runTimelineRefs.js";
2
+ const viewClassForCausalType = (type) => {
3
+ switch (type) {
4
+ case "message.accepted": return "message";
5
+ case "control.wake.accepted": return "wake";
6
+ case "turn.input.submitted": return "turn.input";
7
+ case "turn.output.completed": return "turn.output";
8
+ case "memory.recalled": return "memory.recalled";
9
+ // World-authority additions (increment 3, `buildWorldRecord` below):
10
+ // `world.message` is a message like any other room chat line;
11
+ // `wake.recommended` shares the daimon `control.wake.accepted` class
12
+ // (both mean "a wake was recommended/accepted for an agent").
13
+ case "clock.sync": return "clock";
14
+ case "marker.seen": return "marker";
15
+ case "world.message": return "message";
16
+ case "wake.recommended": return "wake";
17
+ default: return "other";
18
+ }
19
+ };
20
+ const viewClassForBankLogType = (type) => {
21
+ switch (type) {
22
+ case "memory.claimed": return "memory.claimed";
23
+ case "memory.observed": return "memory.observed";
24
+ case "memory.recalled": return "memory.recalled";
25
+ default: return "other";
26
+ }
27
+ };
28
+ /** Resolves the room a moltnet `message.accepted` event targeted — `buildRunTimeline` uses this directly (not just `buildMoltnetRecord`) to build `roomsByMessageEventId`, the daimon-attribution join surface. */
29
+ export const roomForMoltnetMessage = (event) => {
30
+ if (event.type !== "message.accepted")
31
+ return undefined;
32
+ const networkId = networkIdFromStreamId(event.emitter.stream_id);
33
+ const target = event.payload?.target;
34
+ if (!networkId || typeof target !== "object" || target === null)
35
+ return undefined;
36
+ const targetRecord = target;
37
+ const roomId = stringField(targetRecord, "room_id");
38
+ return targetRecord.kind === "room" && roomId ? roomRef(networkId, roomId) : undefined;
39
+ };
40
+ /**
41
+ * The `simfile_event_id` breadcrumb `src/moltnet/world-participant.ts`'s
42
+ * `metadataFromEvent` attaches to a message's first text part's `data` when
43
+ * that message originated from a world action — the real join surface for
44
+ * "this moltnet message echoes that world-authority event" (increment 3
45
+ * dedup rule). Undefined for a genuine agent-authored message, which has no
46
+ * such breadcrumb.
47
+ */
48
+ const worldEventIdFromMessage = (message) => {
49
+ const breadcrumb = message.parts.find((part) => part.kind === "text")?.data?.simfile_event_id;
50
+ return typeof breadcrumb === "string" ? breadcrumb : undefined;
51
+ };
52
+ const buildMoltnetRecord = (event, base, ctx) => {
53
+ // A message.accepted names its OWN room from its network stream_id +
54
+ // target.room_id (`roomForMoltnetMessage`), never the run's single primary
55
+ // room — the fix that keeps an inner-council message under
56
+ // `room:<inner_net>:<room>` in a multi-network run instead of collapsing
57
+ // every network's messages onto the floor room. Falls back to `ctx.room`
58
+ // only when the event carries no resolvable target (never, for a
59
+ // message.accepted).
60
+ const messageRoom = roomForMoltnetMessage(event) ?? ctx.room;
61
+ if (event.type !== "message.accepted") {
62
+ return { ...base, subjects: [ctx.room].filter(isDefined) };
63
+ }
64
+ const messageId = stringField(event.payload, "message_id");
65
+ const message = messageId ? ctx.messagesById.get(messageId) : undefined;
66
+ const authorId = message?.from.id;
67
+ return {
68
+ ...base,
69
+ actor: authorId,
70
+ subjects: [messageRoom, authorId ? agentRef(authorId) : undefined].filter(isDefined),
71
+ text: message ? messageText(message) : undefined,
72
+ worldEventId: message ? worldEventIdFromMessage(message) : undefined,
73
+ };
74
+ };
75
+ const buildDaimonRecord = (event, base, ctx) => {
76
+ const agentId = agentIdFromStreamId(event.emitter.stream_id);
77
+ const turnId = stringField(event.payload, "turn_id");
78
+ const causingMessageEventIds = [
79
+ turnId?.startsWith("moltnet:") ? turnId : undefined,
80
+ ...event.cause_event_ids,
81
+ ].filter(isDefined);
82
+ const causingRoom = causingMessageEventIds
83
+ .map((eventId) => ctx.roomsByMessageEventId.get(eventId))
84
+ .find(isDefined);
85
+ const subjects = [agentId ? agentRef(agentId) : undefined, causingRoom].filter(isDefined);
86
+ let text;
87
+ if (event.type === "turn.input.submitted") {
88
+ const causingMessageId = turnId?.startsWith("moltnet:") ? turnId.slice("moltnet:".length) : undefined;
89
+ const causingMessage = causingMessageId ? ctx.messagesById.get(causingMessageId) : undefined;
90
+ text = causingMessage ? messageText(causingMessage) : undefined;
91
+ }
92
+ return { ...base, actor: agentId, subjects, text };
93
+ };
94
+ const buildMnemeCausalRecord = (event, bank, base, ctx) => {
95
+ const agentId = event.principal_id.startsWith("agent:") ? event.principal_id.slice("agent:".length) : undefined;
96
+ const subjects = [bank ? bankRef(bank) : undefined, agentId ? agentRef(agentId) : undefined].filter(isDefined);
97
+ let text;
98
+ if (event.type === "memory.recalled") {
99
+ const memoryId = stringField(event.payload, "memory_id");
100
+ text = memoryId ? ctx.memoryContentById.get(memoryId) : undefined;
101
+ }
102
+ return { ...base, actor: agentId, subjects, text };
103
+ };
104
+ const roomTargetPattern = /^room:[^:]+:[^:]+$/u;
105
+ const agentTargetPattern = /^agent:[^:]+$/u;
106
+ /**
107
+ * The world clock's own anchor — increment 3's `clock.sync` subject. A
108
+ * `clock.sync` event names the tick axis itself, not any one room or agent,
109
+ * so it gets a dedicated ref rather than an empty `subjects` array (which
110
+ * would make it invisible to any future "world clock" storyline portal).
111
+ */
112
+ const globalClockRef = "clock:global";
113
+ /**
114
+ * The world stream's own `payload.target` is already an `ElementRef`-shaped
115
+ * string (`room:<network>:<room>` or `agent:<id>`, per
116
+ * `src/runtime/rule-actions.ts`'s `action.to` — a Simfile rule's `to:`
117
+ * field, e.g. `room:office_lab:office-room` or `agent:eleanor`) for every
118
+ * world event kind this run emits. Returned verbatim when it matches one of
119
+ * those two shapes; `undefined` otherwise (e.g. `clock.sync`'s `"global"`,
120
+ * which has no per-room/per-agent subject of its own).
121
+ */
122
+ const worldTargetRef = (payload) => {
123
+ const target = stringField(payload, "target");
124
+ if (!target)
125
+ return undefined;
126
+ return roomTargetPattern.test(target) || agentTargetPattern.test(target) ? target : undefined;
127
+ };
128
+ /**
129
+ * Increment 4's variable storyline join: the `variables: string[]` payload
130
+ * field `src/runtime/step-tick.ts`'s `runRule` (and `rule-actions.ts`'s
131
+ * `emitRuleActionEvents`) stamps onto a `rule.fired` event and every
132
+ * world-effect event it emits, whenever that rule's own `when:` condition
133
+ * references at least one variable (`conditionVariableIds`). Read straight
134
+ * off the event's own payload — never invented — and turned into
135
+ * `variable:<id>` subjects so the variable's storyline
136
+ * (`eventsForElement(timeline, "variable:<id>")`) includes the rule firing
137
+ * and the message/dm/wake it caused. Absent on a `clock.sync` (every tick,
138
+ * not this rule's own event) and on any rule with no variable condition.
139
+ */
140
+ const variableRefsFromPayload = (payload) => {
141
+ const raw = payload?.variables;
142
+ if (!Array.isArray(raw))
143
+ return [];
144
+ return raw.filter((id) => typeof id === "string").map(variableRef);
145
+ };
146
+ /**
147
+ * World-authority records (`raw/world/causal.jsonl`, increment 3): the
148
+ * mechanical clock/marker/message/wake stream a world-driven run emits
149
+ * alongside the agents' own moltnet/daimon/mneme streams.
150
+ * - `clock.sync` anchors the tick axis itself (`globalClockRef`), never a
151
+ * room — it is the run's own heartbeat, not a room event.
152
+ * - `marker.seen` is attributed to the room plus the real agent who
153
+ * authored the moltnet message that tripped it, joined by
154
+ * `source_event_id` (a bare transcript message `id`, never `moltnet:`-
155
+ * prefixed — confirmed against this run's own fixture) against
156
+ * `ctx.messagesById`, never invented from the marker's own `alias`.
157
+ * - `world.message`/`world.dm` are attributed to the room/agent the action
158
+ * targeted, with `text` joined from the event's own `content` field (the
159
+ * same text moltnet re-delivers as the echo message this dedups against).
160
+ * - `world.act` is attributed directly to the fed variable it wrote
161
+ * (`payload.target` IS the variable id for this event type, unlike every
162
+ * other world event kind where `target` is a room/agent ref).
163
+ * - `wake.recommended` and any other world event type (`rule.fired`, ...)
164
+ * fall back to the event's own `target` ref, or the run's single room
165
+ * when `target` doesn't resolve to one.
166
+ * - Every branch additionally folds in `variable:<id>` subjects from the
167
+ * event's own `payload.variables` (`variableRefsFromPayload`) when
168
+ * present — increment 4's variable storyline join.
169
+ */
170
+ const buildWorldRecord = (event, base, ctx) => {
171
+ const payload = event.payload;
172
+ const targetRef = worldTargetRef(payload);
173
+ const variableSubjects = variableRefsFromPayload(payload);
174
+ const withVariableSubjects = (record) => variableSubjects.length === 0 ? record : { ...record, subjects: [...new Set([...record.subjects, ...variableSubjects])] };
175
+ if (event.type === "clock.sync") {
176
+ return withVariableSubjects({ ...base, subjects: [globalClockRef] });
177
+ }
178
+ if (event.type === "marker.seen") {
179
+ const sourceEventId = stringField(payload, "source_event_id");
180
+ const sourceMessage = sourceEventId ? ctx.messagesById.get(sourceEventId) : undefined;
181
+ const authorId = sourceMessage?.from.id;
182
+ return withVariableSubjects({
183
+ ...base,
184
+ actor: authorId,
185
+ subjects: [ctx.room ?? targetRef, authorId ? agentRef(authorId) : undefined].filter(isDefined),
186
+ });
187
+ }
188
+ if (event.type === "world.message" || event.type === "world.dm") {
189
+ return withVariableSubjects({
190
+ ...base,
191
+ subjects: [ctx.room ?? targetRef].filter(isDefined),
192
+ text: stringField(payload, "content"),
193
+ });
194
+ }
195
+ if (event.type === "world.act") {
196
+ const fedVariableId = stringField(payload, "target");
197
+ return withVariableSubjects({
198
+ ...base,
199
+ subjects: [fedVariableId ? variableRef(fedVariableId) : (targetRef ?? ctx.room)].filter(isDefined),
200
+ });
201
+ }
202
+ return withVariableSubjects({ ...base, subjects: [targetRef ?? ctx.room].filter(isDefined) });
203
+ };
204
+ /** The one dispatcher every `raw/<authority>/causal.jsonl` record goes through. */
205
+ export const buildCausalRecord = (event, authority, bank, ctx) => {
206
+ const base = {
207
+ eventId: event.event_id,
208
+ authority,
209
+ streamId: event.emitter.stream_id,
210
+ seq: event.emitter.seq,
211
+ type: event.type,
212
+ viewClass: viewClassForCausalType(event.type),
213
+ recordedAt: event.recorded_at,
214
+ causeIds: event.cause_event_ids,
215
+ payload: event.payload,
216
+ };
217
+ if (authority === "moltnet")
218
+ return buildMoltnetRecord(event, base, ctx);
219
+ if (authority === "daimon")
220
+ return buildDaimonRecord(event, base, ctx);
221
+ if (authority === "mneme")
222
+ return buildMnemeCausalRecord(event, bank, base, ctx);
223
+ if (authority === "world")
224
+ return buildWorldRecord(event, base, ctx);
225
+ return { ...base, subjects: [] };
226
+ };
227
+ /** The parallel path for a mneme bank's `events.jsonl` rows (the human-readable memory log, distinct from that bank's `causal.jsonl`). */
228
+ export const buildBankLogRecord = (event, bankName) => {
229
+ const agentId = event.principal.agentId;
230
+ return {
231
+ eventId: event.id,
232
+ authority: "mneme",
233
+ streamId: bankRef(bankName),
234
+ seq: event.seq ?? 0,
235
+ type: event.type,
236
+ viewClass: viewClassForBankLogType(event.type),
237
+ recordedAt: event.createdAt,
238
+ causeIds: event.parentEventIds ?? [],
239
+ actor: agentId,
240
+ subjects: [bankRef(bankName), agentRef(agentId)],
241
+ text: event.content.text,
242
+ payload: event.content,
243
+ };
244
+ };
@@ -0,0 +1,27 @@
1
+ import type { RawTranscriptMessage } from "./runViewModelTypes.js";
2
+ import type { ElementRef } from "./runTimelineTypes.js";
3
+ /**
4
+ * The small, generic `ElementRef`/string helpers `runTimeline.ts` (the
5
+ * orchestrator) and `runTimelineRecords.ts` (the per-authority record
6
+ * builders) both need — split out so neither file has to import the other
7
+ * just for a one-line ref constructor (`AGENTS.md`: small composable
8
+ * modules, split before 400 lines).
9
+ */
10
+ export declare const agentRef: (id: string) => ElementRef;
11
+ export declare const roomRef: (network: string, room: string) => ElementRef;
12
+ export declare const bankRef: (bank: string) => ElementRef;
13
+ export declare const variableRef: (id: string) => ElementRef;
14
+ /** Inverse of `roomRef`: splits a `room:<network>:<room>` ref back into its parts. `undefined` for anything else. */
15
+ export declare const parseRoomRef: (ref: ElementRef) => {
16
+ networkId: string;
17
+ roomId: string;
18
+ } | undefined;
19
+ /** Strips a ref's `<kind>:` prefix, e.g. `agent:luna-shadow` -> `luna-shadow`. Refs with no `:` pass through unchanged. */
20
+ export declare const stripRefPrefix: (ref: ElementRef) => string;
21
+ export declare const isDefined: <T>(value: T | undefined) => value is T;
22
+ export declare const stringField: (record: Record<string, unknown> | undefined, key: string) => string | undefined;
23
+ export declare const messageText: (message: RawTranscriptMessage) => string;
24
+ export declare const agentIdFromStreamId: (streamId: string) => string | undefined;
25
+ export declare const networkIdFromStreamId: (streamId: string) => string | undefined;
26
+ export declare const bankFromRelativePath: (relativePath: string) => string | undefined;
27
+ //# sourceMappingURL=runTimelineRefs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runTimelineRefs.d.ts","sourceRoot":"","sources":["../../src/view/runTimelineRefs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD;;;;;;GAMG;AAEH,eAAO,MAAM,QAAQ,GAAI,IAAI,MAAM,KAAG,UAA2B,CAAC;AAClE,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,EAAE,MAAM,MAAM,KAAG,UAAuC,CAAC;AAChG,eAAO,MAAM,OAAO,GAAI,MAAM,MAAM,KAAG,UAA4B,CAAC;AACpE,eAAO,MAAM,WAAW,GAAI,IAAI,MAAM,KAAG,UAA8B,CAAC;AAExE,qHAAqH;AACrH,eAAO,MAAM,YAAY,GAAI,KAAK,UAAU,KAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAGtF,CAAC;AAEF,2HAA2H;AAC3H,eAAO,MAAM,cAAc,GAAI,KAAK,UAAU,KAAG,MAAqE,CAAC;AAEvH,eAAO,MAAM,SAAS,GAAI,CAAC,EAAG,OAAO,CAAC,GAAG,SAAS,KAAG,KAAK,IAAI,CAAwB,CAAC;AAEvF,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,KAAK,MAAM,KAAG,MAAM,GAAG,SAG/F,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,SAAS,oBAAoB,KAAG,MACI,CAAC;AAEjE,eAAO,MAAM,mBAAmB,GAAI,UAAU,MAAM,KAAG,MAAM,GAAG,SAAiD,CAAC;AAElH,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,KAAG,MAAM,GAAG,SAAmD,CAAC;AAEtH,eAAO,MAAM,oBAAoB,GAAI,cAAc,MAAM,KAAG,MAAM,GAAG,SAGpE,CAAC"}
@@ -0,0 +1,31 @@
1
+ import path from "node:path";
2
+ /**
3
+ * The small, generic `ElementRef`/string helpers `runTimeline.ts` (the
4
+ * orchestrator) and `runTimelineRecords.ts` (the per-authority record
5
+ * builders) both need — split out so neither file has to import the other
6
+ * just for a one-line ref constructor (`AGENTS.md`: small composable
7
+ * modules, split before 400 lines).
8
+ */
9
+ export const agentRef = (id) => `agent:${id}`;
10
+ export const roomRef = (network, room) => `room:${network}:${room}`;
11
+ export const bankRef = (bank) => `bank:${bank}`;
12
+ export const variableRef = (id) => `variable:${id}`;
13
+ /** Inverse of `roomRef`: splits a `room:<network>:<room>` ref back into its parts. `undefined` for anything else. */
14
+ export const parseRoomRef = (ref) => {
15
+ const match = ref.match(/^room:([^:]+):(.+)$/u);
16
+ return match ? { networkId: match[1], roomId: match[2] } : undefined;
17
+ };
18
+ /** Strips a ref's `<kind>:` prefix, e.g. `agent:luna-shadow` -> `luna-shadow`. Refs with no `:` pass through unchanged. */
19
+ export const stripRefPrefix = (ref) => (ref.includes(":") ? ref.slice(ref.indexOf(":") + 1) : ref);
20
+ export const isDefined = (value) => value !== undefined;
21
+ export const stringField = (record, key) => {
22
+ const value = record?.[key];
23
+ return typeof value === "string" ? value : undefined;
24
+ };
25
+ export const messageText = (message) => message.parts.find((part) => part.kind === "text")?.text ?? "";
26
+ export const agentIdFromStreamId = (streamId) => streamId.match(/^agent:(.+)$/u)?.[1];
27
+ export const networkIdFromStreamId = (streamId) => streamId.match(/^network:(.+)$/u)?.[1];
28
+ export const bankFromRelativePath = (relativePath) => {
29
+ const segments = relativePath.split(path.sep);
30
+ return segments[0] === "raw" && segments[1] === "mneme" ? segments[2] : undefined;
31
+ };