@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.
- package/README.md +63 -0
- package/dist/browser/{chunk-VOMLVI6V.js → chunk-BBP2F7TT.js} +70 -1
- package/dist/browser/{chunk-K377RW4V.js → chunk-FCEH7WMH.js} +1 -1
- package/dist/browser/{engine-YJZV4SLD.js → engine-65QDGCAN.js} +1 -1
- package/dist/browser/index.d.ts +104 -2
- package/dist/browser/index.js +181 -5
- package/dist/browser/integrations/svelte.d.ts +2 -2
- package/dist/browser/integrations/svelte.js +2 -2
- package/dist/browser/{reactive-engine.svelte-9aS0kTa8.d.ts → reactive-engine.svelte-Cqd8Mod2.d.ts} +56 -1
- package/dist/node/{chunk-PRPQO6R5.js → chunk-32YFEEML.js} +1 -1
- package/dist/node/{chunk-VOMLVI6V.js → chunk-BBP2F7TT.js} +70 -1
- package/dist/node/{chunk-5RH7UAQC.js → chunk-PTH6MD6P.js} +1 -0
- package/dist/node/cli/index.cjs +1553 -839
- package/dist/node/cli/index.js +39 -2
- package/dist/node/cloud/index.d.cts +1 -1
- package/dist/node/cloud/index.d.ts +1 -1
- package/dist/node/components/index.d.cts +2 -2
- package/dist/node/components/index.d.ts +2 -2
- package/dist/node/conversations-KQBXTP3N.js +596 -0
- package/dist/node/{engine-2DQBKBJC.js → engine-7CXQV6RC.js} +1 -1
- package/dist/node/index.cjs +408 -3
- package/dist/node/index.d.cts +308 -7
- package/dist/node/index.d.ts +308 -7
- package/dist/node/index.js +336 -6
- package/dist/node/integrations/svelte.cjs +70 -1
- package/dist/node/integrations/svelte.d.cts +3 -3
- package/dist/node/integrations/svelte.d.ts +3 -3
- package/dist/node/integrations/svelte.js +2 -2
- package/dist/node/{protocol-Qek7ebBl.d.ts → protocol-BocKczNv.d.cts} +1 -1
- package/dist/node/{protocol-Qek7ebBl.d.cts → protocol-BocKczNv.d.ts} +1 -1
- package/dist/node/{reactive-engine.svelte-CRNqHlbv.d.ts → reactive-engine.svelte-CGe8SpVE.d.cts} +57 -2
- package/dist/node/{reactive-engine.svelte-BFIZfawz.d.cts → reactive-engine.svelte-D-xTDxT5.d.ts} +57 -2
- package/dist/node/{terminal-adapter-B-UK_Vdz.d.ts → terminal-adapter-CvIvgTo4.d.ts} +1 -1
- package/dist/node/{terminal-adapter-BQSIF5bf.d.cts → terminal-adapter-Db-snPJ3.d.cts} +1 -1
- package/dist/node/{validate-CNHUULQE.js → validate-EN3M4FUR.js} +1 -1
- package/dist/node/{verify-KLJRXVJS.js → verify-7VZRP2WS.js} +2 -2
- package/docs/BOT_UPDATE_POLICY.md +125 -0
- package/docs/DOGFOODING_CHECKLIST.md +254 -0
- package/docs/DOGFOODING_INDEX.md +169 -0
- package/docs/DOGFOODING_QUICK_START.md +140 -0
- package/docs/KNO_ENG_EXTRACTION_PLAN.md +577 -0
- package/docs/PLURES_TOOLS_INVENTORY.md +170 -0
- package/docs/README.md +12 -0
- package/docs/TESTING_BOT_WORKFLOWS.md +154 -0
- package/docs/conversations/INTEGRATION_POINTS.md +719 -0
- package/docs/conversations/README.md +168 -0
- package/docs/core/extending-praxis-core.md +604 -0
- package/docs/core/praxis-core-api.md +385 -0
- package/docs/decision-ledger/contract-index.json +2 -2
- package/docs/decision-ledger/decisions/2026-02-01-monorepo-organization.md +130 -0
- package/docs/examples/DOGFOODING_WORKFLOW_EXAMPLE.md +295 -0
- package/docs/examples/README.md +41 -0
- package/docs/workflows/pr-overlap-guard.md +50 -0
- package/package.json +7 -2
- package/src/__tests__/chronicle.test.ts +512 -0
- package/src/__tests__/conversations.test.ts +312 -0
- package/src/__tests__/edge-cases.test.ts +1 -1
- package/src/__tests__/engine-dx.test.ts +355 -0
- package/src/cli/commands/conversations.ts +252 -0
- package/src/cli/index.ts +73 -0
- package/src/conversations/README.md +230 -0
- package/src/conversations/candidate.schema.json +123 -0
- package/src/conversations/candidates.ts +114 -0
- package/src/conversations/capture.ts +56 -0
- package/src/conversations/classify.ts +110 -0
- package/src/conversations/conversation.schema.json +106 -0
- package/src/conversations/emitters/fs.ts +65 -0
- package/src/conversations/emitters/github.ts +115 -0
- package/src/conversations/gate.ts +102 -0
- package/src/conversations/index.ts +28 -0
- package/src/conversations/normalize.ts +51 -0
- package/src/conversations/redact.ts +57 -0
- package/src/conversations/types.ts +96 -0
- package/src/core/chronicle/chronicle.ts +227 -0
- package/src/core/chronicle/context.ts +80 -0
- package/src/core/chronicle/index.ts +53 -0
- package/src/core/chronicle/mcp.ts +135 -0
- package/src/core/chronicle/types.ts +61 -0
- package/src/core/engine.ts +99 -1
- package/src/core/pluresdb/index.ts +22 -0
- package/src/core/pluresdb/store.ts +162 -5
- package/src/core/rules.ts +12 -0
- package/src/dsl/index.ts +6 -0
- package/src/index.ts +18 -0
- package/src/integrations/pluresdb.ts +22 -0
package/dist/node/index.js
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
formatValidationReportJSON,
|
|
22
22
|
formatValidationReportSARIF,
|
|
23
23
|
validateContracts
|
|
24
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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:
|
|
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-
|
|
2
|
-
export {
|
|
3
|
-
import { P as PraxisState, a as PraxisEvent } from '../protocol-
|
|
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-
|
|
2
|
-
export {
|
|
3
|
-
import { P as PraxisState, a as PraxisEvent } from '../protocol-
|
|
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-
|
|
4
|
+
} from "../chunk-32YFEEML.js";
|
|
5
5
|
import "../chunk-R2PSBPKQ.js";
|
|
6
|
-
import "../chunk-
|
|
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,
|
|
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,
|
|
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 };
|