@plures/praxis 1.2.12 → 1.2.41

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 (85) hide show
  1. package/README.md +63 -0
  2. package/dist/browser/{chunk-VOMLVI6V.js → chunk-BBP2F7TT.js} +70 -1
  3. package/dist/browser/{chunk-K377RW4V.js → chunk-FCEH7WMH.js} +1 -1
  4. package/dist/browser/{engine-YJZV4SLD.js → engine-65QDGCAN.js} +1 -1
  5. package/dist/browser/index.d.ts +104 -2
  6. package/dist/browser/index.js +181 -5
  7. package/dist/browser/integrations/svelte.d.ts +2 -2
  8. package/dist/browser/integrations/svelte.js +2 -2
  9. package/dist/browser/{reactive-engine.svelte-9aS0kTa8.d.ts → reactive-engine.svelte-Cqd8Mod2.d.ts} +56 -1
  10. package/dist/node/{chunk-PRPQO6R5.js → chunk-32YFEEML.js} +1 -1
  11. package/dist/node/{chunk-VOMLVI6V.js → chunk-BBP2F7TT.js} +70 -1
  12. package/dist/node/{chunk-5RH7UAQC.js → chunk-PTH6MD6P.js} +1 -0
  13. package/dist/node/cli/index.cjs +1553 -839
  14. package/dist/node/cli/index.js +39 -2
  15. package/dist/node/cloud/index.d.cts +1 -1
  16. package/dist/node/cloud/index.d.ts +1 -1
  17. package/dist/node/components/index.d.cts +2 -2
  18. package/dist/node/components/index.d.ts +2 -2
  19. package/dist/node/conversations-KQBXTP3N.js +596 -0
  20. package/dist/node/{engine-2DQBKBJC.js → engine-7CXQV6RC.js} +1 -1
  21. package/dist/node/index.cjs +408 -3
  22. package/dist/node/index.d.cts +308 -7
  23. package/dist/node/index.d.ts +308 -7
  24. package/dist/node/index.js +336 -6
  25. package/dist/node/integrations/svelte.cjs +70 -1
  26. package/dist/node/integrations/svelte.d.cts +3 -3
  27. package/dist/node/integrations/svelte.d.ts +3 -3
  28. package/dist/node/integrations/svelte.js +2 -2
  29. package/dist/node/{protocol-Qek7ebBl.d.ts → protocol-BocKczNv.d.cts} +1 -1
  30. package/dist/node/{protocol-Qek7ebBl.d.cts → protocol-BocKczNv.d.ts} +1 -1
  31. package/dist/node/{reactive-engine.svelte-CRNqHlbv.d.ts → reactive-engine.svelte-CGe8SpVE.d.cts} +57 -2
  32. package/dist/node/{reactive-engine.svelte-BFIZfawz.d.cts → reactive-engine.svelte-D-xTDxT5.d.ts} +57 -2
  33. package/dist/node/{terminal-adapter-B-UK_Vdz.d.ts → terminal-adapter-CvIvgTo4.d.ts} +1 -1
  34. package/dist/node/{terminal-adapter-BQSIF5bf.d.cts → terminal-adapter-Db-snPJ3.d.cts} +1 -1
  35. package/dist/node/{validate-CNHUULQE.js → validate-EN3M4FUR.js} +1 -1
  36. package/dist/node/{verify-KLJRXVJS.js → verify-7VZRP2WS.js} +2 -2
  37. package/docs/BOT_UPDATE_POLICY.md +125 -0
  38. package/docs/DOGFOODING_CHECKLIST.md +254 -0
  39. package/docs/DOGFOODING_INDEX.md +169 -0
  40. package/docs/DOGFOODING_QUICK_START.md +140 -0
  41. package/docs/KNO_ENG_EXTRACTION_PLAN.md +577 -0
  42. package/docs/PLURES_TOOLS_INVENTORY.md +170 -0
  43. package/docs/README.md +12 -0
  44. package/docs/TESTING_BOT_WORKFLOWS.md +154 -0
  45. package/docs/conversations/INTEGRATION_POINTS.md +719 -0
  46. package/docs/conversations/README.md +168 -0
  47. package/docs/core/extending-praxis-core.md +604 -0
  48. package/docs/core/praxis-core-api.md +385 -0
  49. package/docs/decision-ledger/contract-index.json +2 -2
  50. package/docs/decision-ledger/decisions/2026-02-01-monorepo-organization.md +130 -0
  51. package/docs/examples/DOGFOODING_WORKFLOW_EXAMPLE.md +295 -0
  52. package/docs/examples/README.md +41 -0
  53. package/docs/workflows/pr-overlap-guard.md +50 -0
  54. package/package.json +7 -2
  55. package/src/__tests__/chronicle.test.ts +512 -0
  56. package/src/__tests__/conversations.test.ts +312 -0
  57. package/src/__tests__/edge-cases.test.ts +1 -1
  58. package/src/__tests__/engine-dx.test.ts +355 -0
  59. package/src/cli/commands/conversations.ts +252 -0
  60. package/src/cli/index.ts +73 -0
  61. package/src/conversations/README.md +230 -0
  62. package/src/conversations/candidate.schema.json +123 -0
  63. package/src/conversations/candidates.ts +114 -0
  64. package/src/conversations/capture.ts +56 -0
  65. package/src/conversations/classify.ts +110 -0
  66. package/src/conversations/conversation.schema.json +106 -0
  67. package/src/conversations/emitters/fs.ts +65 -0
  68. package/src/conversations/emitters/github.ts +115 -0
  69. package/src/conversations/gate.ts +102 -0
  70. package/src/conversations/index.ts +28 -0
  71. package/src/conversations/normalize.ts +51 -0
  72. package/src/conversations/redact.ts +57 -0
  73. package/src/conversations/types.ts +96 -0
  74. package/src/core/chronicle/chronicle.ts +227 -0
  75. package/src/core/chronicle/context.ts +80 -0
  76. package/src/core/chronicle/index.ts +53 -0
  77. package/src/core/chronicle/mcp.ts +135 -0
  78. package/src/core/chronicle/types.ts +61 -0
  79. package/src/core/engine.ts +99 -1
  80. package/src/core/pluresdb/index.ts +22 -0
  81. package/src/core/pluresdb/store.ts +162 -5
  82. package/src/core/rules.ts +12 -0
  83. package/src/dsl/index.ts +6 -0
  84. package/src/index.ts +18 -0
  85. package/src/integrations/pluresdb.ts +22 -0
