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.
- package/README.md +143 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +348 -0
- package/dist/coverage/index.d.ts +2 -0
- package/dist/coverage/index.d.ts.map +1 -0
- package/dist/coverage/index.js +1 -0
- package/dist/coverage/matrix.d.ts +21 -0
- package/dist/coverage/matrix.d.ts.map +1 -0
- package/dist/coverage/matrix.js +173 -0
- package/dist/coverage/render.d.ts +3 -0
- package/dist/coverage/render.d.ts.map +1 -0
- package/dist/coverage/render.js +26 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/kernel/duration.d.ts +9 -0
- package/dist/kernel/duration.d.ts.map +1 -0
- package/dist/kernel/duration.js +44 -0
- package/dist/kernel/index.d.ts +4 -0
- package/dist/kernel/index.d.ts.map +1 -0
- package/dist/kernel/index.js +3 -0
- package/dist/kernel/range.d.ts +6 -0
- package/dist/kernel/range.d.ts.map +1 -0
- package/dist/kernel/range.js +16 -0
- package/dist/kernel/stochastic.d.ts +10 -0
- package/dist/kernel/stochastic.d.ts.map +1 -0
- package/dist/kernel/stochastic.js +25 -0
- package/dist/ledger/index.d.ts +4 -0
- package/dist/ledger/index.d.ts.map +1 -0
- package/dist/ledger/index.js +3 -0
- package/dist/ledger/markers.d.ts +46 -0
- package/dist/ledger/markers.d.ts.map +1 -0
- package/dist/ledger/markers.js +108 -0
- package/dist/ledger/stable.d.ts +65 -0
- package/dist/ledger/stable.d.ts.map +1 -0
- package/dist/ledger/stable.js +78 -0
- package/dist/ledger/validation.d.ts +16 -0
- package/dist/ledger/validation.d.ts.map +1 -0
- package/dist/ledger/validation.js +127 -0
- package/dist/moltnet/index.d.ts +3 -0
- package/dist/moltnet/index.d.ts.map +1 -0
- package/dist/moltnet/index.js +2 -0
- package/dist/moltnet/transcript-export.d.ts +34 -0
- package/dist/moltnet/transcript-export.d.ts.map +1 -0
- package/dist/moltnet/transcript-export.js +68 -0
- package/dist/moltnet/world-participant.d.ts +77 -0
- package/dist/moltnet/world-participant.d.ts.map +1 -0
- package/dist/moltnet/world-participant.js +221 -0
- package/dist/observe/artifacts.d.ts +16 -0
- package/dist/observe/artifacts.d.ts.map +1 -0
- package/dist/observe/artifacts.js +31 -0
- package/dist/observe/causalStreams.d.ts +19 -0
- package/dist/observe/causalStreams.d.ts.map +1 -0
- package/dist/observe/causalStreams.js +38 -0
- package/dist/observe/compute.d.ts +17 -0
- package/dist/observe/compute.d.ts.map +1 -0
- package/dist/observe/compute.js +97 -0
- package/dist/observe/index.d.ts +11 -0
- package/dist/observe/index.d.ts.map +1 -0
- package/dist/observe/index.js +10 -0
- package/dist/observe/manifest.d.ts +79 -0
- package/dist/observe/manifest.d.ts.map +1 -0
- package/dist/observe/manifest.js +87 -0
- package/dist/observe/memoryBanks.d.ts +38 -0
- package/dist/observe/memoryBanks.d.ts.map +1 -0
- package/dist/observe/memoryBanks.js +86 -0
- package/dist/observe/observe.d.ts +32 -0
- package/dist/observe/observe.d.ts.map +1 -0
- package/dist/observe/observe.js +73 -0
- package/dist/observe/report.d.ts +165 -0
- package/dist/observe/report.d.ts.map +1 -0
- package/dist/observe/report.js +138 -0
- package/dist/observe/seedSpread.d.ts +49 -0
- package/dist/observe/seedSpread.d.ts.map +1 -0
- package/dist/observe/seedSpread.js +262 -0
- package/dist/observe/seedSpreadArtifacts.d.ts +49 -0
- package/dist/observe/seedSpreadArtifacts.d.ts.map +1 -0
- package/dist/observe/seedSpreadArtifacts.js +118 -0
- package/dist/observe/spreadMatcher.d.ts +45 -0
- package/dist/observe/spreadMatcher.d.ts.map +1 -0
- package/dist/observe/spreadMatcher.js +124 -0
- package/dist/report/index.d.ts +4 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +3 -0
- package/dist/report/probeArtifact.d.ts +26 -0
- package/dist/report/probeArtifact.d.ts.map +1 -0
- package/dist/report/probeArtifact.js +119 -0
- package/dist/report/probes.d.ts +52 -0
- package/dist/report/probes.d.ts.map +1 -0
- package/dist/report/probes.js +164 -0
- package/dist/report/score.d.ts +27 -0
- package/dist/report/score.d.ts.map +1 -0
- package/dist/report/score.js +14 -0
- package/dist/report/transcripts.d.ts +12 -0
- package/dist/report/transcripts.d.ts.map +1 -0
- package/dist/report/transcripts.js +17 -0
- package/dist/runtime/causal-fixture.d.ts +26 -0
- package/dist/runtime/causal-fixture.d.ts.map +1 -0
- package/dist/runtime/causal-fixture.js +36 -0
- package/dist/runtime/clock.d.ts +25 -0
- package/dist/runtime/clock.d.ts.map +1 -0
- package/dist/runtime/clock.js +63 -0
- package/dist/runtime/condition.d.ts +55 -0
- package/dist/runtime/condition.d.ts.map +1 -0
- package/dist/runtime/condition.js +122 -0
- package/dist/runtime/emit-causal-fixture.d.ts +2 -0
- package/dist/runtime/emit-causal-fixture.d.ts.map +1 -0
- package/dist/runtime/emit-causal-fixture.js +45 -0
- package/dist/runtime/expression.d.ts +11 -0
- package/dist/runtime/expression.d.ts.map +1 -0
- package/dist/runtime/expression.js +305 -0
- package/dist/runtime/numeric.d.ts +7 -0
- package/dist/runtime/numeric.d.ts.map +1 -0
- package/dist/runtime/numeric.js +11 -0
- package/dist/runtime/rule-actions.d.ts +5 -0
- package/dist/runtime/rule-actions.d.ts.map +1 -0
- package/dist/runtime/rule-actions.js +82 -0
- package/dist/runtime/run-record.d.ts +73 -0
- package/dist/runtime/run-record.d.ts.map +1 -0
- package/dist/runtime/run-record.js +179 -0
- package/dist/runtime/step-tick.d.ts +43 -0
- package/dist/runtime/step-tick.d.ts.map +1 -0
- package/dist/runtime/step-tick.js +177 -0
- package/dist/runtime/trace-compile.d.ts +66 -0
- package/dist/runtime/trace-compile.d.ts.map +1 -0
- package/dist/runtime/trace-compile.js +157 -0
- package/dist/runtime/trace-export.d.ts +5 -0
- package/dist/runtime/trace-export.d.ts.map +1 -0
- package/dist/runtime/trace-export.js +4 -0
- package/dist/runtime/trace-run.d.ts +15 -0
- package/dist/runtime/trace-run.d.ts.map +1 -0
- package/dist/runtime/trace-run.js +92 -0
- package/dist/runtime/trace.d.ts +10 -0
- package/dist/runtime/trace.d.ts.map +1 -0
- package/dist/runtime/trace.js +9 -0
- package/dist/runtime/types.d.ts +61 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime/viewer-trace.d.ts +64 -0
- package/dist/runtime/viewer-trace.d.ts.map +1 -0
- package/dist/runtime/viewer-trace.js +164 -0
- package/dist/runtime/world-act.d.ts +55 -0
- package/dist/runtime/world-act.d.ts.map +1 -0
- package/dist/runtime/world-act.js +156 -0
- package/dist/schema/binding.d.ts +23 -0
- package/dist/schema/binding.d.ts.map +1 -0
- package/dist/schema/binding.js +249 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +4 -0
- package/dist/schema/model.d.ts +244 -0
- package/dist/schema/model.d.ts.map +1 -0
- package/dist/schema/model.js +222 -0
- package/dist/schema/parse.d.ts +10 -0
- package/dist/schema/parse.d.ts.map +1 -0
- package/dist/schema/parse.js +15 -0
- package/dist/schema/semantic.d.ts +3 -0
- package/dist/schema/semantic.d.ts.map +1 -0
- package/dist/schema/semantic.js +135 -0
- package/dist/sims/composeRunManifest.d.ts +54 -0
- package/dist/sims/composeRunManifest.d.ts.map +1 -0
- package/dist/sims/composeRunManifest.js +40 -0
- package/dist/sims/composedJungianSimDriver.d.ts +50 -0
- package/dist/sims/composedJungianSimDriver.d.ts.map +1 -0
- package/dist/sims/composedJungianSimDriver.js +199 -0
- package/dist/sims/composedOfficeSimDriver.d.ts +53 -0
- package/dist/sims/composedOfficeSimDriver.d.ts.map +1 -0
- package/dist/sims/composedOfficeSimDriver.js +162 -0
- package/dist/sims/exchangeWait.d.ts +56 -0
- package/dist/sims/exchangeWait.d.ts.map +1 -0
- package/dist/sims/exchangeWait.js +66 -0
- package/dist/sims/index.d.ts +14 -0
- package/dist/sims/index.d.ts.map +1 -0
- package/dist/sims/index.js +13 -0
- package/dist/sims/moltnetRoomClient.d.ts +47 -0
- package/dist/sims/moltnetRoomClient.d.ts.map +1 -0
- package/dist/sims/moltnetRoomClient.js +41 -0
- package/dist/sims/poll.d.ts +19 -0
- package/dist/sims/poll.d.ts.map +1 -0
- package/dist/sims/poll.js +23 -0
- package/dist/sims/spawnfileCli.d.ts +49 -0
- package/dist/sims/spawnfileCli.d.ts.map +1 -0
- package/dist/sims/spawnfileCli.js +90 -0
- package/dist/sims/spawnfileReceipts.d.ts +76 -0
- package/dist/sims/spawnfileReceipts.d.ts.map +1 -0
- package/dist/sims/spawnfileReceipts.js +107 -0
- package/dist/sims/worldDrivenOfficeSimDriver.d.ts +59 -0
- package/dist/sims/worldDrivenOfficeSimDriver.d.ts.map +1 -0
- package/dist/sims/worldDrivenOfficeSimDriver.js +182 -0
- package/dist/sims/worldLedgerWriter.d.ts +32 -0
- package/dist/sims/worldLedgerWriter.d.ts.map +1 -0
- package/dist/sims/worldLedgerWriter.js +39 -0
- package/dist/sims/worldSeedLint.d.ts +42 -0
- package/dist/sims/worldSeedLint.d.ts.map +1 -0
- package/dist/sims/worldSeedLint.js +73 -0
- package/dist/sims/worldTickIngest.d.ts +27 -0
- package/dist/sims/worldTickIngest.d.ts.map +1 -0
- package/dist/sims/worldTickIngest.js +35 -0
- package/dist/sims/worldTickLoop.d.ts +64 -0
- package/dist/sims/worldTickLoop.d.ts.map +1 -0
- package/dist/sims/worldTickLoop.js +122 -0
- package/dist/view/engineProvenance.d.ts +46 -0
- package/dist/view/engineProvenance.d.ts.map +1 -0
- package/dist/view/engineProvenance.js +76 -0
- package/dist/view/index.d.ts +14 -0
- package/dist/view/index.d.ts.map +1 -0
- package/dist/view/index.js +107 -0
- package/dist/view/membranes.d.ts +14 -0
- package/dist/view/membranes.d.ts.map +1 -0
- package/dist/view/membranes.js +127 -0
- package/dist/view/runDetect.d.ts +2 -0
- package/dist/view/runDetect.d.ts.map +1 -0
- package/dist/view/runDetect.js +47 -0
- package/dist/view/runRawArtifacts.d.ts +48 -0
- package/dist/view/runRawArtifacts.d.ts.map +1 -0
- package/dist/view/runRawArtifacts.js +143 -0
- package/dist/view/runTimeline.d.ts +24 -0
- package/dist/view/runTimeline.d.ts.map +1 -0
- package/dist/view/runTimeline.js +204 -0
- package/dist/view/runTimelineRecords.d.ts +42 -0
- package/dist/view/runTimelineRecords.d.ts.map +1 -0
- package/dist/view/runTimelineRecords.js +244 -0
- package/dist/view/runTimelineRefs.d.ts +27 -0
- package/dist/view/runTimelineRefs.d.ts.map +1 -0
- package/dist/view/runTimelineRefs.js +31 -0
- package/dist/view/runTimelineTypes.d.ts +99 -0
- package/dist/view/runTimelineTypes.d.ts.map +1 -0
- package/dist/view/runTimelineTypes.js +1 -0
- package/dist/view/runViewModel.d.ts +21 -0
- package/dist/view/runViewModel.d.ts.map +1 -0
- package/dist/view/runViewModel.js +66 -0
- package/dist/view/runViewModelCompute.d.ts +24 -0
- package/dist/view/runViewModelCompute.d.ts.map +1 -0
- package/dist/view/runViewModelCompute.js +157 -0
- package/dist/view/runViewModelTypes.d.ts +177 -0
- package/dist/view/runViewModelTypes.d.ts.map +1 -0
- package/dist/view/runViewModelTypes.js +1 -0
- package/dist/view/runWorldTrace.d.ts +97 -0
- package/dist/view/runWorldTrace.d.ts.map +1 -0
- package/dist/view/runWorldTrace.js +88 -0
- package/dist/view/server.d.ts +12 -0
- package/dist/view/server.d.ts.map +1 -0
- package/dist/view/server.js +306 -0
- package/package.json +65 -0
- package/web/dist/assets/index-CJHLjfsG.js +49 -0
- package/web/dist/assets/index-DJOsPsU8.css +1 -0
- package/web/dist/index.html +13 -0
- package/web/dist/models/AnimatedMushnub.glb +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* Causal envelope constants shared with `specs/causal-event.v1.schema.json`
|
|
4
|
+
* (root, canonical) and `specs/CAUSAL.md`. Simfile does not import that
|
|
5
|
+
* schema file directly — this is simfile's own native TS copy of the wire
|
|
6
|
+
* contract, per the "type sharing" rule: siblings do not vendor the schema,
|
|
7
|
+
* they each hand-write a native type and stay conformant with the wire JSON.
|
|
8
|
+
*/
|
|
9
|
+
export const CAUSAL_ENVELOPE_VERSION = "noopolis.causal-event.v1";
|
|
10
|
+
export const SIMFILE_EMITTER_SYSTEM = "simfile";
|
|
11
|
+
export const DEFAULT_EMITTER_STREAM_ID = "world";
|
|
12
|
+
export const DEFAULT_PRINCIPAL_ID = "system:simfile.world";
|
|
13
|
+
const asJsonCompatible = (value) => {
|
|
14
|
+
if (value === null) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(value)) {
|
|
21
|
+
return value.map(asJsonCompatible);
|
|
22
|
+
}
|
|
23
|
+
if (typeof value === "object") {
|
|
24
|
+
const ordered = Object.keys(value)
|
|
25
|
+
.sort()
|
|
26
|
+
.reduce((acc, key) => {
|
|
27
|
+
const nested = value[key];
|
|
28
|
+
if (nested !== undefined) {
|
|
29
|
+
acc[key] = asJsonCompatible(nested);
|
|
30
|
+
}
|
|
31
|
+
return acc;
|
|
32
|
+
}, {});
|
|
33
|
+
return ordered;
|
|
34
|
+
}
|
|
35
|
+
return String(value);
|
|
36
|
+
};
|
|
37
|
+
export const stableStringify = (value) => {
|
|
38
|
+
return JSON.stringify(asJsonCompatible(value));
|
|
39
|
+
};
|
|
40
|
+
/** simfile's event_id convention: `simfile:<runId>:<seq>` (system:local, per the shared schema). */
|
|
41
|
+
export const createEventId = (runId, seq) => `${SIMFILE_EMITTER_SYSTEM}:${runId}:${seq}`;
|
|
42
|
+
const defaultRecordedAt = (simTime) => new Date(Math.max(0, Number.isFinite(simTime) ? simTime : 0) * 1000).toISOString();
|
|
43
|
+
export const createCanonicalEventEnvelope = (input) => {
|
|
44
|
+
if (!Number.isInteger(input.seq) || input.seq < 1) {
|
|
45
|
+
throw new Error(`seq must be a positive integer: ${input.seq}`);
|
|
46
|
+
}
|
|
47
|
+
if (!Number.isFinite(input.simTime)) {
|
|
48
|
+
throw new Error(`simTime must be finite: ${input.simTime}`);
|
|
49
|
+
}
|
|
50
|
+
if (input.runId.length === 0) {
|
|
51
|
+
throw new Error("runId must not be empty");
|
|
52
|
+
}
|
|
53
|
+
const streamId = input.streamId ?? DEFAULT_EMITTER_STREAM_ID;
|
|
54
|
+
const principalId = input.principalId ?? DEFAULT_PRINCIPAL_ID;
|
|
55
|
+
const causeEventIds = input.causeEventIds ? [...input.causeEventIds] : [];
|
|
56
|
+
return {
|
|
57
|
+
version: CAUSAL_ENVELOPE_VERSION,
|
|
58
|
+
run_id: input.runId,
|
|
59
|
+
event_id: createEventId(input.runId, input.seq),
|
|
60
|
+
emitter: {
|
|
61
|
+
system: SIMFILE_EMITTER_SYSTEM,
|
|
62
|
+
stream_id: streamId,
|
|
63
|
+
seq: input.seq
|
|
64
|
+
},
|
|
65
|
+
kind: input.kind,
|
|
66
|
+
principal_id: principalId,
|
|
67
|
+
recorded_at: input.observedAt ?? defaultRecordedAt(input.simTime),
|
|
68
|
+
cause_event_ids: causeEventIds,
|
|
69
|
+
sim_time: input.simTime,
|
|
70
|
+
provenance: input.provenance,
|
|
71
|
+
actor: input.actor,
|
|
72
|
+
target: input.target,
|
|
73
|
+
scope: input.scope,
|
|
74
|
+
payload: input.payload
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
export const stableEventLine = (input) => stableStringify(createCanonicalEventEnvelope(input));
|
|
78
|
+
export const createEventDigest = (input) => createHash("sha256").update(stableEventLine(input)).digest("hex");
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type LedgerEventEnvelope } from "./stable.js";
|
|
2
|
+
export interface CanonicalLedgerValidationOptions {
|
|
3
|
+
runId?: string;
|
|
4
|
+
/** Restrict validation to a single emitter stream (defaults to accepting any). */
|
|
5
|
+
streamId?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Validates and normalizes a stream of simfile causal ledger envelopes.
|
|
9
|
+
*
|
|
10
|
+
* Contiguity is generalized to (run_id, stream_id): every emitter.seq must be
|
|
11
|
+
* 1-based and contiguous within its own (run_id, stream_id) group, even if
|
|
12
|
+
* multiple streams are interleaved across the input array.
|
|
13
|
+
*/
|
|
14
|
+
export declare const validateCanonicalLedgerEvents: (events: readonly unknown[], options?: CanonicalLedgerValidationOptions) => LedgerEventEnvelope[];
|
|
15
|
+
export declare const parseCanonicalLedgerJsonl: (source: string, options?: CanonicalLedgerValidationOptions) => LedgerEventEnvelope[];
|
|
16
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/ledger/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,mBAAmB,EAEzB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,gCAAgC;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAiDD;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,GACxC,QAAQ,SAAS,OAAO,EAAE,EAC1B,UAAS,gCAAqC,KAC7C,mBAAmB,EAuErB,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,QAAQ,MAAM,EACd,UAAS,gCAAqC,KAC7C,mBAAmB,EAerB,CAAC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { createEventId, stableStringify, CAUSAL_ENVELOPE_VERSION, SIMFILE_EMITTER_SYSTEM } from "./stable.js";
|
|
2
|
+
const provenanceValues = new Set(["mechanical", "agentic", "external"]);
|
|
3
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4
|
+
const requireString = (event, key, index) => {
|
|
5
|
+
const value = event[key];
|
|
6
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
7
|
+
throw new Error(`ledger event ${index} has invalid ${key}`);
|
|
8
|
+
}
|
|
9
|
+
return value;
|
|
10
|
+
};
|
|
11
|
+
const requireStringArray = (event, key, index) => {
|
|
12
|
+
const value = event[key];
|
|
13
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string" || entry.length === 0)) {
|
|
14
|
+
throw new Error(`ledger event ${index} has invalid ${key}`);
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
17
|
+
};
|
|
18
|
+
const requirePayload = (event, index) => {
|
|
19
|
+
if (!Object.hasOwn(event, "payload") || event.payload === undefined) {
|
|
20
|
+
throw new Error(`ledger event ${index} is missing payload`);
|
|
21
|
+
}
|
|
22
|
+
return event.payload;
|
|
23
|
+
};
|
|
24
|
+
const requireEmitter = (event, index) => {
|
|
25
|
+
const emitter = event.emitter;
|
|
26
|
+
if (!isRecord(emitter)) {
|
|
27
|
+
throw new Error(`ledger event ${index} has invalid emitter`);
|
|
28
|
+
}
|
|
29
|
+
if (emitter.system !== SIMFILE_EMITTER_SYSTEM) {
|
|
30
|
+
throw new Error(`ledger event ${index} has invalid emitter.system`);
|
|
31
|
+
}
|
|
32
|
+
const streamId = emitter.stream_id;
|
|
33
|
+
if (typeof streamId !== "string" || streamId.length === 0) {
|
|
34
|
+
throw new Error(`ledger event ${index} has invalid emitter.stream_id`);
|
|
35
|
+
}
|
|
36
|
+
const seq = emitter.seq;
|
|
37
|
+
if (typeof seq !== "number" || !Number.isInteger(seq) || seq < 1) {
|
|
38
|
+
throw new Error(`ledger event ${index} has invalid emitter.seq`);
|
|
39
|
+
}
|
|
40
|
+
return { system: SIMFILE_EMITTER_SYSTEM, stream_id: streamId, seq };
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Validates and normalizes a stream of simfile causal ledger envelopes.
|
|
44
|
+
*
|
|
45
|
+
* Contiguity is generalized to (run_id, stream_id): every emitter.seq must be
|
|
46
|
+
* 1-based and contiguous within its own (run_id, stream_id) group, even if
|
|
47
|
+
* multiple streams are interleaved across the input array.
|
|
48
|
+
*/
|
|
49
|
+
export const validateCanonicalLedgerEvents = (events, options = {}) => {
|
|
50
|
+
let runId = options.runId;
|
|
51
|
+
const nextSeqByStream = new Map();
|
|
52
|
+
return events.map((event, index) => {
|
|
53
|
+
if (!isRecord(event)) {
|
|
54
|
+
throw new Error(`ledger event ${index} is not an object`);
|
|
55
|
+
}
|
|
56
|
+
const version = event.version;
|
|
57
|
+
if (version !== CAUSAL_ENVELOPE_VERSION) {
|
|
58
|
+
throw new Error(`ledger event ${index} has invalid version`);
|
|
59
|
+
}
|
|
60
|
+
const eventRunId = requireString(event, "run_id", index);
|
|
61
|
+
runId ??= eventRunId;
|
|
62
|
+
if (eventRunId !== runId) {
|
|
63
|
+
throw new Error(`ledger event ${index} has mismatched run_id`);
|
|
64
|
+
}
|
|
65
|
+
const emitter = requireEmitter(event, index);
|
|
66
|
+
if (options.streamId !== undefined && emitter.stream_id !== options.streamId) {
|
|
67
|
+
throw new Error(`ledger event ${index} has unexpected emitter.stream_id`);
|
|
68
|
+
}
|
|
69
|
+
const streamKey = `${runId} ${emitter.stream_id}`;
|
|
70
|
+
const expectedSeq = (nextSeqByStream.get(streamKey) ?? 0) + 1;
|
|
71
|
+
if (emitter.seq !== expectedSeq) {
|
|
72
|
+
throw new Error(`ledger event ${index} has non-contiguous seq for (run_id, stream_id)`);
|
|
73
|
+
}
|
|
74
|
+
nextSeqByStream.set(streamKey, emitter.seq);
|
|
75
|
+
const eventId = requireString(event, "event_id", index);
|
|
76
|
+
if (eventId !== createEventId(runId, emitter.seq)) {
|
|
77
|
+
throw new Error(`ledger event ${index} has invalid event_id`);
|
|
78
|
+
}
|
|
79
|
+
const principalId = requireString(event, "principal_id", index);
|
|
80
|
+
const recordedAt = requireString(event, "recorded_at", index);
|
|
81
|
+
if (Number.isNaN(Date.parse(recordedAt))) {
|
|
82
|
+
throw new Error(`ledger event ${index} has invalid recorded_at`);
|
|
83
|
+
}
|
|
84
|
+
const causeEventIds = requireStringArray(event, "cause_event_ids", index);
|
|
85
|
+
const simTime = event.sim_time;
|
|
86
|
+
if (typeof simTime !== "number" || !Number.isFinite(simTime)) {
|
|
87
|
+
throw new Error(`ledger event ${index} has invalid sim_time`);
|
|
88
|
+
}
|
|
89
|
+
const provenance = requireString(event, "provenance", index);
|
|
90
|
+
if (!provenanceValues.has(provenance)) {
|
|
91
|
+
throw new Error(`ledger event ${index} has invalid provenance`);
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
version: CAUSAL_ENVELOPE_VERSION,
|
|
95
|
+
run_id: runId,
|
|
96
|
+
event_id: eventId,
|
|
97
|
+
emitter,
|
|
98
|
+
kind: requireString(event, "kind", index),
|
|
99
|
+
principal_id: principalId,
|
|
100
|
+
recorded_at: recordedAt,
|
|
101
|
+
cause_event_ids: causeEventIds,
|
|
102
|
+
sim_time: simTime,
|
|
103
|
+
provenance: provenance,
|
|
104
|
+
actor: requireString(event, "actor", index),
|
|
105
|
+
target: requireString(event, "target", index),
|
|
106
|
+
scope: requireString(event, "scope", index),
|
|
107
|
+
payload: requirePayload(event, index)
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
export const parseCanonicalLedgerJsonl = (source, options = {}) => {
|
|
112
|
+
const lines = source.split(/\r?\n/u).filter((line) => line.length > 0);
|
|
113
|
+
const parsed = lines.map((line, index) => {
|
|
114
|
+
let value;
|
|
115
|
+
try {
|
|
116
|
+
value = JSON.parse(line);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
throw new Error(`ledger line ${index} is not valid JSON: ${error.message}`);
|
|
120
|
+
}
|
|
121
|
+
if (stableStringify(value) !== line) {
|
|
122
|
+
throw new Error(`ledger line ${index} is not canonical JSON`);
|
|
123
|
+
}
|
|
124
|
+
return value;
|
|
125
|
+
});
|
|
126
|
+
return validateCanonicalLedgerEvents(parsed, options);
|
|
127
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/moltnet/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { MoltnetMessageActor, MoltnetMessagePart, MoltnetMessageTarget, MoltnetWorldDeliveryOptions } from "./world-participant.js";
|
|
2
|
+
export type TranscriptSource = "harness-derived" | "moltnet-exported";
|
|
3
|
+
export interface MoltnetTranscriptTarget {
|
|
4
|
+
kind: "dm" | "room";
|
|
5
|
+
id: string;
|
|
6
|
+
scope?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface MoltnetExportedTranscriptMessage {
|
|
9
|
+
from?: MoltnetMessageActor;
|
|
10
|
+
id: string;
|
|
11
|
+
parts?: MoltnetMessagePart[];
|
|
12
|
+
target?: MoltnetMessageTarget;
|
|
13
|
+
}
|
|
14
|
+
export interface MoltnetConversationTranscript {
|
|
15
|
+
messages: MoltnetExportedTranscriptMessage[];
|
|
16
|
+
target: MoltnetTranscriptTarget;
|
|
17
|
+
}
|
|
18
|
+
export interface MoltnetExportedTranscript {
|
|
19
|
+
conversations: MoltnetConversationTranscript[];
|
|
20
|
+
source: "moltnet-exported";
|
|
21
|
+
version: "simfile.moltnet.transcript.v1";
|
|
22
|
+
}
|
|
23
|
+
export interface TranscriptSourceArtifact {
|
|
24
|
+
source?: TranscriptSource;
|
|
25
|
+
}
|
|
26
|
+
export interface ExportMoltnetTranscriptOptions extends MoltnetWorldDeliveryOptions {
|
|
27
|
+
limit?: number;
|
|
28
|
+
targets: readonly MoltnetTranscriptTarget[];
|
|
29
|
+
}
|
|
30
|
+
export declare const roomTranscriptTargetFromScope: (scope: string) => MoltnetTranscriptTarget;
|
|
31
|
+
export declare const extractSimfileEventIds: (transcript: MoltnetExportedTranscript) => string[];
|
|
32
|
+
export declare const requireMoltnetExportedTranscript: (artifact: TranscriptSourceArtifact) => void;
|
|
33
|
+
export declare const exportMoltnetTranscript: (options: ExportMoltnetTranscriptOptions) => Promise<MoltnetExportedTranscript>;
|
|
34
|
+
//# sourceMappingURL=transcript-export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcript-export.d.ts","sourceRoot":"","sources":["../../src/moltnet/transcript-export.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,2BAA2B,EAC5B,MAAM,wBAAwB,CAAC;AAKhC,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAEtE,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gCAAgC;IAC/C,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,oBAAoB,CAAC;CAC/B;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,gCAAgC,EAAE,CAAC;IAC7C,MAAM,EAAE,uBAAuB,CAAC;CACjC;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,6BAA6B,EAAE,CAAC;IAC/C,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,+BAA+B,CAAC;CAC1C;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,8BAA+B,SAAQ,2BAA2B;IACjF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,SAAS,uBAAuB,EAAE,CAAC;CAC7C;AAED,eAAO,MAAM,6BAA6B,GAAI,OAAO,MAAM,KAAG,uBAM7D,CAAC;AA4BF,eAAO,MAAM,sBAAsB,GACjC,YAAY,yBAAyB,KACpC,MAAM,EAYR,CAAC;AAEF,eAAO,MAAM,gCAAgC,GAC3C,UAAU,wBAAwB,KACjC,IAIF,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,SAAS,8BAA8B,KACtC,OAAO,CAAC,yBAAyB,CAmBnC,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const DEFAULT_LIMIT = 200;
|
|
2
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
3
|
+
export const roomTranscriptTargetFromScope = (scope) => {
|
|
4
|
+
const [kind, network, room] = scope.split(":");
|
|
5
|
+
if (kind !== "room" || !network || !room) {
|
|
6
|
+
throw new Error(`invalid room scope ${scope}`);
|
|
7
|
+
}
|
|
8
|
+
return { kind: "room", id: room, scope };
|
|
9
|
+
};
|
|
10
|
+
const requestHeaders = (options) => ({
|
|
11
|
+
...(options.authToken?.trim() ? { Authorization: `Bearer ${options.authToken.trim()}` } : {})
|
|
12
|
+
});
|
|
13
|
+
const readJSON = async (url, options) => {
|
|
14
|
+
const timeout = options.requestTimeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
15
|
+
const signal = timeout > 0 ? AbortSignal.timeout(timeout) : undefined;
|
|
16
|
+
const response = await (options.fetchFn ?? fetch)(url.href, {
|
|
17
|
+
method: "GET",
|
|
18
|
+
headers: requestHeaders(options),
|
|
19
|
+
...(signal ? { signal } : {})
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(`moltnet endpoint ${response.status} ${response.statusText}`);
|
|
23
|
+
}
|
|
24
|
+
return await response.json();
|
|
25
|
+
};
|
|
26
|
+
const transcriptPath = (target, limit) => {
|
|
27
|
+
const encodedId = encodeURIComponent(target.id);
|
|
28
|
+
const encodedLimit = encodeURIComponent(String(limit));
|
|
29
|
+
return target.kind === "room"
|
|
30
|
+
? `/v1/rooms/${encodedId}/messages?limit=${encodedLimit}`
|
|
31
|
+
: `/v1/dms/${encodedId}/messages?limit=${encodedLimit}`;
|
|
32
|
+
};
|
|
33
|
+
export const extractSimfileEventIds = (transcript) => {
|
|
34
|
+
const ids = new Set();
|
|
35
|
+
for (const conversation of transcript.conversations) {
|
|
36
|
+
for (const message of conversation.messages) {
|
|
37
|
+
const data = message.parts?.[0]?.data;
|
|
38
|
+
const eventId = data && typeof data === "object"
|
|
39
|
+
? data.simfile_event_id
|
|
40
|
+
: undefined;
|
|
41
|
+
if (typeof eventId === "string")
|
|
42
|
+
ids.add(eventId);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return [...ids].sort();
|
|
46
|
+
};
|
|
47
|
+
export const requireMoltnetExportedTranscript = (artifact) => {
|
|
48
|
+
if (artifact.source !== "moltnet-exported") {
|
|
49
|
+
throw new Error("live simulation acceptance requires a moltnet-exported transcript");
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
export const exportMoltnetTranscript = async (options) => {
|
|
53
|
+
const base = options.baseUrl.replace(/\/+$/u, "");
|
|
54
|
+
const limit = Math.max(1, Math.floor(options.limit ?? DEFAULT_LIMIT));
|
|
55
|
+
const conversations = [];
|
|
56
|
+
for (const target of options.targets) {
|
|
57
|
+
const page = await readJSON(new URL(`${base}${transcriptPath(target, limit)}`), options);
|
|
58
|
+
conversations.push({
|
|
59
|
+
messages: page.messages ?? [],
|
|
60
|
+
target
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
conversations,
|
|
65
|
+
source: "moltnet-exported",
|
|
66
|
+
version: "simfile.moltnet.transcript.v1"
|
|
67
|
+
};
|
|
68
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { RuntimeTraceEvent } from "../runtime/types.js";
|
|
2
|
+
export declare const WORLD_MESSAGE_EVENT_KINDS: readonly ["world.message", "world.dm", "wake.recommended"];
|
|
3
|
+
type WorldMessageEventKind = (typeof WORLD_MESSAGE_EVENT_KINDS)[number];
|
|
4
|
+
export interface MoltnetMessageActor {
|
|
5
|
+
type: "agent";
|
|
6
|
+
id: string;
|
|
7
|
+
name?: string;
|
|
8
|
+
network_id?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface MoltnetMessageTarget {
|
|
11
|
+
kind: "room" | "dm";
|
|
12
|
+
room_id?: string;
|
|
13
|
+
dm_id?: string;
|
|
14
|
+
participant_ids?: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface MoltnetMessagePart {
|
|
17
|
+
kind: "text";
|
|
18
|
+
text: string;
|
|
19
|
+
data?: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
interface MoltnetMessageOrigin {
|
|
22
|
+
network_id: string;
|
|
23
|
+
message_id: string;
|
|
24
|
+
}
|
|
25
|
+
export interface MoltnetSendMessageRequest {
|
|
26
|
+
id?: string;
|
|
27
|
+
origin?: MoltnetMessageOrigin;
|
|
28
|
+
target: MoltnetMessageTarget;
|
|
29
|
+
from: MoltnetMessageActor;
|
|
30
|
+
parts: MoltnetMessagePart[];
|
|
31
|
+
}
|
|
32
|
+
export interface MoltnetMessageAccepted {
|
|
33
|
+
message_id: string;
|
|
34
|
+
event_id: string;
|
|
35
|
+
accepted: boolean;
|
|
36
|
+
thread_created: boolean;
|
|
37
|
+
dm_created: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface MoltnetWorldDeliveryOptions {
|
|
40
|
+
actorId?: string;
|
|
41
|
+
actorName?: string;
|
|
42
|
+
authToken?: string;
|
|
43
|
+
baseUrl: string;
|
|
44
|
+
networkId?: string;
|
|
45
|
+
buildDmId?: (network: string, agentId: string, event: RuntimeTraceEvent) => string;
|
|
46
|
+
fetchFn?: typeof fetch;
|
|
47
|
+
requestTimeoutMs?: number;
|
|
48
|
+
}
|
|
49
|
+
export interface MoltnetWorldDeliveryResult {
|
|
50
|
+
eventId: string;
|
|
51
|
+
request: MoltnetSendMessageRequest;
|
|
52
|
+
response: MoltnetMessageAccepted;
|
|
53
|
+
}
|
|
54
|
+
export interface MoltnetTranscriptMessage {
|
|
55
|
+
from?: MoltnetMessageActor;
|
|
56
|
+
id: string;
|
|
57
|
+
parts?: MoltnetMessagePart[];
|
|
58
|
+
target?: MoltnetMessageTarget;
|
|
59
|
+
}
|
|
60
|
+
export interface MoltnetWorldTranscriptEntry {
|
|
61
|
+
eventId?: string;
|
|
62
|
+
kind?: string;
|
|
63
|
+
message: MoltnetTranscriptMessage;
|
|
64
|
+
target: MoltnetMessageTarget;
|
|
65
|
+
}
|
|
66
|
+
export interface MoltnetWorldTranscriptOptions extends MoltnetWorldDeliveryOptions {
|
|
67
|
+
events: readonly RuntimeTraceEvent[];
|
|
68
|
+
}
|
|
69
|
+
export declare const isWorldMessageEvent: (event: RuntimeTraceEvent) => event is RuntimeTraceEvent & {
|
|
70
|
+
kind: WorldMessageEventKind;
|
|
71
|
+
};
|
|
72
|
+
export declare const buildMoltnetMessageRequest: (event: RuntimeTraceEvent, options: MoltnetWorldDeliveryOptions) => MoltnetSendMessageRequest;
|
|
73
|
+
export declare const sendWorldEventToMoltnet: (event: RuntimeTraceEvent, options: MoltnetWorldDeliveryOptions) => Promise<MoltnetWorldDeliveryResult>;
|
|
74
|
+
export declare const sendWorldEventsToMoltnet: (events: readonly RuntimeTraceEvent[], options: MoltnetWorldDeliveryOptions) => Promise<MoltnetWorldDeliveryResult[]>;
|
|
75
|
+
export declare const readWorldTranscriptFromMoltnet: (options: MoltnetWorldTranscriptOptions) => Promise<MoltnetWorldTranscriptEntry[]>;
|
|
76
|
+
export {};
|
|
77
|
+
//# sourceMappingURL=world-participant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"world-participant.d.ts","sourceRoot":"","sources":["../../src/moltnet/world-participant.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
export const WORLD_MESSAGE_EVENT_KINDS = ["world.message", "world.dm", "wake.recommended"];
|
|
2
|
+
const WORLD_ACTOR_ID = "world";
|
|
3
|
+
const WORLD_ACTOR_NAME = "@world";
|
|
4
|
+
const WORLD_HTTP_TIMEOUT_MS = 10_000;
|
|
5
|
+
const WORLD_EVENT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
6
|
+
export const isWorldMessageEvent = (event) => WORLD_MESSAGE_EVENT_KINDS.includes(event.kind);
|
|
7
|
+
const asRoomScope = (scope) => {
|
|
8
|
+
const [kind, network, room] = scope.split(":");
|
|
9
|
+
if (kind !== "room" || !network || !room) {
|
|
10
|
+
throw new Error(`invalid room target scope ${scope}`);
|
|
11
|
+
}
|
|
12
|
+
return { network, room };
|
|
13
|
+
};
|
|
14
|
+
const asAgentScope = (scope) => {
|
|
15
|
+
const [kind, agent] = scope.split(":");
|
|
16
|
+
if (kind !== "agent" || !agent) {
|
|
17
|
+
throw new Error(`invalid agent target scope ${scope}`);
|
|
18
|
+
}
|
|
19
|
+
return agent;
|
|
20
|
+
};
|
|
21
|
+
const defaultActor = (networkId) => ({
|
|
22
|
+
type: "agent",
|
|
23
|
+
id: WORLD_ACTOR_ID,
|
|
24
|
+
name: WORLD_ACTOR_NAME,
|
|
25
|
+
...(networkId ? { network_id: networkId } : {})
|
|
26
|
+
});
|
|
27
|
+
const defaultDmId = (network, agentId, event) => `world-${network}-${agentId}`;
|
|
28
|
+
const deriveActorNetworkId = (event, options) => {
|
|
29
|
+
if (options.networkId)
|
|
30
|
+
return options.networkId;
|
|
31
|
+
if (event.kind === "world.message" || event.kind === "wake.recommended") {
|
|
32
|
+
return asRoomScope(event.target).network;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
};
|
|
36
|
+
const requestTextFromEvent = (event) => {
|
|
37
|
+
const payload = typeof event.payload === "object" && event.payload !== null && !Array.isArray(event.payload)
|
|
38
|
+
? event.payload
|
|
39
|
+
: {};
|
|
40
|
+
if (typeof payload.content === "string" && payload.content.length > 0) {
|
|
41
|
+
return payload.content;
|
|
42
|
+
}
|
|
43
|
+
if (typeof payload.reason === "string" && payload.reason.length > 0) {
|
|
44
|
+
return `${event.kind}: ${payload.reason}`;
|
|
45
|
+
}
|
|
46
|
+
return `${event.kind}: ${event.target}`;
|
|
47
|
+
};
|
|
48
|
+
const metadataFromEvent = (event) => ({
|
|
49
|
+
simfile_event_id: event.event_id,
|
|
50
|
+
simfile_event_kind: event.kind,
|
|
51
|
+
simfile_rule_id: event.actor
|
|
52
|
+
});
|
|
53
|
+
const requestHeaders = (options) => ({
|
|
54
|
+
"Content-Type": "application/json",
|
|
55
|
+
...(options.authToken?.trim() ? { Authorization: `Bearer ${options.authToken.trim()}` } : {})
|
|
56
|
+
});
|
|
57
|
+
const requestFromWorldEvent = (event, options) => {
|
|
58
|
+
const actorNetwork = deriveActorNetworkId(event, options);
|
|
59
|
+
const metadata = metadataFromEvent(event);
|
|
60
|
+
const messageText = requestTextFromEvent(event);
|
|
61
|
+
if (event.kind === "world.dm") {
|
|
62
|
+
const actorId = options.actorId?.trim() || WORLD_ACTOR_ID;
|
|
63
|
+
const network = options.networkId ?? actorNetwork;
|
|
64
|
+
if (!network) {
|
|
65
|
+
throw new Error("networkId is required for world.dm delivery");
|
|
66
|
+
}
|
|
67
|
+
const toAgent = asAgentScope(event.target);
|
|
68
|
+
const dmIdFactory = options.buildDmId ?? defaultDmId;
|
|
69
|
+
const dmId = dmIdFactory(network, toAgent, event);
|
|
70
|
+
return {
|
|
71
|
+
id: WORLD_EVENT_ID_PATTERN.test(event.event_id) ? event.event_id : undefined,
|
|
72
|
+
origin: { network_id: network, message_id: event.event_id },
|
|
73
|
+
from: {
|
|
74
|
+
...defaultActor(network),
|
|
75
|
+
id: actorId
|
|
76
|
+
},
|
|
77
|
+
target: {
|
|
78
|
+
kind: "dm",
|
|
79
|
+
dm_id: dmId,
|
|
80
|
+
participant_ids: [actorId, toAgent]
|
|
81
|
+
},
|
|
82
|
+
parts: [{
|
|
83
|
+
kind: "text",
|
|
84
|
+
text: messageText,
|
|
85
|
+
data: metadata
|
|
86
|
+
}]
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const roomScope = asRoomScope(event.target);
|
|
90
|
+
const actorId = options.actorId?.trim() || WORLD_ACTOR_ID;
|
|
91
|
+
return {
|
|
92
|
+
id: WORLD_EVENT_ID_PATTERN.test(event.event_id) ? event.event_id : undefined,
|
|
93
|
+
origin: { network_id: roomScope.network, message_id: event.event_id },
|
|
94
|
+
from: {
|
|
95
|
+
...defaultActor(roomScope.network),
|
|
96
|
+
id: actorId
|
|
97
|
+
},
|
|
98
|
+
target: {
|
|
99
|
+
kind: "room",
|
|
100
|
+
room_id: roomScope.room
|
|
101
|
+
},
|
|
102
|
+
parts: [{
|
|
103
|
+
kind: "text",
|
|
104
|
+
text: messageText,
|
|
105
|
+
data: metadata
|
|
106
|
+
}]
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
const parseMoltnetAccepted = async (response) => {
|
|
110
|
+
const body = await response.text();
|
|
111
|
+
let payload;
|
|
112
|
+
try {
|
|
113
|
+
payload = JSON.parse(body);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
throw new Error(`moltnet response decode failed: ${error.message}`);
|
|
117
|
+
}
|
|
118
|
+
const message = payload;
|
|
119
|
+
if (typeof message !== "object" ||
|
|
120
|
+
message === null ||
|
|
121
|
+
typeof message.message_id !== "string" ||
|
|
122
|
+
typeof message.event_id !== "string" ||
|
|
123
|
+
typeof message.accepted !== "boolean" ||
|
|
124
|
+
typeof message.thread_created !== "boolean" ||
|
|
125
|
+
typeof message.dm_created !== "boolean") {
|
|
126
|
+
throw new Error("moltnet response missing expected fields");
|
|
127
|
+
}
|
|
128
|
+
return message;
|
|
129
|
+
};
|
|
130
|
+
export const buildMoltnetMessageRequest = (event, options) => {
|
|
131
|
+
if (!isWorldMessageEvent(event)) {
|
|
132
|
+
throw new Error(`unsupported event kind ${event.kind}`);
|
|
133
|
+
}
|
|
134
|
+
return requestFromWorldEvent(event, options);
|
|
135
|
+
};
|
|
136
|
+
export const sendWorldEventToMoltnet = async (event, options) => {
|
|
137
|
+
const request = buildMoltnetMessageRequest(event, options);
|
|
138
|
+
const requestTarget = new URL(`${options.baseUrl.replace(/\/+$/u, "")}/v1/messages`);
|
|
139
|
+
const timeout = options.requestTimeoutMs ?? WORLD_HTTP_TIMEOUT_MS;
|
|
140
|
+
const signal = timeout > 0 ? AbortSignal.timeout(timeout) : undefined;
|
|
141
|
+
const fetcher = options.fetchFn ?? fetch;
|
|
142
|
+
const response = await fetcher(requestTarget.href, {
|
|
143
|
+
method: "POST",
|
|
144
|
+
headers: requestHeaders(options),
|
|
145
|
+
body: JSON.stringify(request),
|
|
146
|
+
...(signal ? { signal } : {})
|
|
147
|
+
});
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
throw new Error(`moltnet endpoint ${response.status} ${response.statusText}`);
|
|
150
|
+
}
|
|
151
|
+
const accepted = await parseMoltnetAccepted(response);
|
|
152
|
+
return { eventId: event.event_id, request, response: accepted };
|
|
153
|
+
};
|
|
154
|
+
export const sendWorldEventsToMoltnet = async (events, options) => {
|
|
155
|
+
const results = [];
|
|
156
|
+
for (const event of events) {
|
|
157
|
+
if (!isWorldMessageEvent(event))
|
|
158
|
+
continue;
|
|
159
|
+
results.push(await sendWorldEventToMoltnet(event, options));
|
|
160
|
+
}
|
|
161
|
+
return results;
|
|
162
|
+
};
|
|
163
|
+
const readJSON = async (url, options) => {
|
|
164
|
+
const timeout = options.requestTimeoutMs ?? WORLD_HTTP_TIMEOUT_MS;
|
|
165
|
+
const signal = timeout > 0 ? AbortSignal.timeout(timeout) : undefined;
|
|
166
|
+
const response = await (options.fetchFn ?? fetch)(url.href, {
|
|
167
|
+
method: "GET",
|
|
168
|
+
headers: requestHeaders(options),
|
|
169
|
+
...(signal ? { signal } : {})
|
|
170
|
+
});
|
|
171
|
+
if (!response.ok) {
|
|
172
|
+
throw new Error(`moltnet endpoint ${response.status} ${response.statusText}`);
|
|
173
|
+
}
|
|
174
|
+
return await response.json();
|
|
175
|
+
};
|
|
176
|
+
const transcriptTargets = (events, options) => {
|
|
177
|
+
const targets = new Map();
|
|
178
|
+
for (const event of events) {
|
|
179
|
+
if (!isWorldMessageEvent(event))
|
|
180
|
+
continue;
|
|
181
|
+
const request = buildMoltnetMessageRequest(event, options);
|
|
182
|
+
const target = request.target;
|
|
183
|
+
if (target.kind === "room" && target.room_id) {
|
|
184
|
+
targets.set(`room:${target.room_id}`, target);
|
|
185
|
+
}
|
|
186
|
+
if (target.kind === "dm" && target.dm_id) {
|
|
187
|
+
targets.set(`dm:${target.dm_id}`, target);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return [...targets.values()];
|
|
191
|
+
};
|
|
192
|
+
const firstPartMetadata = (message) => {
|
|
193
|
+
const data = message.parts?.[0]?.data;
|
|
194
|
+
return data && typeof data === "object" ? data : undefined;
|
|
195
|
+
};
|
|
196
|
+
export const readWorldTranscriptFromMoltnet = async (options) => {
|
|
197
|
+
const base = options.baseUrl.replace(/\/+$/u, "");
|
|
198
|
+
const entries = [];
|
|
199
|
+
for (const target of transcriptTargets(options.events, options)) {
|
|
200
|
+
const path = target.kind === "room" && target.room_id
|
|
201
|
+
? `/v1/rooms/${encodeURIComponent(target.room_id)}/messages?limit=200`
|
|
202
|
+
: target.kind === "dm" && target.dm_id
|
|
203
|
+
? `/v1/dms/${encodeURIComponent(target.dm_id)}/messages?limit=200`
|
|
204
|
+
: undefined;
|
|
205
|
+
if (!path)
|
|
206
|
+
continue;
|
|
207
|
+
const page = await readJSON(new URL(`${base}${path}`), options);
|
|
208
|
+
for (const message of page.messages ?? []) {
|
|
209
|
+
const data = firstPartMetadata(message);
|
|
210
|
+
if (typeof data?.simfile_event_id !== "string")
|
|
211
|
+
continue;
|
|
212
|
+
entries.push({
|
|
213
|
+
eventId: data.simfile_event_id,
|
|
214
|
+
kind: typeof data.simfile_event_kind === "string" ? data.simfile_event_kind : undefined,
|
|
215
|
+
message,
|
|
216
|
+
target
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return entries;
|
|
221
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { RunManifestArtifactEntry } from "./manifest.js";
|
|
2
|
+
export interface ArtifactIntegrityCheck {
|
|
3
|
+
path: string;
|
|
4
|
+
expectedSha256: string;
|
|
5
|
+
actualSha256: string | null;
|
|
6
|
+
ok: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Verifies every manifest-declared artifact's sha256 against the file on
|
|
10
|
+
* disk. A mismatch (or a missing file) is reported as a failed check, never
|
|
11
|
+
* silently repaired or stitched over — the caller decides what to do with a
|
|
12
|
+
* failed integrity check (contracts.md: "missing links are reported, not
|
|
13
|
+
* synthesized" applies just as much to artifact bytes as to causal edges).
|
|
14
|
+
*/
|
|
15
|
+
export declare const verifyManifestArtifacts: (runDir: string, artifacts: readonly RunManifestArtifactEntry[]) => Promise<ArtifactIntegrityCheck[]>;
|
|
16
|
+
//# sourceMappingURL=artifacts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../src/observe/artifacts.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAE9D,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,EAAE,EAAE,OAAO,CAAC;CACb;AAID;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,GAClC,QAAQ,MAAM,EACd,WAAW,SAAS,wBAAwB,EAAE,KAC7C,OAAO,CAAC,sBAAsB,EAAE,CAkBlC,CAAC"}
|