@plures/praxis 1.1.2 → 1.2.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 (49) hide show
  1. package/FRAMEWORK.md +106 -15
  2. package/README.md +275 -53
  3. package/dist/browser/adapter-TM4IS5KT.js +12 -0
  4. package/dist/browser/chunk-JQ64KMLN.js +141 -0
  5. package/dist/browser/chunk-LE2ZJYFC.js +154 -0
  6. package/dist/browser/chunk-VOMLVI6V.js +197 -0
  7. package/dist/browser/engine-YJZV4SLD.js +8 -0
  8. package/dist/browser/index.d.ts +300 -11
  9. package/dist/browser/index.js +334 -325
  10. package/dist/browser/integrations/svelte.d.ts +3 -1
  11. package/dist/browser/integrations/svelte.js +8 -0
  12. package/dist/browser/{engine-BjdqxeXG.d.ts → reactive-engine.svelte-C9OpcTHf.d.ts} +87 -1
  13. package/dist/node/adapter-K6DOX6XS.js +13 -0
  14. package/dist/node/chunk-JQ64KMLN.js +141 -0
  15. package/dist/node/chunk-LE2ZJYFC.js +154 -0
  16. package/dist/node/chunk-S54337I5.js +446 -0
  17. package/dist/node/chunk-VOMLVI6V.js +197 -0
  18. package/dist/node/cli/index.cjs +1444 -889
  19. package/dist/node/cli/index.js +9 -0
  20. package/dist/node/components/index.d.cts +2 -2
  21. package/dist/node/components/index.d.ts +2 -2
  22. package/dist/node/docs-JFNYTOJA.js +102 -0
  23. package/dist/node/engine-2DQBKBJC.js +9 -0
  24. package/dist/node/index.cjs +747 -234
  25. package/dist/node/index.d.cts +237 -15
  26. package/dist/node/index.d.ts +237 -15
  27. package/dist/node/index.js +339 -767
  28. package/dist/node/integrations/svelte.cjs +357 -2
  29. package/dist/node/integrations/svelte.d.cts +3 -1
  30. package/dist/node/integrations/svelte.d.ts +3 -1
  31. package/dist/node/integrations/svelte.js +7 -0
  32. package/dist/node/{engine-CVJobhHm.d.cts → reactive-engine.svelte-1M4m_C_v.d.cts} +87 -1
  33. package/dist/node/{engine-1iqLe6_P.d.ts → reactive-engine.svelte-ChNFn4Hj.d.ts} +87 -1
  34. package/dist/node/{terminal-adapter-XLtCjjb_.d.cts → terminal-adapter-CDzxoLKR.d.cts} +68 -1
  35. package/dist/node/{terminal-adapter-07HGftGQ.d.ts → terminal-adapter-CWka-yL8.d.ts} +68 -1
  36. package/package.json +3 -2
  37. package/src/__tests__/reactive-engine.test.ts +516 -0
  38. package/src/cli/commands/docs.ts +147 -0
  39. package/src/cli/index.ts +21 -0
  40. package/src/core/pluresdb/README.md +156 -0
  41. package/src/core/pluresdb/adapter.ts +165 -0
  42. package/src/core/pluresdb/index.ts +3 -3
  43. package/src/core/reactive-engine.svelte.ts +93 -19
  44. package/src/core/reactive-engine.ts +284 -22
  45. package/src/index.browser.ts +16 -0
  46. package/src/index.ts +16 -0
  47. package/src/integrations/pluresdb.ts +2 -2
  48. package/src/integrations/svelte.ts +8 -0
  49. package/src/integrations/unified.ts +350 -0
