@plures/praxis 1.2.13 → 1.3.0

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 (93) hide show
  1. package/README.md +44 -0
  2. package/dist/browser/chunk-MJK3IYTJ.js +384 -0
  3. package/dist/browser/{chunk-K377RW4V.js → chunk-N63K4KWS.js} +1 -1
  4. package/dist/browser/{engine-YJZV4SLD.js → engine-YIEGSX7U.js} +1 -1
  5. package/dist/browser/index.d.ts +104 -2
  6. package/dist/browser/index.js +188 -7
  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-DjynI82A.d.ts} +139 -5
  10. package/dist/node/{chunk-PRPQO6R5.js → chunk-5JQJZADT.js} +1 -1
  11. package/dist/node/chunk-KMJWAFZV.js +389 -0
  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-FEN5IYZ5.js} +1 -1
  21. package/dist/node/index.cjs +911 -43
  22. package/dist/node/index.d.cts +574 -7
  23. package/dist/node/index.d.ts +574 -7
  24. package/dist/node/index.js +672 -26
  25. package/dist/node/integrations/svelte.cjs +190 -3
  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-DcyGMmWY.d.cts} +8 -1
  30. package/dist/node/{protocol-Qek7ebBl.d.cts → protocol-DcyGMmWY.d.ts} +8 -1
  31. package/dist/node/{reactive-engine.svelte-CRNqHlbv.d.ts → reactive-engine.svelte-Cg0Yc2Hs.d.cts} +145 -6
  32. package/dist/node/{reactive-engine.svelte-BFIZfawz.d.cts → reactive-engine.svelte-DekxqFu0.d.ts} +145 -6
  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 +8 -3
  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/__tests__/engine-v2.test.ts +532 -0
  60. package/src/cli/commands/conversations.ts +252 -0
  61. package/src/cli/index.ts +73 -0
  62. package/src/conversations/README.md +230 -0
  63. package/src/conversations/candidate.schema.json +123 -0
  64. package/src/conversations/candidates.ts +114 -0
  65. package/src/conversations/capture.ts +56 -0
  66. package/src/conversations/classify.ts +110 -0
  67. package/src/conversations/conversation.schema.json +106 -0
  68. package/src/conversations/emitters/fs.ts +65 -0
  69. package/src/conversations/emitters/github.ts +115 -0
  70. package/src/conversations/gate.ts +102 -0
  71. package/src/conversations/index.ts +28 -0
  72. package/src/conversations/normalize.ts +51 -0
  73. package/src/conversations/redact.ts +57 -0
  74. package/src/conversations/types.ts +96 -0
  75. package/src/core/chronicle/chronicle.ts +227 -0
  76. package/src/core/chronicle/context.ts +80 -0
  77. package/src/core/chronicle/index.ts +53 -0
  78. package/src/core/chronicle/mcp.ts +135 -0
  79. package/src/core/chronicle/types.ts +61 -0
  80. package/src/core/completeness.ts +274 -0
  81. package/src/core/engine.ts +143 -3
  82. package/src/core/pluresdb/index.ts +22 -0
  83. package/src/core/pluresdb/store.ts +171 -8
  84. package/src/core/protocol.ts +7 -0
  85. package/src/core/rule-result.ts +130 -0
  86. package/src/core/rules.ts +24 -5
  87. package/src/core/ui-rules.ts +340 -0
  88. package/src/dsl/index.ts +6 -0
  89. package/src/index.ts +45 -0
  90. package/src/integrations/pluresdb.ts +22 -0
  91. package/src/vite/completeness-plugin.ts +72 -0
  92. package/dist/browser/chunk-VOMLVI6V.js +0 -197
  93. package/dist/node/chunk-VOMLVI6V.js +0 -197
package/README.md CHANGED
@@ -318,6 +318,8 @@ See [src/decision-ledger/README.md](./src/decision-ledger/README.md) for complet
318
318
  ## Documentation
319
319
  - [Getting Started](./GETTING_STARTED.md)
320
320
  - [Framework Guide](./FRAMEWORK.md)