@@ -21,7 +21,7 @@ import {
21
21
  formatValidationReportJSON,
22
22
  formatValidationReportSARIF,
23
23
  validateContracts
24
- } from "./chunk-5RH7UAQC.js";
24
+ } from "./chunk-PTH6MD6P.js";
25
25
  import {
26
26
  defineContract,
27
27
  getContract,
@@ -50,7 +50,7 @@ import {
50
50
  import {
51
51
  ReactiveLogicEngine,
52
52
  createReactiveEngine
53
- } from "./chunk-PRPQO6R5.js";
53
+ } from "./chunk-32YFEEML.js";
54
54
  import {
55
55
  PraxisRegistry
56
56
  } from "./chunk-R2PSBPKQ.js";
@@ -79,7 +79,7 @@ import {
79
79
  LogicEngine,
80
80
  PRAXIS_PROTOCOL_VERSION,
81
81
  createPraxisEngine
82
- } from "./chunk-VOMLVI6V.js";
82
+ } from "./chunk-BBP2F7TT.js";
83
83
  import "./chunk-QGM4M3NI.js";
84
84
 
85
85
  // src/core/reactive-engine.ts
@@ -622,6 +622,53 @@ function createIntrospector(registry) {
622
622
  return new RegistryIntrospector(registry);
623
623
  }
624
624
 
625
+ // src/core/chronicle/context.ts
626
+ var ChronicleContext = class {
627
+ static _stack = [];
628
+ /**
629
+ * Get the current active span, if any.
630
+ */
631
+ static get current() {
632
+ return this._stack[this._stack.length - 1];
633
+ }
634
+ /**
635
+ * Run a synchronous function within a causal span.
636
+ * The span is automatically popped when the function returns.
637
+ */
638
+ static run(span, fn) {
639
+ this._stack.push(span);
640
+ try {
641
+ return fn();
642
+ } finally {
643
+ this._stack.pop();
644
+ }
645
+ }
646
+ /**
647
+ * Run an async function within a causal span.
648
+ * The span is popped after the promise settles.
649
+ */
650
+ static async runAsync(span, fn) {
651
+ this._stack.push(span);
652
+ try {
653
+ return await fn();
654
+ } finally {
655
+ this._stack.pop();
656
+ }
657
+ }
658
+ /**
659
+ * Create a child span that inherits the current contextId.
660
+ *
661
+ * @param spanId ID for the new span
662
+ * @returns A new ChronicleSpan with the current contextId
663
+ */
664
+ static childSpan(spanId) {
665
+ return {
666
+ spanId,
667
+ contextId: this.current?.contextId
668
+ };
669
+ }
670
+ };
671
+
625
672
  // src/core/pluresdb/store.ts
