@plures/praxis 1.2.41 → 1.4.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.
- package/dist/browser/{chunk-BBP2F7TT.js → chunk-MJK3IYTJ.js} +123 -5
- package/dist/browser/{chunk-FCEH7WMH.js → chunk-N63K4KWS.js} +1 -1
- package/dist/browser/{engine-65QDGCAN.js → engine-YIEGSX7U.js} +1 -1
- package/dist/browser/index.d.ts +2 -2
- package/dist/browser/index.js +10 -5
- package/dist/browser/integrations/svelte.d.ts +2 -2
- package/dist/browser/integrations/svelte.js +2 -2
- package/dist/browser/{reactive-engine.svelte-Cqd8Mod2.d.ts → reactive-engine.svelte-DjynI82A.d.ts} +83 -4
- package/dist/node/chunk-2IUFZBH3.js +87 -0
- package/dist/node/{chunk-WZ6B3LZ6.js → chunk-7CSWBDFL.js} +3 -56
- package/dist/node/{chunk-32YFEEML.js → chunk-7M3HV4XR.js} +4 -4
- package/dist/node/{chunk-PTH6MD6P.js → chunk-FWOXU4MM.js} +1 -1
- package/dist/node/{chunk-BBP2F7TT.js → chunk-KMJWAFZV.js} +128 -5
- package/dist/node/chunk-PGVSB6NR.js +59 -0
- package/dist/node/cli/index.cjs +1078 -211
- package/dist/node/cli/index.js +21 -2
- package/dist/node/cloud/index.d.cts +1 -1
- package/dist/node/cloud/index.d.ts +1 -1
- package/dist/node/{engine-7CXQV6RC.js → engine-FEN5IYZ5.js} +1 -1
- package/dist/node/index.cjs +1633 -59
- package/dist/node/index.d.cts +769 -5
- package/dist/node/index.d.ts +769 -5
- package/dist/node/index.js +1375 -45
- package/dist/node/integrations/svelte.cjs +123 -5
- package/dist/node/integrations/svelte.d.cts +3 -3
- package/dist/node/integrations/svelte.d.ts +3 -3
- package/dist/node/integrations/svelte.js +3 -3
- package/dist/node/{protocol-BocKczNv.d.ts → protocol-DcyGMmWY.d.cts} +7 -0
- package/dist/node/{protocol-BocKczNv.d.cts → protocol-DcyGMmWY.d.ts} +7 -0
- package/dist/node/{reactive-engine.svelte-CGe8SpVE.d.cts → reactive-engine.svelte-Cg0Yc2Hs.d.cts} +90 -6
- package/dist/node/{reactive-engine.svelte-D-xTDxT5.d.ts → reactive-engine.svelte-DekxqFu0.d.ts} +90 -6
- package/dist/node/{reverse-W7THPV45.js → reverse-YD3CWIGM.js} +3 -2
- package/dist/node/rules-4DAJ4Z4N.js +7 -0
- package/dist/node/server-SYZPDULV.js +361 -0
- package/dist/node/{validate-EN3M4FUR.js → validate-TQGVIG7G.js} +4 -3
- package/package.json +29 -3
- package/src/__tests__/engine-v2.test.ts +532 -0
- package/src/__tests__/expectations.test.ts +364 -0
- package/src/__tests__/factory.test.ts +426 -0
- package/src/__tests__/mcp-server.test.ts +310 -0
- package/src/__tests__/project.test.ts +396 -0
- package/src/cli/index.ts +28 -0
- package/src/core/completeness.ts +274 -0
- package/src/core/engine.ts +47 -5
- package/src/core/pluresdb/store.ts +9 -3
- package/src/core/protocol.ts +7 -0
- package/src/core/rule-result.ts +130 -0
- package/src/core/rules.ts +12 -5
- package/src/core/ui-rules.ts +340 -0
- package/src/expectations/expectations.ts +471 -0
- package/src/expectations/index.ts +29 -0
- package/src/expectations/types.ts +95 -0
- package/src/factory/factory.ts +634 -0
- package/src/factory/index.ts +27 -0
- package/src/factory/types.ts +64 -0
- package/src/index.ts +84 -0
- package/src/mcp/index.ts +33 -0
- package/src/mcp/server.ts +485 -0
- package/src/mcp/types.ts +161 -0
- package/src/project/index.ts +31 -0
- package/src/project/project.ts +423 -0
- package/src/project/types.ts +87 -0
- package/src/vite/completeness-plugin.ts +72 -0
- /package/dist/node/{chunk-R2PSBPKQ.js → chunk-TEMFJOIH.js} +0 -0
|
@@ -1,6 +1,93 @@
|
|
|
1
1
|
// src/core/protocol.ts
|
|
2
2
|
var PRAXIS_PROTOCOL_VERSION = "1.0.0";
|
|
3
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
|
+
function fact(tag, payload) {
|
|
88
|
+
return { tag, payload };
|
|
89
|
+
}
|
|
90
|
+
|
|
4
91
|
// src/core/engine.ts
|
|
5
92
|
function safeClone(value) {
|
|
6
93
|
if (value === null || typeof value !== "object") {
|
|
@@ -80,7 +167,13 @@ var LogicEngine = class {
|
|
|
80
167
|
stepWithConfig(events, config) {
|
|
81
168
|
const diagnostics = [];
|
|
82
169
|
let newState = { ...this.state };
|
|
170
|
+
const stateWithEvents = {
|
|
171
|
+
...newState,
|
|
172
|
+
events
|
|
173
|
+
// current batch — rules can read state.events
|
|
174
|
+
};
|
|
83
175
|
const newFacts = [];
|
|
176
|
+
const retractions = [];
|
|
84
177
|
const eventTags = new Set(events.map((e) => e.tag));
|
|
85
178
|
for (const ruleId of config.ruleIds) {
|
|
86
179
|
const rule = this.registry.getRule(ruleId);
|
|
@@ -99,8 +192,31 @@ var LogicEngine = class {
|
|
|
99
192
|
}
|
|
100
193
|
}
|
|
101
194
|
try {
|
|
102
|
-
const
|
|
103
|
-
|
|
195
|
+
const rawResult = rule.impl(stateWithEvents, events);
|
|
196
|
+
if (rawResult instanceof RuleResult) {
|
|
197
|
+
rawResult.ruleId = ruleId;
|
|
198
|
+
switch (rawResult.kind) {
|
|
199
|
+
case "emit":
|
|
200
|
+
newFacts.push(...rawResult.facts);
|
|
201
|
+
break;
|
|
202
|
+
case "retract":
|
|
203
|
+
retractions.push(...rawResult.retractTags);
|
|
204
|
+
break;
|
|
205
|
+
case "noop":
|
|
206
|
+
case "skip":
|
|
207
|
+
if (rawResult.reason) {
|
|
208
|
+
diagnostics.push({
|
|
209
|
+
kind: "rule-error",
|
|
210
|
+
// reused kind — could add 'rule-trace' in protocol v2
|
|
211
|
+
message: `[${rawResult.kind}] ${ruleId}: ${rawResult.reason}`,
|
|
212
|
+
data: { ruleId, resultKind: rawResult.kind, reason: rawResult.reason }
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
} else if (Array.isArray(rawResult)) {
|
|
218
|
+
newFacts.push(...rawResult);
|
|
219
|
+
}
|
|
104
220
|
} catch (error) {
|
|
105
221
|
diagnostics.push({
|
|
106
222
|
kind: "rule-error",
|
|
@@ -109,21 +225,26 @@ var LogicEngine = class {
|
|
|
109
225
|
});
|
|
110
226
|
}
|
|
111
227
|
}
|
|
228
|
+
let existingFacts = newState.facts;
|
|
229
|
+
if (retractions.length > 0) {
|
|
230
|
+
const retractSet = new Set(retractions);
|
|
231
|
+
existingFacts = existingFacts.filter((f) => !retractSet.has(f.tag));
|
|
232
|
+
}
|
|
112
233
|
let mergedFacts;
|
|
113
234
|
switch (this.factDedup) {
|
|
114
235
|
case "last-write-wins": {
|
|
115
236
|
const factMap = /* @__PURE__ */ new Map();
|
|
116
|
-
for (const f of
|
|
237
|
+
for (const f of existingFacts) factMap.set(f.tag, f);
|
|
117
238
|
for (const f of newFacts) factMap.set(f.tag, f);
|
|
118
239
|
mergedFacts = Array.from(factMap.values());
|
|
119
240
|
break;
|
|
120
241
|
}
|
|
121
242
|
case "append":
|
|
122
|
-
mergedFacts = [...
|
|
243
|
+
mergedFacts = [...existingFacts, ...newFacts];
|
|
123
244
|
break;
|
|
124
245
|
case "none":
|
|
125
246
|
default:
|
|
126
|
-
mergedFacts = [...
|
|
247
|
+
mergedFacts = [...existingFacts, ...newFacts];
|
|
127
248
|
break;
|
|
128
249
|
}
|
|
129
250
|
if (this.maxFacts > 0 && mergedFacts.length > this.maxFacts) {
|
|
@@ -261,6 +382,8 @@ function createPraxisEngine(options) {
|
|
|
261
382
|
|
|
262
383
|
export {
|
|
263
384
|
PRAXIS_PROTOCOL_VERSION,
|
|
385
|
+
RuleResult,
|
|
386
|
+
fact,
|
|
264
387
|
LogicEngine,
|
|
265
388
|
createPraxisEngine
|
|
266
389
|
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// src/decision-ledger/types.ts
|
|
2
|
+
function isContract(obj) {
|
|
3
|
+
if (typeof obj !== "object" || obj === null) {
|
|
4
|
+
return false;
|
|
5
|
+
}
|
|
6
|
+
const contract = obj;
|
|
7
|
+
return typeof contract.ruleId === "string" && typeof contract.behavior === "string" && Array.isArray(contract.examples) && contract.examples.length > 0 && contract.examples.every(
|
|
8
|
+
(ex) => typeof ex === "object" && ex !== null && typeof ex.given === "string" && typeof ex.when === "string" && typeof ex.then === "string"
|
|
9
|
+
) && Array.isArray(contract.invariants) && contract.invariants.every((inv) => typeof inv === "string");
|
|
10
|
+
}
|
|
11
|
+
function defineContract(options) {
|
|
12
|
+
if (options.examples.length === 0) {
|
|
13
|
+
throw new Error("Contract must have at least one example");
|
|
14
|
+
}
|
|
15
|
+
if (options.assumptions) {
|
|
16
|
+
for (const assumption of options.assumptions) {
|
|
17
|
+
if (assumption.confidence < 0 || assumption.confidence > 1) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`Assumption '${assumption.id}' has invalid confidence value ${assumption.confidence}. Must be between 0.0 and 1.0`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
ruleId: options.ruleId,
|
|
26
|
+
behavior: options.behavior,
|
|
27
|
+
examples: options.examples,
|
|
28
|
+
invariants: options.invariants,
|
|
29
|
+
assumptions: options.assumptions,
|
|
30
|
+
references: options.references,
|
|
31
|
+
version: options.version || "1.0.0",
|
|
32
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function getContract(meta) {
|
|
36
|
+
if (!meta || !meta.contract) {
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
if (isContract(meta.contract)) {
|
|
40
|
+
return meta.contract;
|
|
41
|
+
}
|
|
42
|
+
return void 0;
|
|
43
|
+
}
|
|
44
|
+
function getContractFromDescriptor(descriptor) {
|
|
45
|
+
if (!descriptor) {
|
|
46
|
+
return void 0;
|
|
47
|
+
}
|
|
48
|
+
if (descriptor.contract && isContract(descriptor.contract)) {
|
|
49
|
+
return descriptor.contract;
|
|
50
|
+
}
|
|
51
|
+
return getContract(descriptor.meta);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export {
|
|
55
|
+
isContract,
|
|
56
|
+
defineContract,
|
|
57
|
+
getContract,
|
|
58
|
+
getContractFromDescriptor
|
|
59
|
+
};
|