321
+ - [Praxis-Core API](./docs/core/praxis-core-api.md) - Stable API surface & guarantees
322
+ - [Extending Praxis-Core](./docs/core/extending-praxis-core.md) - Extension guidelines
321
323
  - [Decision Ledger Guide](./src/decision-ledger/README.md)
322
324
  - [Examples](./examples/)
323
325
 
@@ -458,6 +460,44 @@ This protocol is:
458
460
 
459
461
  ## Framework Architecture
460
462
 
463
+ Praxis is organized as a **monorepo** with clearly separated packages. See [MONOREPO.md](./MONOREPO.md) for the complete organization plan.
464
+
465
+ ### Target Monorepo Structure
466
+
467
+ ```
468
+ praxis/
469
+ ├── packages/ # Published npm packages
470
+ │ ├── praxis-core/ # Core logic library (zero dependencies)
471
+ │ │ └── src/
472
+ │ │ ├── logic/ # Facts, events, rules, constraints, engine
473
+ │ │ ├── schema/ # Schema definitions and validation
474
+ │ │ ├── decision-ledger/ # Contracts and behavior specifications
475
+ │ │ └── protocol/ # Core protocol types
476
+ │ ├── praxis-cli/ # Command-line interface
477
+ │ │ └── src/
478
+ │ │ ├── commands/ # CLI commands
479
+ │ │ └── generators/ # Code generators
480
+ │ ├── praxis-svelte/ # Svelte 5 integration
481
+ │ │ └── src/
482
+ │ │ ├── components/ # Reactive Svelte components
483
+ │ │ ├── generators/ # Component generators
484
+ │ │ └── runtime/ # Svelte runtime integration
485
+ │ ├── praxis-cloud/ # Cloud sync and relay
486
+ │ │ └── src/
487
+ │ │ ├── relay/ # Cloud relay server
488
+ │ │ └── sync/ # Sync protocol
489
+ │ └── praxis/ # Main package (re-exports all)
490
+ ├── apps/ # Example applications
491
+ ├── tools/ # Development tools
492
+ ├── ui/ # UI components and tools
493
+ ├── docs/ # Documentation
494
+ └── examples/ # Simple examples and demos
495
+ ```
496
+
497
+ ### Current Structure (In Transition)
498
+
499
+ The existing code is currently located in:
500
+
461
501
  ```
462
502
  /praxis
463
503
  ├── core/ # Core framework
@@ -1116,6 +1156,10 @@ MIT License - see [LICENSE](./LICENSE) for details.
1116
1156
 
1117
1157
  Contributions are welcome! Please read our [Contributing Guide](./CONTRIBUTING.md) to get started.
1118
1158
 
1159
+ **Automated Updates**: This repository uses batched bot updates to reduce commit churn. Dependency updates are grouped weekly and include audit trails. See the [Bot Update Policy](./docs/BOT_UPDATE_POLICY.md) for details.
1160
+
1161
+ **Dogfooding Plures Tools**: We actively dogfood all Plures tools during development. If you encounter friction while using any tool, please file a [Dogfooding Friction Report](https://github.com/plures/praxis/issues/new/choose). See the [Dogfooding Quick Start](./docs/DOGFOODING_QUICK_START.md) for details.
1162
+
1119
1163
  - 🐛 [Report a bug](https://github.com/plures/praxis/issues/new?template=bug_report.yml)
1120
1164
  - 💡 [Request a feature](https://github.com/plures/praxis/issues/new?template=enhancement.yml)
1121
1165
  - 📖 [Improve documentation](https://github.com/plures/praxis/issues/new?template=bug_report.yml)
@@ -0,0 +1,384 @@
1
+ // src/core/protocol.ts
2
+ var PRAXIS_PROTOCOL_VERSION = "1.0.0";
3
+
4
+ // src/core/rule-result.ts
5
+ var RuleResult = class _RuleResult {
6
+ /** The kind of result */
7
+ kind;
8
+ /** Facts produced (only for 'emit') */
9
+ facts;
10
+ /** Fact tags to retract (only for 'retract') */
11
+ retractTags;
12
+ /** Optional reason (for noop/skip/retract — useful for debugging) */
13
+ reason;
14
+ /** The rule ID that produced this result (set by engine) */
15
+ ruleId;
16
+ constructor(kind, facts, retractTags, reason) {
17
+ this.kind = kind;
18
+ this.facts = facts;
19
+ this.retractTags = retractTags;
20
+ this.reason = reason;
21
+ }
22
+ /**
23
+ * Rule produced facts.
24
+ *
25
+ * @example
26
+ * return RuleResult.emit([
27
+ * { tag: 'sprint.behind', payload: { deficit: 5 } }
28
+ * ]);
29
+ */
30
+ static emit(facts) {
31
+ if (facts.length === 0) {
32
+ throw new Error(
33
+ "RuleResult.emit() requires at least one fact. Use RuleResult.noop() or RuleResult.skip() when a rule has nothing to say."
34
+ );
35
+ }
36
+ return new _RuleResult("emit", facts, []);
37
+ }
38
+ /**
39
+ * Rule evaluated but had nothing to report.
40
+ * Unlike returning [], this is explicit and traceable.
41
+ *
42
+ * @example
43
+ * if (ctx.completedHours >= expectedHours) {
44
+ * return RuleResult.noop('Sprint is on pace');
45
+ * }
46
+ */
47
+ static noop(reason) {
48
+ return new _RuleResult("noop", [], [], reason);
49
+ }
50
+ /**
51
+ * Rule decided to skip because preconditions were not met.
52
+ * Distinct from noop: skip means "I can't evaluate", noop means "I evaluated and found nothing".
53
+ *
54
+ * @example
55
+ * if (!ctx.sprintName) {
56
+ * return RuleResult.skip('No active sprint');
57
+ * }
58
+ */
59
+ static skip(reason) {
60
+ return new _RuleResult("skip", [], [], reason);
61
+ }
62
+ /**
63
+ * Rule retracts previously emitted facts by tag.
64
+ * Used when a condition that previously produced facts is no longer true.
65
+ *
66
+ * @example
67
+ * // Sprint was behind, but caught up
68
+ * if (ctx.completedHours >= expectedHours) {
69
+ * return RuleResult.retract(['sprint.behind'], 'Sprint caught up');
70
+ * }
71
+ */
72
+ static retract(tags, reason) {
73
+ if (tags.length === 0) {
74
+ throw new Error("RuleResult.retract() requires at least one tag.");
75
+ }
76
+ return new _RuleResult("retract", [], tags, reason);
77
+ }
78
+ /** Whether this result produced facts */
79
+ get hasFacts() {
80
+ return this.facts.length > 0;
81
+ }
82
+ /** Whether this result retracts facts */
83
+ get hasRetractions() {
84
+ return this.retractTags.length > 0;
85
+ }
86
+ };
87
+
88
+ // src/core/engine.ts
89
+ function safeClone(value) {
90
+ if (value === null || typeof value !== "object") {
91
+ return value;
92
+ }
93
+ if (typeof globalThis.structuredClone === "function") {
94
+ try {
95
+ return globalThis.structuredClone(value);
96
+ } catch {
97
+ }
98
+ }
99
+ if (Array.isArray(value)) {
100
+ return [...value];
101
+ }
102
+ return { ...value };
103
+ }
104
+ var LogicEngine = class {
105
+ state;
106
+ registry;
107
+ factDedup;
108
+ maxFacts;
109
+ constructor(options) {
110
+ this.registry = options.registry;
111
+ this.factDedup = options.factDedup ?? "last-write-wins";
112
+ this.maxFacts = options.maxFacts ?? 1e3;
113
+ this.state = {
114
+ context: options.initialContext,
115
+ facts: options.initialFacts ?? [],
116
+ meta: options.initialMeta ?? {},
117
+ protocolVersion: PRAXIS_PROTOCOL_VERSION
118
+ };
119
+ }
120
+ /**
121
+ * Get the current state (immutable copy)
122
+ */
123
+ getState() {
124
+ return {
125
+ context: safeClone(this.state.context),
126
+ facts: [...this.state.facts],
127
+ meta: this.state.meta ? safeClone(this.state.meta) : void 0,
128
+ protocolVersion: this.state.protocolVersion
129
+ };
130
+ }
131
+ /**
132
+ * Get the current context
133
+ */
134
+ getContext() {
135
+ return safeClone(this.state.context);
136
+ }
137
+ /**
138
+ * Get current facts
139
+ */
140
+ getFacts() {
141
+ return [...this.state.facts];
142
+ }
143
+ /**
144
+ * Process events through the engine.
145
+ * Applies all registered rules and checks all registered constraints.
146
+ *
147
+ * @param events Events to process
148
+ * @returns Result with new state and diagnostics
149
+ */
150
+ step(events) {
151
+ const config = {
152
+ ruleIds: this.registry.getRuleIds(),
153
+ constraintIds: this.registry.getConstraintIds()
154
+ };
155
+ return this.stepWithConfig(events, config);
156
+ }
157
+ /**
158
+ * Process events with specific rule and constraint configuration.
159
+ *
160
+ * @param events Events to process
161
+ * @param config Step configuration
162
+ * @returns Result with new state and diagnostics
163
+ */
164
+ stepWithConfig(events, config) {
165
+ const diagnostics = [];
166
+ let newState = { ...this.state };
167
+ const stateWithEvents = {
168
+ ...newState,
169
+ events
170
+ // current batch — rules can read state.events
171
+ };
172
+ const newFacts = [];
173
+ const retractions = [];
174
+ const eventTags = new Set(events.map((e) => e.tag));
175
+ for (const ruleId of config.ruleIds) {
176
+ const rule = this.registry.getRule(ruleId);
177
+ if (!rule) {
178
+ diagnostics.push({
179
+ kind: "rule-error",
180
+ message: `Rule "${ruleId}" not found in registry`,
181
+ data: { ruleId }
182
+ });
183
+ continue;
184
+ }
185
+ if (rule.eventTypes) {
186
+ const filterTags = Array.isArray(rule.eventTypes) ? rule.eventTypes : [rule.eventTypes];
187
+ if (!filterTags.some((t) => eventTags.has(t))) {
188
+ continue;
189
+ }
190
+ }
191
+ try {
192
+ const rawResult = rule.impl(stateWithEvents, events);
193
+ if (rawResult instanceof RuleResult) {
194
+ rawResult.ruleId = ruleId;
195
+ switch (rawResult.kind) {
196
+ case "emit":
197
+ newFacts.push(...rawResult.facts);
198
+ break;
199
+ case "retract":
200
+ retractions.push(...rawResult.retractTags);
201
+ break;
202
+ case "noop":
203
+ case "skip":
204
+ if (rawResult.reason) {
205
+ diagnostics.push({
206
+ kind: "rule-error",
207
+ // reused kind — could add 'rule-trace' in protocol v2
208
+ message: `[${rawResult.kind}] ${ruleId}: ${rawResult.reason}`,
209
+ data: { ruleId, resultKind: rawResult.kind, reason: rawResult.reason }
210
+ });
211
+ }
212
+ break;
213
+ }
214
+ } else if (Array.isArray(rawResult)) {
215
+ newFacts.push(...rawResult);
216
+ }
217
+ } catch (error) {
218
+ diagnostics.push({
219
+ kind: "rule-error",
220
+ message: `Error executing rule "${ruleId}": ${error instanceof Error ? error.message : String(error)}`,
221
+ data: { ruleId, error }
222
+ });
223
+ }
224
+ }
225
+ let existingFacts = newState.facts;
226
+ if (retractions.length > 0) {
227
+ const retractSet = new Set(retractions);
228
+ existingFacts = existingFacts.filter((f) => !retractSet.has(f.tag));
229
+ }
230
+ let mergedFacts;
231
+ switch (this.factDedup) {
232
+ case "last-write-wins": {
233
+ const factMap = /* @__PURE__ */ new Map();
234
+ for (const f of existingFacts) factMap.set(f.tag, f);
235
+ for (const f of newFacts) factMap.set(f.tag, f);
236
+ mergedFacts = Array.from(factMap.values());
237
+ break;
238
+ }
239
+ case "append":
240
+ mergedFacts = [...existingFacts, ...newFacts];
241
+ break;
242
+ case "none":
243
+ default:
244
+ mergedFacts = [...existingFacts, ...newFacts];
245
+ break;
246
+ }
247
+ if (this.maxFacts > 0 && mergedFacts.length > this.maxFacts) {
248
+ mergedFacts = mergedFacts.slice(mergedFacts.length - this.maxFacts);
249
+ }
250
+ newState = {
251
+ ...newState,
252
+ facts: mergedFacts
253
+ };
254
+ for (const constraintId of config.constraintIds) {
255
+ const constraint = this.registry.getConstraint(constraintId);
256
+ if (!constraint) {
257
+ diagnostics.push({
258
+ kind: "constraint-violation",
259
+ message: `Constraint "${constraintId}" not found in registry`,
260
+ data: { constraintId }
261
+ });
262
+ continue;
263
+ }
264
+ try {
265
+ const result = constraint.impl(newState);
266
+ if (result === false) {
267
+ diagnostics.push({
268
+ kind: "constraint-violation",
269
+ message: `Constraint "${constraintId}" violated`,
270
+ data: { constraintId, description: constraint.description }
271
+ });
272
+ } else if (typeof result === "string") {
273
+ diagnostics.push({
274
+ kind: "constraint-violation",
275
+ message: result,
276
+ data: { constraintId, description: constraint.description }
277
+ });
278
+ }
279
+ } catch (error) {
280
+ diagnostics.push({
281
+ kind: "constraint-violation",
282
+ message: `Error checking constraint "${constraintId}": ${error instanceof Error ? error.message : String(error)}`,
283
+ data: { constraintId, error }
284
+ });
285
+ }
286
+ }
287
+ this.state = newState;
288
+ return {
289
+ state: newState,
290
+ diagnostics
291
+ };
292
+ }
293
+ /**
294
+ * Update the context directly (for exceptional cases).
295
+ * Generally, context should be updated through rules.
296
+ *
297
+ * @param updater Function that produces new context from old context
298
+ */
299
+ updateContext(updater) {
300
+ this.state = {
301
+ ...this.state,
302
+ context: updater(this.state.context)
303
+ };
304
+ }
305
+ /**
306
+ * Atomically update context AND process events in a single call.
307
+ *
308
+ * This avoids the fragile pattern of calling updateContext() then step()
309
+ * separately, where rules could see stale context if the ordering is wrong.
310
+ *
311
+ * @param updater Function that produces new context from old context
312
+ * @param events Events to process after context is updated
313
+ * @returns Result with new state and diagnostics
314
+ *
315
+ * @example
316
+ * engine.stepWithContext(
317
+ * ctx => ({ ...ctx, sprintName: sprint.name, items: sprint.items }),
318
+ * [{ tag: 'sprint.update', payload: { name: sprint.name } }]
319
+ * );
320
+ */
321
+ stepWithContext(updater, events) {
322
+ this.state = {
323
+ ...this.state,
324
+ context: updater(this.state.context)
325
+ };
326
+ return this.step(events);
327
+ }
328
+ /**
329
+ * Add facts directly (for exceptional cases).
330
+ * Generally, facts should be added through rules.
331
+ *
332
+ * @param facts Facts to add
333
+ */
334
+ addFacts(facts) {
335
+ this.state = {
336
+ ...this.state,
337
+ facts: [...this.state.facts, ...facts]
338
+ };
339
+ }
340
+ /**
341
+ * Check all constraints without processing any events.
342
+ *
343
+ * Useful for validation-only scenarios (e.g., form validation,
344
+ * pre-save checks) where you want constraint diagnostics without
345
+ * triggering any rules.
346
+ *
347
+ * @returns Array of constraint violation diagnostics (empty = all passing)
348
+ */
349
+ checkConstraints() {
350
+ return this.stepWithConfig([], {
351
+ ruleIds: [],
352
+ constraintIds: this.registry.getConstraintIds()
353
+ }).diagnostics;
354
+ }
355
+ /**
356
+ * Clear all facts
357
+ */
358
+ clearFacts() {
359
+ this.state = {
360
+ ...this.state,
361
+ facts: []
362
+ };
363
+ }
364
+ /**
365
+ * Reset the engine to initial state
366
+ */
367
+ reset(options) {
368
+ this.state = {
369
+ context: options.initialContext,
370
+ facts: options.initialFacts ?? [],
371
+ meta: options.initialMeta ?? {},
372
+ protocolVersion: PRAXIS_PROTOCOL_VERSION
373
+ };
374
+ }
375
+ };
376
+ function createPraxisEngine(options) {
377
+ return new LogicEngine(options);
378
+ }
379
+
380
+ export {
381
+ PRAXIS_PROTOCOL_VERSION,
382
+ LogicEngine,
383
+ createPraxisEngine
384
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createPraxisEngine
3
- } from "./chunk-VOMLVI6V.js";
3
+ } from "./chunk-MJK3IYTJ.js";
4
4
 
5
5
  // src/core/rules.ts
6
6
  var PraxisRegistry = class {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  LogicEngine,
3
3
  createPraxisEngine
4
- } from "./chunk-VOMLVI6V.js";
4
+ } from "./chunk-MJK3IYTJ.js";
5
5
  export {
6
6
  LogicEngine,
7
7
  createPraxisEngine
@@ -1,5 +1,5 @@
1
- import { L as LogicEngine, P as PraxisState, a as PraxisEvent, b as PraxisRegistry, R as RuleDescriptor, C as ConstraintDescriptor, c as PraxisFact, d as RuleFn, e as Contract, f as ConstraintFn, g as PraxisModule } from './reactive-engine.svelte-9aS0kTa8.js';
2
- export { n as ConstraintId, l as PRAXIS_PROTOCOL_VERSION, h as PraxisDiagnostics, o as PraxisEngineOptions, i as PraxisStepConfig, k as PraxisStepFn, j as PraxisStepResult, q as ReactiveEngineOptions, r as ReactiveLogicEngine, m as RuleId, p as createPraxisEngine, s as createReactiveEngine } from './reactive-engine.svelte-9aS0kTa8.js';
1
+ import { L as LogicEngine, P as PraxisState, a as PraxisEvent, b as PraxisRegistry, R as RuleDescriptor, C as ConstraintDescriptor, c as ConstraintFn, d as Contract, e as RuleFn, f as PraxisFact, g as PraxisModule } from './reactive-engine.svelte-DjynI82A.js';
2
+ export { h as ConstraintId, i as PRAXIS_PROTOCOL_VERSION, j as PraxisDiagnostics, k as PraxisEngineOptions, l as PraxisStepConfig, m as PraxisStepFn, n as PraxisStepResult, o as ReactiveEngineOptions, p as ReactiveLogicEngine, q as RuleId, r as createPraxisEngine, s as createReactiveEngine } from './reactive-engine.svelte-DjynI82A.js';
3
3
  import { LocalFirstOptions } from '@plures/pluresdb/local-first';
4
4
 
5
5
  /**
@@ -435,6 +435,11 @@ interface DefineRuleOptions<TContext = unknown> {
435
435
  id: string;
436
436
  description: string;
437
437
  impl: RuleFn<TContext>;
438
+ /**
439
+ * Optional event type filter — only evaluate this rule when at least one
440
+ * event in the batch has a matching `tag`. Accepts a single tag or array.
441
+ */
442
+ eventTypes?: string | string[];
438
443
  contract?: Contract;
439
444
  meta?: Record<string, unknown>;
440
445
  }
@@ -1103,6 +1108,86 @@ interface PraxisLocalFirstOptions extends LocalFirstOptions {
1103
1108
  */
1104
1109
  declare function createPraxisLocalFirst(options?: PraxisLocalFirstOptions): Promise<PluresDBPraxisAdapter>;
1105
1110
 
1111
+ /**
1112
+ * Chronicle Types
1113
+ *
1114
+ * Core types for the Chronicle causal tracking system.
1115
+ * Records state transitions as a causal graph stored in PluresDB.
1116
+ */
1117
+ /**
1118
+ * Direction for traversing causal chains.
1119
+ */
1120
+ type TraceDirection = 'backward' | 'forward' | 'both';
1121
+ /**
1122
+ * A recorded state transition event passed to Chronicle.
1123
+ */
1124
+ interface ChronicleEvent {
1125
+ /** Path to the changed value (fact or event stream path) */
1126
+ path: string;
1127
+ /** Value before the change (undefined for creates) */
1128
+ before?: unknown;
1129
+ /** Value after the change */
1130
+ after?: unknown;
1131
+ /** Parent span/node ID that caused this change */
1132
+ cause?: string;
1133
+ /** Session or request ID grouping related changes */
1134
+ context?: string;
1135
+ /** Additional metadata key-value pairs */
1136
+ metadata: Record<string, string>;
1137
+ }
1138
+ /**
1139
+ * A Chronicle node representing a single recorded state transition.
1140
+ */
1141
+ interface ChronicleNode {
1142
+ /** Unique node ID: `chronos:{timestamp}-{counter}` */
1143
+ id: string;
1144
+ /** Timestamp (ms since epoch) when this node was recorded */
1145
+ timestamp: number;
1146
+ /** The recorded state transition */
1147
+ event: ChronicleEvent;
1148
+ }
1149
+
1150
+ /**
1151
+ * Chronicle Interface and PluresDbChronicle Implementation
1152
+ *
1153
+ * Records state transitions as a causal graph in PluresDB.
1154
+ * Attached to PraxisDBStore via `.withChronicle()` for zero-effort observability.
1155
+ */
1156
+
1157
+ /**
1158
+ * Chronicle interface — records state transitions as a causal graph.
1159
+ *
1160
+ * Automatically attached to any PraxisDBStore at runtime via `.withChronicle()`.
1161
+ * Records state diffs as graph nodes with causal edges.
1162
+ */
1163
+ interface Chronicle {
1164
+ /**
1165
+ * Record a state transition and return the created node.
1166
+ */
1167
+ record(event: ChronicleEvent): Promise<ChronicleNode>;
1168
+ /**
1169
+ * Trace causality backward or forward from a node.
1170
+ *
1171
+ * @param nodeId Starting node ID
1172
+ * @param direction `'backward'` follows incoming edges, `'forward'` follows outgoing edges
1173
+ * @param maxDepth Maximum traversal depth (prevents cycles / infinite loops)
1174
+ */
1175
+ trace(nodeId: string, direction: TraceDirection, maxDepth: number): Promise<ChronicleNode[]>;
1176
+ /**
1177
+ * Return all Chronicle nodes recorded within a timestamp range.
1178
+ *
1179
+ * @param start Inclusive start timestamp (ms)
1180
+ * @param end Inclusive end timestamp (ms)
1181
+ */
1182
+ range(start: number, end: number): Promise<ChronicleNode[]>;
1183
+ /**
1184
+ * Return all Chronicle nodes belonging to a context (session/request).
1185
+ *
1186
+ * @param contextId The context identifier
1187
+ */
1188
+ subgraph(contextId: string): Promise<ChronicleNode[]>;
1189
+ }
1190
+
1106
1191
  /**
1107
1192
  * PraxisDB Store
1108
1193
  *
@@ -1182,9 +1267,26 @@ declare class PraxisDBStore<TContext = unknown> {
1182
1267
  private subscriptions;
1183
1268
  private factWatchers;
1184
1269
  private onRuleError;
1270
+ private chronicle?;
1185
1271
  constructor(options: PraxisDBStoreOptions<TContext> & {
1186
1272
  onRuleError?: RuleErrorHandler;
1187
1273
  });
1274
+ /**
1275
+ * Attach a Chronicle observer to this store.
1276
+ *
1277
+ * Every subsequent `storeFact` and `appendEvent` call will be recorded as a
1278
+ * causal graph node in PluresDB, enabling full observability for free.
1279
+ *
1280
+ * @param chronicle Chronicle implementation to attach
1281
+ * @returns `this` for fluent chaining
1282
+ *
1283
+ * @example
1284
+ * ```typescript
1285
+ * const store = createPraxisDBStore(db, registry)
1286
+ * .withChronicle(createChronicle(db));
1287
+ * ```
1288
+ */
1289
+ withChronicle(chronicle: Chronicle): this;
1188
1290
  /**
1189
1291
  * Store a fact in PluresDB
1190
1292
  *