626
673
  var PRAXIS_PATHS = {
627
674
  /** Base path for all Praxis data */
@@ -657,12 +704,32 @@ var PraxisDBStore = class {
657
704
  subscriptions = [];
658
705
  factWatchers = /* @__PURE__ */ new Map();
659
706
  onRuleError;
707
+ chronicle;
660
708
  constructor(options) {
661
709
  this.db = options.db;
662
710
  this.registry = options.registry;
663
711
  this.context = options.initialContext ?? {};
664
712
  this.onRuleError = options.onRuleError ?? defaultErrorHandler;
665
713
  }
714
+ /**
715
+ * Attach a Chronicle observer to this store.
716
+ *
717
+ * Every subsequent `storeFact` and `appendEvent` call will be recorded as a
718
+ * causal graph node in PluresDB, enabling full observability for free.
719
+ *
720
+ * @param chronicle Chronicle implementation to attach
721
+ * @returns `this` for fluent chaining
722
+ *
723
+ * @example
724
+ * ```typescript
725
+ * const store = createPraxisDBStore(db, registry)
726
+ * .withChronicle(createChronicle(db));
727
+ * ```
728
+ */
729
+ withChronicle(chronicle) {
730
+ this.chronicle = chronicle;
731
+ return this;
732
+ }
666
733
  /**
667
734
  * Store a fact in PluresDB
668
735
  *
@@ -677,7 +744,31 @@ var PraxisDBStore = class {
677
744
  if (!constraintResult.valid) {
678
745
  throw new Error(`Constraint violation: ${constraintResult.errors.join(", ")}`);
679
746
  }
747
+ let before;
748
+ if (this.chronicle) {
749
+ const payload = fact.payload;
750
+ const id = payload?.id;
751
+ if (id) {
752
+ before = await this.getFact(fact.tag, id);
753
+ }
754
+ }
680
755
  await this.persistFact(fact);
756
+ if (this.chronicle) {
757
+ const payload = fact.payload;
758
+ const id = payload?.id ?? "";
759
+ const span = ChronicleContext.current;
760
+ try {
761
+ await this.chronicle.record({
762
+ path: getFactPath(fact.tag, id),
763
+ before,
764
+ after: fact,
765
+ cause: span?.spanId,
766
+ context: span?.contextId,
767
+ metadata: { factTag: fact.tag, operation: "storeFact" }
768
+ });
769
+ } catch {
770
+ }
771
+ }
681
772
  await this.triggerRules([fact]);
682
773
  }
683
774
  /**
@@ -691,7 +782,31 @@ var PraxisDBStore = class {
691
782
  throw new Error(`Constraint violation: ${constraintResult.errors.join(", ")}`);
692
783
  }
693
784
  for (const fact of facts) {
785
+ let before;
786
+ if (this.chronicle) {
787
+ const payload = fact.payload;
788
+ const id = payload?.id;
789
+ if (id) {
790
+ before = await this.getFact(fact.tag, id);
791
+ }
792
+ }
694
793
  await this.persistFact(fact);
794
+ if (this.chronicle) {
795
+ const payload = fact.payload;
796
+ const id = payload?.id ?? "";
797
+ const span = ChronicleContext.current;
798
+ try {
799
+ await this.chronicle.record({
800
+ path: getFactPath(fact.tag, id),
801
+ before,
802
+ after: fact,
803
+ cause: span?.spanId,
804
+ context: span?.contextId,
805
+ metadata: { factTag: fact.tag, operation: "storeFacts" }
806
+ });
807
+ } catch {
808
+ }
809
+ }
695
810
  }
696
811
  await this.triggerRules(facts);
697
812
  }
@@ -733,7 +848,29 @@ var PraxisDBStore = class {
733
848
  };
734
849
  const newEvents = [...existingEvents, entry];
735
850
  await this.db.set(path, newEvents);
736
- await this.triggerRulesForEvents([event]);
851
+ let eventNodeId;
852
+ if (this.chronicle) {
853
+ const span = ChronicleContext.current;
854
+ try {
855
+ const node = await this.chronicle.record({
856
+ path,
857
+ before: existingEvents.length > 0 ? existingEvents[existingEvents.length - 1] : void 0,
858
+ after: entry,
859
+ cause: span?.spanId,
860
+ context: span?.contextId,
861
+ metadata: { eventTag: event.tag, sequence: String(entry.sequence), operation: "appendEvent" }
862
+ });
863
+ eventNodeId = node.id;
864
+ } catch {
865
+ }
866
+ }
867
+ const outerSpan = ChronicleContext.current;
868
+ const ruleSpan = eventNodeId ? { spanId: eventNodeId, contextId: outerSpan?.contextId } : outerSpan;
869
+ if (ruleSpan && this.chronicle) {
870
+ await ChronicleContext.runAsync(ruleSpan, () => this.triggerRulesForEvents([event]));
871
+ } else {
872
+ await this.triggerRulesForEvents([event]);
873
+ }
737
874
  }
738
875
  /**
739
876
  * Append multiple events to their respective streams
@@ -746,6 +883,7 @@ var PraxisDBStore = class {
746
883
  const existing = eventsByTag.get(event.tag) ?? [];
747
884
  eventsByTag.set(event.tag, [...existing, event]);
748
885
  }
886
+ let lastEventNodeId;
749
887
  for (const [tag, tagEvents] of eventsByTag) {
750
888
  const path = getEventPath(tag);
751
889
  const existingEvents = await this.db.get(path) ?? [];
@@ -756,8 +894,30 @@ var PraxisDBStore = class {
756
894
  sequence: sequence++
757
895
  }));
758
896
  await this.db.set(path, [...existingEvents, ...newEntries]);
897
+ if (this.chronicle) {
898
+ const span = ChronicleContext.current;
899
+ for (const entry of newEntries) {
900
+ try {
901
+ const node = await this.chronicle.record({
902
+ path,
903
+ after: entry,
904
+ cause: span?.spanId,
905
+ context: span?.contextId,
906
+ metadata: { eventTag: tag, sequence: String(entry.sequence), operation: "appendEvents" }
907
+ });
908
+ lastEventNodeId = node.id;
909
+ } catch {
910
+ }
911
+ }
912
+ }
913
+ }
914
+ const outerSpan = ChronicleContext.current;
915
+ const ruleSpan = lastEventNodeId ? { spanId: lastEventNodeId, contextId: outerSpan?.contextId } : outerSpan;
916
+ if (ruleSpan && this.chronicle) {
917
+ await ChronicleContext.runAsync(ruleSpan, () => this.triggerRulesForEvents(events));
918
+ } else {
919
+ await this.triggerRulesForEvents(events);
759
920
  }
760
- await this.triggerRulesForEvents(events);
761
921
  }
762
922
  /**
763
923
  * Get events from a stream
@@ -870,6 +1030,21 @@ var PraxisDBStore = class {
870
1030
  if (constraintResult.valid) {
871
1031
  for (const fact of derivedFacts) {
872
1032
  await this.persistFact(fact);
1033
+ if (this.chronicle) {
1034
+ const payload = fact.payload;
1035
+ const id = payload?.id ?? "";
1036
+ const span = ChronicleContext.current;
1037
+ try {
1038
+ await this.chronicle.record({
1039
+ path: getFactPath(fact.tag, id),
1040
+ after: fact,
1041
+ cause: span?.spanId,
1042
+ context: span?.contextId,
1043
+ metadata: { factTag: fact.tag, operation: "derivedFact" }
1044
+ });
1045
+ } catch {
1046
+ }
1047
+ }
873
1048
  }
874
1049
  }
875
1050
  }
@@ -989,6 +1164,156 @@ function createSchemaRegistry(db) {
989
1164
  return new PraxisSchemaRegistry(db);
990
1165
  }
991
1166
 
1167
+ // src/core/chronicle/chronicle.ts
1168
+ var CHRONICLE_PATHS = {
1169
+ BASE: "/_praxis/chronos",
1170
+ NODES: "/_praxis/chronos/nodes",
1171
+ EDGES_OUT: "/_praxis/chronos/edges/out",
1172
+ EDGES_IN: "/_praxis/chronos/edges/in",
1173
+ CONTEXT: "/_praxis/chronos/context",
1174
+ INDEX: "/_praxis/chronos/index"
1175
+ };
1176
+ var _nodeCounter = 0;
1177
+ var PluresDbChronicle = class {
1178
+ db;
1179
+ constructor(db) {
1180
+ this.db = db;
1181
+ }
1182
+ async record(event) {
1183
+ const timestamp = Date.now();
1184
+ const id = `chronos:${timestamp}-${++_nodeCounter}`;
1185
+ const node = { id, timestamp, event };
1186
+ await this.db.set(`${CHRONICLE_PATHS.NODES}/${id}`, node);
1187
+ const index = await this.db.get(CHRONICLE_PATHS.INDEX) ?? [];
1188
+ await this.db.set(CHRONICLE_PATHS.INDEX, [...index, id]);
1189
+ if (event.cause) {
1190
+ await this.addEdge(event.cause, id, "causes");
1191
+ }
1192
+ if (event.context) {
1193
+ const contextPath = `${CHRONICLE_PATHS.CONTEXT}/${event.context}`;
1194
+ const contextNodes = await this.db.get(contextPath) ?? [];
1195
+ if (contextNodes.length > 0) {
1196
+ const prevId = contextNodes[contextNodes.length - 1];
1197
+ await this.addEdge(prevId, id, "follows");
1198
+ }
1199
+ await this.db.set(contextPath, [...contextNodes, id]);
1200
+ }
1201
+ return node;
1202
+ }
1203
+ async trace(nodeId, direction, maxDepth) {
1204
+ const visited = /* @__PURE__ */ new Set();
1205
+ const result = [];
1206
+ await this._traceRecursive(nodeId, direction, maxDepth, 0, visited, result);
1207
+ return result;
1208
+ }
1209
+ async range(start, end) {
1210
+ const index = await this.db.get(CHRONICLE_PATHS.INDEX) ?? [];
1211
+ const result = [];
1212
+ for (const id of index) {
1213
+ const node = await this.db.get(`${CHRONICLE_PATHS.NODES}/${id}`);
1214
+ if (node && node.timestamp >= start && node.timestamp <= end) {
1215
+ result.push(node);
1216
+ }
1217
+ }
1218
+ return result;
1219
+ }
1220
+ async subgraph(contextId) {
1221
+ const contextPath = `${CHRONICLE_PATHS.CONTEXT}/${contextId}`;
1222
+ const nodeIds = await this.db.get(contextPath) ?? [];
1223
+ const result = [];
1224
+ for (const id of nodeIds) {
1225
+ const node = await this.db.get(`${CHRONICLE_PATHS.NODES}/${id}`);
1226
+ if (node) {
1227
+ result.push(node);
1228
+ }
1229
+ }
1230
+ return result;
1231
+ }
1232
+ // ── Internal helpers ──────────────────────────────────────────────────────
1233
+ async addEdge(from, to, type) {
1234
+ const edge = { from, to, type };
1235
+ const outPath = `${CHRONICLE_PATHS.EDGES_OUT}/${from}`;
1236
+ const outEdges = await this.db.get(outPath) ?? [];
1237
+ await this.db.set(outPath, [...outEdges, edge]);
1238
+ const inPath = `${CHRONICLE_PATHS.EDGES_IN}/${to}`;
1239
+ const inEdges = await this.db.get(inPath) ?? [];
1240
+ await this.db.set(inPath, [...inEdges, edge]);
1241
+ }
1242
+ async _traceRecursive(nodeId, direction, maxDepth, depth, visited, result) {
1243
+ if (depth > maxDepth || visited.has(nodeId)) {
1244
+ return;
1245
+ }
1246
+ visited.add(nodeId);
1247
+ const node = await this.db.get(`${CHRONICLE_PATHS.NODES}/${nodeId}`);
1248
+ if (node) {
1249
+ result.push(node);
1250
+ }
1251
+ if (direction === "backward" || direction === "both") {
1252
+ const inEdges = await this.db.get(`${CHRONICLE_PATHS.EDGES_IN}/${nodeId}`) ?? [];
1253
+ for (const edge of inEdges) {
1254
+ await this._traceRecursive(edge.from, direction, maxDepth, depth + 1, visited, result);
1255
+ }
1256
+ }
1257
+ if (direction === "forward" || direction === "both") {
1258
+ const outEdges = await this.db.get(`${CHRONICLE_PATHS.EDGES_OUT}/${nodeId}`) ?? [];
1259
+ for (const edge of outEdges) {
1260
+ await this._traceRecursive(edge.to, direction, maxDepth, depth + 1, visited, result);
1261
+ }
1262
+ }
1263
+ }
1264
+ };
1265
+ function createChronicle(db) {
1266
+ return new PluresDbChronicle(db);
1267
+ }
1268
+
1269
+ // src/core/chronicle/mcp.ts
1270
+ function createChronosMcpTools(chronicle) {
1271
+ return {
1272
+ async trace(params) {
1273
+ try {
1274
+ const nodes = await chronicle.trace(
1275
+ params.nodeId,
1276
+ params.direction ?? "backward",
1277
+ params.maxDepth ?? 10
1278
+ );
1279
+ return { success: true, data: nodes };
1280
+ } catch (error) {
1281
+ return {
1282
+ success: false,
1283
+ error: error instanceof Error ? error.message : String(error)
1284
+ };
1285
+ }
1286
+ },
1287
+ async search(params) {
1288
+ try {
1289
+ const query = params.query.toLowerCase();
1290
+ let candidates;
1291
+ if (params.contextId) {
1292
+ candidates = await chronicle.subgraph(params.contextId);
1293
+ } else {
1294
+ candidates = await chronicle.range(params.since ?? 0, params.until ?? Date.now());
1295
+ }
1296
+ const filtered = candidates.filter((node) => {
1297
+ const inPath = node.event.path.toLowerCase().includes(query);
1298
+ const inMeta = Object.values(node.event.metadata).some(
1299
+ (v) => v.toLowerCase().includes(query)
1300
+ );
1301
+ const inAfter = JSON.stringify(node.event.after ?? "").toLowerCase().includes(query);
1302
+ const inBefore = JSON.stringify(node.event.before ?? "").toLowerCase().includes(query);
1303
+ return inPath || inMeta || inAfter || inBefore;
1304
+ });
1305
+ const limited = params.limit !== void 0 ? filtered.slice(0, params.limit) : filtered;
1306
+ return { success: true, data: limited };
1307
+ } catch (error) {
1308
+ return {
1309
+ success: false,
1310
+ error: error instanceof Error ? error.message : String(error)
1311
+ };
1312
+ }
1313
+ }
1314
+ };
1315
+ }
1316
+
992
1317
  // src/integrations/pluresdb.ts