@@ -0,0 +1,141 @@
1
+ // src/core/pluresdb/adapter.ts
2
+ var InMemoryPraxisDB = class {
3
+ store = /* @__PURE__ */ new Map();
4
+ watchers = /* @__PURE__ */ new Map();
5
+ async get(key) {
6
+ return this.store.get(key);
7
+ }
8
+ async set(key, value) {
9
+ this.store.set(key, value);
10
+ const keyWatchers = this.watchers.get(key);
11
+ if (keyWatchers) {
12
+ for (const callback of keyWatchers) {
13
+ callback(value);
14
+ }
15
+ }
16
+ }
17
+ watch(key, callback) {
18
+ if (!this.watchers.has(key)) {
19
+ this.watchers.set(key, /* @__PURE__ */ new Set());
20
+ }
21
+ const watchers = this.watchers.get(key);
22
+ const wrappedCallback = (val) => callback(val);
23
+ watchers.add(wrappedCallback);
24
+ return () => {
25
+ watchers.delete(wrappedCallback);
26
+ if (watchers.size === 0) {
27
+ this.watchers.delete(key);
28
+ }
29
+ };
30
+ }
31
+ /**
32
+ * Get all keys (for testing/debugging)
33
+ */
34
+ keys() {
35
+ return Array.from(this.store.keys());
36
+ }
37
+ /**
38
+ * Clear all data (for testing)
39
+ */
40
+ clear() {
41
+ this.store.clear();
42
+ this.watchers.clear();
43
+ }
44
+ };
45
+ function createInMemoryDB() {
46
+ return new InMemoryPraxisDB();
47
+ }
48
+ var PluresDBPraxisAdapter = class {
49
+ db;
50
+ watchers = /* @__PURE__ */ new Map();
51
+ pollIntervals = /* @__PURE__ */ new Map();
52
+ lastValues = /* @__PURE__ */ new Map();
53
+ pollInterval;
54
+ constructor(config) {
55
+ if ("get" in config && "put" in config) {
56
+ this.db = config;
57
+ this.pollInterval = 1e3;
58
+ } else {
59
+ this.db = config.db;
60
+ this.pollInterval = config.pollInterval ?? 1e3;
61
+ }
62
+ }
63
+ async get(key) {
64
+ try {
65
+ const value = await this.db.get(key);
66
+ return value;
67
+ } catch (error) {
68
+ return void 0;
69
+ }
70
+ }
71
+ async set(key, value) {
72
+ await this.db.put(key, value);
73
+ this.lastValues.set(key, value);
74
+ const keyWatchers = this.watchers.get(key);
75
+ if (keyWatchers) {
76
+ for (const callback of keyWatchers) {
77
+ callback(value);
78
+ }
79
+ }
80
+ }
81
+ watch(key, callback) {
82
+ if (!this.watchers.has(key)) {
83
+ this.watchers.set(key, /* @__PURE__ */ new Set());
84
+ }
85
+ const watchers = this.watchers.get(key);
86
+ const wrappedCallback = (val) => callback(val);
87
+ watchers.add(wrappedCallback);
88
+ if (!this.pollIntervals.has(key)) {
89
+ const interval = setInterval(async () => {
90
+ try {
91
+ const value = await this.db.get(key);
92
+ const lastValue = this.lastValues.get(key);
93
+ if (JSON.stringify(value) !== JSON.stringify(lastValue)) {
94
+ this.lastValues.set(key, value);
95
+ const currentWatchers = this.watchers.get(key);
96
+ if (currentWatchers) {
97
+ for (const cb of currentWatchers) {
98
+ cb(value);
99
+ }
100
+ }
101
+ }
102
+ } catch (error) {
103
+ }
104
+ }, this.pollInterval);
105
+ this.pollIntervals.set(key, interval);
106
+ }
107
+ return () => {
108
+ watchers.delete(wrappedCallback);
109
+ if (watchers.size === 0) {
110
+ this.watchers.delete(key);
111
+ const interval = this.pollIntervals.get(key);
112
+ if (interval) {
113
+ clearInterval(interval);
114
+ this.pollIntervals.delete(key);
115
+ }
116
+ this.lastValues.delete(key);
117
+ }
118
+ };
119
+ }
120
+ /**
121
+ * Clean up all resources
122
+ */
123
+ dispose() {
124
+ for (const interval of this.pollIntervals.values()) {
125
+ clearInterval(interval);
126
+ }
127
+ this.pollIntervals.clear();
128
+ this.watchers.clear();
129
+ this.lastValues.clear();
130
+ }
131
+ };
132
+ function createPluresDB(config) {
133
+ return new PluresDBPraxisAdapter(config);
134
+ }
135
+
136
+ export {
137
+ InMemoryPraxisDB,
138
+ createInMemoryDB,
139
+ PluresDBPraxisAdapter,
140
+ createPluresDB
141
+ };
@@ -0,0 +1,154 @@
1
+ import {
2
+ createPraxisEngine
3
+ } from "./chunk-VOMLVI6V.js";
4
+
5
+ // src/core/rules.ts
6
+ var PraxisRegistry = class {
7
+ rules = /* @__PURE__ */ new Map();
8
+ constraints = /* @__PURE__ */ new Map();
9
+ /**
10
+ * Register a rule
11
+ */
12
+ registerRule(descriptor) {
13
+ if (this.rules.has(descriptor.id)) {
14
+ throw new Error(`Rule with id "${descriptor.id}" already registered`);
15
+ }
16
+ this.rules.set(descriptor.id, descriptor);
17
+ }
18
+ /**
19
+ * Register a constraint
20
+ */
21
+ registerConstraint(descriptor) {
22
+ if (this.constraints.has(descriptor.id)) {
23
+ throw new Error(`Constraint with id "${descriptor.id}" already registered`);
24
+ }
25
+ this.constraints.set(descriptor.id, descriptor);
26
+ }
27
+ /**
28
+ * Register a module (all its rules and constraints)
29
+ */
30
+ registerModule(module) {
31
+ for (const rule of module.rules) {
32
+ this.registerRule(rule);
33
+ }
34
+ for (const constraint of module.constraints) {
35
+ this.registerConstraint(constraint);
36
+ }
37
+ }
38
+ /**
39
+ * Get a rule by ID
40
+ */
41
+ getRule(id) {
42
+ return this.rules.get(id);
43
+ }
44
+ /**
45
+ * Get a constraint by ID
46
+ */
47
+ getConstraint(id) {
48
+ return this.constraints.get(id);
49
+ }
50
+ /**
51
+ * Get all registered rule IDs
52
+ */
53
+ getRuleIds() {
54
+ return Array.from(this.rules.keys());
55
+ }
56
+ /**
57
+ * Get all registered constraint IDs
58
+ */
59
+ getConstraintIds() {
60
+ return Array.from(this.constraints.keys());
61
+ }
62
+ /**
63
+ * Get all rules
64
+ */
65
+ getAllRules() {
66
+ return Array.from(this.rules.values());
67
+ }
68
+ /**
69
+ * Get all constraints
70
+ */
71
+ getAllConstraints() {
72
+ return Array.from(this.constraints.values());
73
+ }
74
+ };
75
+
76
+ // src/core/reactive-engine.svelte.ts
77
+ import * as $ from "svelte/internal/client";
78
+ var ReactiveLogicEngine = class {
79
+ #state = (
80
+ // Use Svelte's $state rune for automatic reactivity
81
+ $.state($.proxy({ context: {}, facts: [], meta: {} }))
82
+ );
83
+ get state() {
84
+ return $.get(this.#state);
85
+ }
86
+ set state(value) {
87
+ $.set(this.#state, value, true);
88
+ }
89
+ _engine;
90
+ constructor(options) {
91
+ this.state.context = options.initialContext;
92
+ this.state.facts = options.initialFacts ?? [];
93
+ this.state.meta = options.initialMeta ?? {};
94
+ if (options.registry) {
95
+ this._engine = createPraxisEngine({
96
+ initialContext: options.initialContext,
97
+ registry: options.registry
98
+ });
99
+ } else {
100
+ this._engine = createPraxisEngine({
101
+ initialContext: options.initialContext,
102
+ registry: new PraxisRegistry()
103
+ });
104
+ }
105
+ }
106
+ /**
107
+ * Access the reactive context.
108
+ * In Svelte 5 components, changes to this object will automatically trigger updates.
109
+ */
110
+ get context() {
111
+ return this.state.context;
112
+ }
113
+ /**
114
+ * Access the reactive facts list.
115
+ */
116
+ get facts() {
117
+ return this.state.facts;
118
+ }
119
+ /**
120
+ * Access the reactive metadata.
121
+ */
122
+ get meta() {
123
+ return this.state.meta;
124
+ }
125
+ /**
126
+ * Apply a mutation to the state.
127
+ * Changes will automatically trigger Svelte reactivity.
128
+ *
129
+ * @param mutator A function that receives the state and modifies it.
130
+ */
131
+ apply(mutator) {
132
+ mutator(this.state);
133
+ }
134
+ /**
135
+ * Process events through the logic engine and update reactive state.
136
+ *
137
+ * @param events Events to process
138
+ */
139
+ step(events) {
140
+ const result = this._engine.step(events);
141
+ this.state.context = result.state.context;
142
+ this.state.facts = result.state.facts;
143
+ this.state.meta = result.state.meta ?? {};
144
+ }
145
+ };
146
+ function createReactiveEngine(options) {
147
+ return new ReactiveLogicEngine(options);
148
+ }
149
+
150
+ export {
151
+ PraxisRegistry,
152
+ ReactiveLogicEngine,
153
+ createReactiveEngine
154
+ };
@@ -0,0 +1,197 @@
1
+ // src/core/protocol.ts
2
+ var PRAXIS_PROTOCOL_VERSION = "1.0.0";
3
+
4
+ // src/core/engine.ts
5
+ function safeClone(value) {
6
+ if (value === null || typeof value !== "object") {
7
+ return value;
8
+ }
9
+ if (typeof globalThis.structuredClone === "function") {
10
+ try {
11
+ return globalThis.structuredClone(value);
12
+ } catch {
13
+ }
14
+ }
15
+ if (Array.isArray(value)) {
16
+ return [...value];
17
+ }
18
+ return { ...value };
19
+ }
20
+ var LogicEngine = class {
21
+ state;
22
+ registry;
23
+ constructor(options) {
24
+ this.registry = options.registry;
25
+ this.state = {
26
+ context: options.initialContext,
27
+ facts: options.initialFacts ?? [],
28
+ meta: options.initialMeta ?? {},
29
+ protocolVersion: PRAXIS_PROTOCOL_VERSION
30
+ };
31
+ }
32
+ /**
33
+ * Get the current state (immutable copy)
34
+ */
35
+ getState() {
36
+ return {
37
+ context: safeClone(this.state.context),
38
+ facts: [...this.state.facts],
39
+ meta: this.state.meta ? safeClone(this.state.meta) : void 0,
40
+ protocolVersion: this.state.protocolVersion
41
+ };
42
+ }
43
+ /**
44
+ * Get the current context
45
+ */
46
+ getContext() {
47
+ return safeClone(this.state.context);
48
+ }
49
+ /**
50
+ * Get current facts
51
+ */
52
+ getFacts() {
53
+ return [...this.state.facts];
54
+ }
55
+ /**
56
+ * Process events through the engine.
57
+ * Applies all registered rules and checks all registered constraints.
58
+ *
59
+ * @param events Events to process
60
+ * @returns Result with new state and diagnostics
61
+ */
62
+ step(events) {
63
+ const config = {
64
+ ruleIds: this.registry.getRuleIds(),
65
+ constraintIds: this.registry.getConstraintIds()
66
+ };
67
+ return this.stepWithConfig(events, config);
68
+ }
69
+ /**
70
+ * Process events with specific rule and constraint configuration.
71
+ *
72
+ * @param events Events to process
73
+ * @param config Step configuration
74
+ * @returns Result with new state and diagnostics
75
+ */
76
+ stepWithConfig(events, config) {
77
+ const diagnostics = [];
78
+ let newState = { ...this.state };
79
+ const newFacts = [];
80
+ for (const ruleId of config.ruleIds) {
81
+ const rule = this.registry.getRule(ruleId);
82
+ if (!rule) {
83
+ diagnostics.push({
84
+ kind: "rule-error",
85
+ message: `Rule "${ruleId}" not found in registry`,
86
+ data: { ruleId }
87
+ });
88
+ continue;
89
+ }
90
+ try {
91
+ const ruleFacts = rule.impl(newState, events);
92
+ newFacts.push(...ruleFacts);
93
+ } catch (error) {
94
+ diagnostics.push({
95
+ kind: "rule-error",
96
+ message: `Error executing rule "${ruleId}": ${error instanceof Error ? error.message : String(error)}`,
97
+ data: { ruleId, error }
98
+ });
99
+ }
100
+ }
101
+ newState = {
102
+ ...newState,
103
+ facts: [...newState.facts, ...newFacts]
104
+ };
105
+ for (const constraintId of config.constraintIds) {
106
+ const constraint = this.registry.getConstraint(constraintId);
107
+ if (!constraint) {
108
+ diagnostics.push({
109
+ kind: "constraint-violation",
110
+ message: `Constraint "${constraintId}" not found in registry`,
111
+ data: { constraintId }
112
+ });
113
+ continue;
114
+ }
115
+ try {
116
+ const result = constraint.impl(newState);
117
+ if (result === false) {
118
+ diagnostics.push({
119
+ kind: "constraint-violation",
120
+ message: `Constraint "${constraintId}" violated`,
121
+ data: { constraintId, description: constraint.description }
122
+ });
123
+ } else if (typeof result === "string") {
124
+ diagnostics.push({
125
+ kind: "constraint-violation",
126
+ message: result,
127
+ data: { constraintId, description: constraint.description }
128
+ });
129
+ }
130
+ } catch (error) {
131
+ diagnostics.push({
132
+ kind: "constraint-violation",
133
+ message: `Error checking constraint "${constraintId}": ${error instanceof Error ? error.message : String(error)}`,
134
+ data: { constraintId, error }
135
+ });
136
+ }
137
+ }
138
+ this.state = newState;
139
+ return {
140
+ state: newState,
141
+ diagnostics
142
+ };
143
+ }
144
+ /**
145
+ * Update the context directly (for exceptional cases).
146
+ * Generally, context should be updated through rules.
147
+ *
148
+ * @param updater Function that produces new context from old context
149
+ */
150
+ updateContext(updater) {
151
+ this.state = {
152
+ ...this.state,
153
+ context: updater(this.state.context)
154
+ };
155
+ }
156
+ /**
157
+ * Add facts directly (for exceptional cases).
158
+ * Generally, facts should be added through rules.
159
+ *
160
+ * @param facts Facts to add
161
+ */
162
+ addFacts(facts) {
163
+ this.state = {
164
+ ...this.state,
165
+ facts: [...this.state.facts, ...facts]
166
+ };
167
+ }
168
+ /**
169
+ * Clear all facts
170
+ */
171
+ clearFacts() {
172
+ this.state = {
173
+ ...this.state,
174
+ facts: []
175
+ };
176
+ }
177
+ /**
178
+ * Reset the engine to initial state
179
+ */
180
+ reset(options) {
181
+ this.state = {
182
+ context: options.initialContext,
183
+ facts: options.initialFacts ?? [],
184
+ meta: options.initialMeta ?? {},
185
+ protocolVersion: PRAXIS_PROTOCOL_VERSION
186
+ };
187
+ }
188
+ };
189
+ function createPraxisEngine(options) {
190
+ return new LogicEngine(options);
191
+ }
192
+
193
+ export {
194
+ PRAXIS_PROTOCOL_VERSION,
195
+ LogicEngine,
196
+ createPraxisEngine
197
+ };
@@ -0,0 +1,8 @@
1
+ import {
2
+ LogicEngine,
3
+ createPraxisEngine
4
+ } from "./chunk-VOMLVI6V.js";
5
+ export {
6
+ LogicEngine,
7
+ createPraxisEngine
8
+ };