993
1318
  function createPluresDBAdapter(options) {
994
1319
  const store = createPraxisDBStore(options.db, options.registry, options.initialContext);
@@ -1443,7 +1768,7 @@ function generateTauriConfig(config) {
1443
1768
 
1444
1769
  // src/integrations/unified.ts
1445
1770
  async function createUnifiedApp(config) {
1446
- const { createPraxisEngine: createPraxisEngine2 } = await import("./engine-2DQBKBJC.js");
1771
+ const { createPraxisEngine: createPraxisEngine2 } = await import("./engine-7CXQV6RC.js");
1447
1772
  const { createInMemoryDB: createInMemoryDB2 } = await import("./adapter-75ISSMWD.js");
1448
1773
  const db = config.db || createInMemoryDB2();
1449
1774
  const pluresdb = createPluresDBAdapter({
@@ -1576,6 +1901,8 @@ export {
1576
1901
  AcknowledgeContractGap,
1577
1902
  ActorManager,
1578
1903
  BehaviorLedger,
1904
+ CHRONICLE_PATHS,
1905
+ ChronicleContext,
1579
1906
  ContractAdded,
1580
1907
  ContractGapAcknowledged,
1581
1908
  ContractMissing,
@@ -1588,6 +1915,7 @@ export {
1588
1915
  PRAXIS_PROTOCOL_VERSION,
1589
1916
  PluresDBGenerator,
1590
1917
  PluresDBPraxisAdapter,
1918
+ PluresDbChronicle,
1591
1919
  PraxisDBStore,
1592
1920
  PraxisRegistry,
1593
1921
  PraxisSchemaRegistry,
@@ -1605,6 +1933,8 @@ export {
1605
1933
  canvasToYaml,
1606
1934
  createBehaviorLedger,
1607
1935
  createCanvasEditor,
1936
+ createChronicle,
1937
+ createChronosMcpTools,
1608
1938
  createReactiveEngine2 as createFrameworkAgnosticReactiveEngine,
1609
1939
  createInMemoryDB,
1610
1940
  createIntrospector,
@@ -215,8 +215,12 @@ function safeClone(value) {
215
215
  var LogicEngine = class {
216
216
  state;
217
217
  registry;
218
+ factDedup;
219
+ maxFacts;
218
220
  constructor(options) {
219
221
  this.registry = options.registry;
222
+ this.factDedup = options.factDedup ?? "last-write-wins";
223
+ this.maxFacts = options.maxFacts ?? 1e3;
220
224
  this.state = {
221
225
  context: options.initialContext,
222
226
  facts: options.initialFacts ?? [],
@@ -272,6 +276,7 @@ var LogicEngine = class {
272
276
  const diagnostics = [];
273
277
  let newState = { ...this.state };
274
278
  const newFacts = [];
279
+ const eventTags = new Set(events.map((e) => e.tag));
275
280
  for (const ruleId of config.ruleIds) {
276
281
  const rule = this.registry.getRule(ruleId);
277
282
  if (!rule) {
@@ -282,6 +287,12 @@ var LogicEngine = class {
282
287
  });
283
288
  continue;
284
289
  }
290
+ if (rule.eventTypes) {
291
+ const filterTags = Array.isArray(rule.eventTypes) ? rule.eventTypes : [rule.eventTypes];
292
+ if (!filterTags.some((t) => eventTags.has(t))) {
293
+ continue;
294
+ }
295
+ }
285
296
  try {
286
297
  const ruleFacts = rule.impl(newState, events);
287
298
  newFacts.push(...ruleFacts);
@@ -293,9 +304,29 @@ var LogicEngine = class {
293
304
  });
294
305
  }
295
306
  }
307
+ let mergedFacts;
308
+ switch (this.factDedup) {
309
+ case "last-write-wins": {
310
+ const factMap = /* @__PURE__ */ new Map();
311
+ for (const f of newState.facts) factMap.set(f.tag, f);
312
+ for (const f of newFacts) factMap.set(f.tag, f);
313
+ mergedFacts = Array.from(factMap.values());
314
+ break;
315
+ }
316
+ case "append":
317
+ mergedFacts = [...newState.facts, ...newFacts];
318
+ break;
319
+ case "none":
320
+ default:
321
+ mergedFacts = [...newState.facts, ...newFacts];
322
+ break;
323
+ }
324
+ if (this.maxFacts > 0 && mergedFacts.length > this.maxFacts) {
325
+ mergedFacts = mergedFacts.slice(mergedFacts.length - this.maxFacts);
326
+ }
296
327
  newState = {
297
328
  ...newState,
298
- facts: [...newState.facts, ...newFacts]
329
+ facts: mergedFacts
299
330
  };
300
331
  for (const constraintId of config.constraintIds) {
301
332
  const constraint = this.registry.getConstraint(constraintId);
@@ -348,6 +379,29 @@ var LogicEngine = class {
348
379
  context: updater(this.state.context)
349
380
  };
350
381
  }
382
+ /**
383
+ * Atomically update context AND process events in a single call.
384
+ *
385
+ * This avoids the fragile pattern of calling updateContext() then step()
386
+ * separately, where rules could see stale context if the ordering is wrong.
387
+ *
388
+ * @param updater Function that produces new context from old context
389
+ * @param events Events to process after context is updated
390
+ * @returns Result with new state and diagnostics
391
+ *
392
+ * @example
393
+ * engine.stepWithContext(
394
+ * ctx => ({ ...ctx, sprintName: sprint.name, items: sprint.items }),
395
+ * [{ tag: 'sprint.update', payload: { name: sprint.name } }]
396
+ * );
397
+ */
398
+ stepWithContext(updater, events) {
399
+ this.state = {
400
+ ...this.state,
401
+ context: updater(this.state.context)
402
+ };
403
+ return this.step(events);
404
+ }
351
405
  /**
352
406
  * Add facts directly (for exceptional cases).
353
407
  * Generally, facts should be added through rules.
@@ -360,6 +414,21 @@ var LogicEngine = class {
360
414
  facts: [...this.state.facts, ...facts]
361
415
  };
362
416
  }
417
+ /**
418
+ * Check all constraints without processing any events.
419
+ *
420
+ * Useful for validation-only scenarios (e.g., form validation,
421
+ * pre-save checks) where you want constraint diagnostics without
422
+ * triggering any rules.
423
+ *
424
+ * @returns Array of constraint violation diagnostics (empty = all passing)
425
+ */
426
+ checkConstraints() {
427
+ return this.stepWithConfig([], {
428
+ ruleIds: [],
429
+ constraintIds: this.registry.getConstraintIds()
430
+ }).diagnostics;
431
+ }
363
432
  /**
364
433
  * Clear all facts
365
434
  */
@@ -1,6 +1,6 @@
1
- import { L as LogicEngine } from '../reactive-engine.svelte-BFIZfawz.cjs';
2
- export { a as ReactiveEngineOptions, R as ReactiveLogicEngine, c as createReactiveEngine } from '../reactive-engine.svelte-BFIZfawz.cjs';
3
- import { P as PraxisState, a as PraxisEvent } from '../protocol-Qek7ebBl.cjs';
1
+ import { L as LogicEngine } from '../reactive-engine.svelte-CGe8SpVE.cjs';
2
+ export { R as ReactiveEngineOptions, a as ReactiveLogicEngine, c as createReactiveEngine } from '../reactive-engine.svelte-CGe8SpVE.cjs';
3
+ import { P as PraxisState, a as PraxisEvent } from '../protocol-BocKczNv.cjs';
4
4
 
5
5
  /**
6
6
  * Svelte v5 Integration
@@ -1,6 +1,6 @@
1
- import { L as LogicEngine } from '../reactive-engine.svelte-CRNqHlbv.js';
2
- export { a as ReactiveEngineOptions, R as ReactiveLogicEngine, c as createReactiveEngine } from '../reactive-engine.svelte-CRNqHlbv.js';
3
- import { P as PraxisState, a as PraxisEvent } from '../protocol-Qek7ebBl.js';
1
+ import { L as LogicEngine } from '../reactive-engine.svelte-D-xTDxT5.js';
2
+ export { R as ReactiveEngineOptions, a as ReactiveLogicEngine, c as createReactiveEngine } from '../reactive-engine.svelte-D-xTDxT5.js';
3
+ import { P as PraxisState, a as PraxisEvent } from '../protocol-BocKczNv.js';
4
4
 
5
5
  /**
6
6
  * Svelte v5 Integration
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  ReactiveLogicEngine,
3
3
  createReactiveEngine
4
- } from "../chunk-PRPQO6R5.js";
4
+ } from "../chunk-32YFEEML.js";
5
5
  import "../chunk-R2PSBPKQ.js";
6
- import "../chunk-VOMLVI6V.js";
6
+ import "../chunk-BBP2F7TT.js";
7
7
  import "../chunk-QGM4M3NI.js";
8
8
 
9
9
  // src/integrations/svelte.ts
@@ -119,4 +119,4 @@ interface PraxisStepResult {
119
119
  */
120
120
  type PraxisStepFn = (state: PraxisState, events: PraxisEvent[], config: PraxisStepConfig) => PraxisStepResult;
121
121
 
122
- export { type PraxisState as P, type PraxisEvent as a, type PraxisFact as b, type PraxisStepResult as c, type PraxisStepConfig as d, type PraxisDiagnostics as e, type PraxisStepFn as f, PRAXIS_PROTOCOL_VERSION as g };
122
+ export { type PraxisState as P, type PraxisEvent as a, type PraxisFact as b, type PraxisStepResult as c, type PraxisStepConfig as d, type PraxisDiagnostics as e, PRAXIS_PROTOCOL_VERSION as f, type PraxisStepFn as g };
@@ -119,4 +119,4 @@ interface PraxisStepResult {
119
119
  */
120
120
  type PraxisStepFn = (state: PraxisState, events: PraxisEvent[], config: PraxisStepConfig) => PraxisStepResult;
121
121
 
122
- export { type PraxisState as P, type PraxisEvent as a, type PraxisFact as b, type PraxisStepResult as c, type PraxisStepConfig as d, type PraxisDiagnostics as e, type PraxisStepFn as f, PRAXIS_PROTOCOL_VERSION as g };
122
+ export { type PraxisState as P, type PraxisEvent as a, type PraxisFact as b, type PraxisStepResult as c, type PraxisStepConfig as d, type PraxisDiagnostics as e, PRAXIS_PROTOCOL_VERSION as f, type PraxisStepFn as g };