@plures/praxis 1.2.0 → 1.2.11
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 +93 -96
- package/dist/browser/{adapter-TM4IS5KT.js → adapter-CIMBGDC7.js} +5 -3
- package/dist/browser/{chunk-LE2ZJYFC.js → chunk-K377RW4V.js} +76 -0
- package/dist/{node/chunk-JQ64KMLN.js → browser/chunk-MBVHLOU2.js} +12 -1
- package/dist/browser/index.d.ts +32 -5
- package/dist/browser/index.js +15 -7
- package/dist/browser/integrations/svelte.d.ts +2 -2
- package/dist/browser/integrations/svelte.js +1 -1
- package/dist/browser/{reactive-engine.svelte-C9OpcTHf.d.ts → reactive-engine.svelte-9aS0kTa8.d.ts} +136 -1
- package/dist/node/{adapter-K6DOX6XS.js → adapter-75ISSMWD.js} +5 -3
- package/dist/node/chunk-5RH7UAQC.js +486 -0
- package/dist/{browser/chunk-JQ64KMLN.js → node/chunk-MBVHLOU2.js} +12 -1
- package/dist/node/{chunk-LE2ZJYFC.js → chunk-PRPQO6R5.js} +3 -72
- package/dist/node/chunk-R2PSBPKQ.js +150 -0
- package/dist/node/chunk-WZ6B3LZ6.js +638 -0
- package/dist/node/cli/index.cjs +2316 -832
- package/dist/node/cli/index.js +18 -0
- package/dist/node/components/index.d.cts +3 -2
- package/dist/node/components/index.d.ts +3 -2
- package/dist/node/index.cjs +620 -38
- package/dist/node/index.d.cts +259 -5
- package/dist/node/index.d.ts +259 -5
- package/dist/node/index.js +55 -65
- package/dist/node/integrations/svelte.cjs +76 -0
- package/dist/node/integrations/svelte.d.cts +2 -2
- package/dist/node/integrations/svelte.d.ts +2 -2
- package/dist/node/integrations/svelte.js +2 -1
- package/dist/node/{reactive-engine.svelte-1M4m_C_v.d.cts → reactive-engine.svelte-BFIZfawz.d.cts} +199 -1
- package/dist/node/{reactive-engine.svelte-ChNFn4Hj.d.ts → reactive-engine.svelte-CRNqHlbv.d.ts} +199 -1
- package/dist/node/reverse-W7THPV45.js +193 -0
- package/dist/node/{terminal-adapter-CWka-yL8.d.ts → terminal-adapter-B-UK_Vdz.d.ts} +28 -3
- package/dist/node/{terminal-adapter-CDzxoLKR.d.cts → terminal-adapter-BQSIF5bf.d.cts} +28 -3
- package/dist/node/validate-CNHUULQE.js +180 -0
- package/docs/core/pluresdb-integration.md +15 -15
- package/docs/decision-ledger/BEHAVIOR_LEDGER.md +225 -0
- package/docs/decision-ledger/DecisionLedger.tla +180 -0
- package/docs/decision-ledger/IMPLEMENTATION_SUMMARY.md +217 -0
- package/docs/decision-ledger/LATEST.md +166 -0
- package/docs/guides/cicd-pipeline.md +142 -0
- package/package.json +2 -2
- package/src/__tests__/cli-validate.test.ts +197 -0
- package/src/__tests__/decision-ledger.test.ts +485 -0
- package/src/__tests__/reverse-generator.test.ts +189 -0
- package/src/__tests__/scanner.test.ts +215 -0
- package/src/cli/commands/reverse.ts +289 -0
- package/src/cli/commands/validate.ts +264 -0
- package/src/cli/index.ts +47 -0
- package/src/core/pluresdb/adapter.ts +45 -2
- package/src/core/rules.ts +133 -0
- package/src/decision-ledger/README.md +400 -0
- package/src/decision-ledger/REVERSE_ENGINEERING.md +484 -0
- package/src/decision-ledger/facts-events.ts +121 -0
- package/src/decision-ledger/index.ts +70 -0
- package/src/decision-ledger/ledger.ts +246 -0
- package/src/decision-ledger/logic-ledger.ts +158 -0
- package/src/decision-ledger/reverse-generator.ts +426 -0
- package/src/decision-ledger/scanner.ts +506 -0
- package/src/decision-ledger/types.ts +247 -0
- package/src/decision-ledger/validation.ts +336 -0
- package/src/dsl/index.ts +13 -2
- package/src/index.browser.ts +2 -0
- package/src/index.ts +36 -0
- package/src/integrations/pluresdb.ts +14 -2
package/dist/node/index.cjs
CHANGED
|
@@ -246,7 +246,8 @@ __export(adapter_exports, {
|
|
|
246
246
|
InMemoryPraxisDB: () => InMemoryPraxisDB,
|
|
247
247
|
PluresDBPraxisAdapter: () => PluresDBPraxisAdapter,
|
|
248
248
|
createInMemoryDB: () => createInMemoryDB,
|
|
249
|
-
createPluresDB: () => createPluresDB
|
|
249
|
+
createPluresDB: () => createPluresDB,
|
|
250
|
+
createPraxisLocalFirst: () => createPraxisLocalFirst
|
|
250
251
|
});
|
|
251
252
|
function createInMemoryDB() {
|
|
252
253
|
return new InMemoryPraxisDB();
|
|
@@ -254,6 +255,16 @@ function createInMemoryDB() {
|
|
|
254
255
|
function createPluresDB(config) {
|
|
255
256
|
return new PluresDBPraxisAdapter(config);
|
|
256
257
|
}
|
|
258
|
+
async function createPraxisLocalFirst(options = {}) {
|
|
259
|
+
const { pollInterval, ...localOptions } = options;
|
|
260
|
+
const mod = await import("@plures/pluresdb/local-first");
|
|
261
|
+
const LocalFirstCtor = mod.PluresDBLocalFirst ?? mod.default;
|
|
262
|
+
if (!LocalFirstCtor) {
|
|
263
|
+
throw new Error("Failed to load PluresDBLocalFirst from @plures/pluresdb/local-first");
|
|
264
|
+
}
|
|
265
|
+
const db = new LocalFirstCtor(localOptions);
|
|
266
|
+
return new PluresDBPraxisAdapter({ db, pollInterval });
|
|
267
|
+
}
|
|
257
268
|
var InMemoryPraxisDB, PluresDBPraxisAdapter;
|
|
258
269
|
var init_adapter = __esm({
|
|
259
270
|
"src/core/pluresdb/adapter.ts"() {
|
|
@@ -391,7 +402,14 @@ var init_adapter = __esm({
|
|
|
391
402
|
// src/index.ts
|
|
392
403
|
var src_exports = {};
|
|
393
404
|
__export(src_exports, {
|
|
405
|
+
AcknowledgeContractGap: () => AcknowledgeContractGap,
|
|
394
406
|
ActorManager: () => ActorManager,
|
|
407
|
+
BehaviorLedger: () => BehaviorLedger,
|
|
408
|
+
ContractAdded: () => ContractAdded,
|
|
409
|
+
ContractGapAcknowledged: () => ContractGapAcknowledged,
|
|
410
|
+
ContractMissing: () => ContractMissing,
|
|
411
|
+
ContractUpdated: () => ContractUpdated,
|
|
412
|
+
ContractValidated: () => ContractValidated,
|
|
395
413
|
FrameworkAgnosticReactiveEngine: () => ReactiveLogicEngine2,
|
|
396
414
|
InMemoryPraxisDB: () => InMemoryPraxisDB,
|
|
397
415
|
LogicEngine: () => LogicEngine,
|
|
@@ -406,6 +424,7 @@ __export(src_exports, {
|
|
|
406
424
|
RegistryIntrospector: () => RegistryIntrospector,
|
|
407
425
|
StateDocsGenerator: () => StateDocsGenerator,
|
|
408
426
|
TerminalAdapter: () => TerminalAdapter,
|
|
427
|
+
ValidateContracts: () => ValidateContracts,
|
|
409
428
|
attachAllIntegrations: () => attachAllIntegrations,
|
|
410
429
|
attachTauriToEngine: () => attachTauriToEngine,
|
|
411
430
|
attachToEngine: () => attachToEngine,
|
|
@@ -413,6 +432,7 @@ __export(src_exports, {
|
|
|
413
432
|
canvasToMermaid: () => canvasToMermaid,
|
|
414
433
|
canvasToSchema: () => canvasToSchema,
|
|
415
434
|
canvasToYaml: () => canvasToYaml,
|
|
435
|
+
createBehaviorLedger: () => createBehaviorLedger,
|
|
416
436
|
createCanvasEditor: () => createCanvasEditor,
|
|
417
437
|
createFrameworkAgnosticReactiveEngine: () => createReactiveEngine2,
|
|
418
438
|
createInMemoryDB: () => createInMemoryDB,
|
|
@@ -424,6 +444,7 @@ __export(src_exports, {
|
|
|
424
444
|
createPluresDBGenerator: () => createPluresDBGenerator,
|
|
425
445
|
createPraxisDBStore: () => createPraxisDBStore,
|
|
426
446
|
createPraxisEngine: () => createPraxisEngine,
|
|
447
|
+
createPraxisLocalFirst: () => createPraxisLocalFirst,
|
|
427
448
|
createReactiveEngine: () => createReactiveEngine,
|
|
428
449
|
createSchemaRegistry: () => createSchemaRegistry,
|
|
429
450
|
createSchemaTemplate: () => createSchemaTemplate,
|
|
@@ -434,6 +455,7 @@ __export(src_exports, {
|
|
|
434
455
|
createUnifiedApp: () => createUnifiedApp,
|
|
435
456
|
createUnumAdapter: () => createUnumAdapter,
|
|
436
457
|
defineConstraint: () => defineConstraint,
|
|
458
|
+
defineContract: () => defineContract,
|
|
437
459
|
defineEvent: () => defineEvent,
|
|
438
460
|
defineFact: () => defineFact,
|
|
439
461
|
defineModule: () => defineModule,
|
|
@@ -442,12 +464,17 @@ __export(src_exports, {
|
|
|
442
464
|
filterFacts: () => filterFacts,
|
|
443
465
|
findEvent: () => findEvent,
|
|
444
466
|
findFact: () => findFact,
|
|
467
|
+
formatValidationReport: () => formatValidationReport,
|
|
468
|
+
formatValidationReportJSON: () => formatValidationReportJSON,
|
|
469
|
+
formatValidationReportSARIF: () => formatValidationReportSARIF,
|
|
445
470
|
generateDocs: () => generateDocs,
|
|
446
471
|
generateId: () => generateId,
|
|
447
472
|
generateTauriConfig: () => generateTauriConfig,
|
|
473
|
+
getContract: () => getContract,
|
|
448
474
|
getEventPath: () => getEventPath,
|
|
449
475
|
getFactPath: () => getFactPath,
|
|
450
476
|
getSchemaPath: () => getSchemaPath,
|
|
477
|
+
isContract: () => isContract,
|
|
451
478
|
loadSchema: () => loadSchema,
|
|
452
479
|
loadSchemaFromFile: () => loadSchemaFromFile,
|
|
453
480
|
loadSchemaFromJson: () => loadSchemaFromJson,
|
|
@@ -455,6 +482,7 @@ __export(src_exports, {
|
|
|
455
482
|
registerSchema: () => registerSchema,
|
|
456
483
|
runTerminalCommand: () => runTerminalCommand,
|
|
457
484
|
schemaToCanvas: () => schemaToCanvas,
|
|
485
|
+
validateContracts: () => validateContracts,
|
|
458
486
|
validateForGeneration: () => validateForGeneration,
|
|
459
487
|
validateSchema: () => validateSchema,
|
|
460
488
|
validateWithGuardian: () => validateWithGuardian
|
|
@@ -466,6 +494,17 @@ init_protocol();
|
|
|
466
494
|
var PraxisRegistry = class {
|
|
467
495
|
rules = /* @__PURE__ */ new Map();
|
|
468
496
|
constraints = /* @__PURE__ */ new Map();
|
|
497
|
+
compliance;
|
|
498
|
+
contractGaps = [];
|
|
499
|
+
constructor(options = {}) {
|
|
500
|
+
const defaultEnabled = typeof process !== "undefined" ? process.env?.NODE_ENV !== "production" : false;
|
|
501
|
+
this.compliance = {
|
|
502
|
+
enabled: defaultEnabled,
|
|
503
|
+
requiredFields: ["behavior", "examples", "invariants"],
|
|
504
|
+
missingSeverity: "warning",
|
|
505
|
+
...options.compliance
|
|
506
|
+
};
|
|
507
|
+
}
|
|
469
508
|
/**
|
|
470
509
|
* Register a rule
|
|
471
510
|
*/
|
|
@@ -474,6 +513,7 @@ var PraxisRegistry = class {
|
|
|
474
513
|
throw new Error(`Rule with id "${descriptor.id}" already registered`);
|
|
475
514
|
}
|
|
476
515
|
this.rules.set(descriptor.id, descriptor);
|
|
516
|
+
this.trackContractCompliance(descriptor.id, descriptor);
|
|
477
517
|
}
|
|
478
518
|
/**
|
|
479
519
|
* Register a constraint
|
|
@@ -483,6 +523,7 @@ var PraxisRegistry = class {
|
|
|
483
523
|
throw new Error(`Constraint with id "${descriptor.id}" already registered`);
|
|
484
524
|
}
|
|
485
525
|
this.constraints.set(descriptor.id, descriptor);
|
|
526
|
+
this.trackContractCompliance(descriptor.id, descriptor);
|
|
486
527
|
}
|
|
487
528
|
/**
|
|
488
529
|
* Register a module (all its rules and constraints)
|
|
@@ -531,6 +572,69 @@ var PraxisRegistry = class {
|
|
|
531
572
|
getAllConstraints() {
|
|
532
573
|
return Array.from(this.constraints.values());
|
|
533
574
|
}
|
|
575
|
+
/**
|
|
576
|
+
* Get collected contract gaps from registration-time validation.
|
|
577
|
+
*/
|
|
578
|
+
getContractGaps() {
|
|
579
|
+
return [...this.contractGaps];
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Clear collected contract gaps.
|
|
583
|
+
*/
|
|
584
|
+
clearContractGaps() {
|
|
585
|
+
this.contractGaps = [];
|
|
586
|
+
}
|
|
587
|
+
trackContractCompliance(id, descriptor) {
|
|
588
|
+
if (!this.compliance.enabled) {
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
const gaps = this.validateDescriptorContract(id, descriptor);
|
|
592
|
+
for (const gap of gaps) {
|
|
593
|
+
this.contractGaps.push(gap);
|
|
594
|
+
if (this.compliance.onGap) {
|
|
595
|
+
this.compliance.onGap(gap);
|
|
596
|
+
} else {
|
|
597
|
+
const label = gap.severity === "error" ? "ERROR" : gap.severity === "warning" ? "WARN" : "INFO";
|
|
598
|
+
console.warn(`[Praxis][${label}] Contract gap for "${gap.ruleId}": missing ${gap.missing.join(", ")}`);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
validateDescriptorContract(id, descriptor) {
|
|
603
|
+
const requiredFields = this.compliance.requiredFields ?? ["behavior", "examples", "invariants"];
|
|
604
|
+
const missingSeverity = this.compliance.missingSeverity ?? "warning";
|
|
605
|
+
const contract = descriptor.contract ?? (descriptor.meta?.contract && typeof descriptor.meta.contract === "object" ? descriptor.meta.contract : void 0);
|
|
606
|
+
if (!contract) {
|
|
607
|
+
return [
|
|
608
|
+
{
|
|
609
|
+
ruleId: id,
|
|
610
|
+
missing: ["contract"],
|
|
611
|
+
severity: missingSeverity,
|
|
612
|
+
message: `Contract missing for "${id}"`
|
|
613
|
+
}
|
|
614
|
+
];
|
|
615
|
+
}
|
|
616
|
+
const missing = [];
|
|
617
|
+
if (requiredFields.includes("behavior") && (!contract.behavior || contract.behavior.trim() === "")) {
|
|
618
|
+
missing.push("behavior");
|
|
619
|
+
}
|
|
620
|
+
if (requiredFields.includes("examples") && (!contract.examples || contract.examples.length === 0)) {
|
|
621
|
+
missing.push("examples");
|
|
622
|
+
}
|
|
623
|
+
if (requiredFields.includes("invariants") && (!contract.invariants || contract.invariants.length === 0)) {
|
|
624
|
+
missing.push("invariants");
|
|
625
|
+
}
|
|
626
|
+
if (missing.length === 0) {
|
|
627
|
+
return [];
|
|
628
|
+
}
|
|
629
|
+
return [
|
|
630
|
+
{
|
|
631
|
+
ruleId: id,
|
|
632
|
+
missing,
|
|
633
|
+
severity: "warning",
|
|
634
|
+
message: `Contract for "${id}" is incomplete: missing ${missing.join(", ")}`
|
|
635
|
+
}
|
|
636
|
+
];
|
|
637
|
+
}
|
|
534
638
|
};
|
|
535
639
|
|
|
536
640
|
// src/index.ts
|
|
@@ -1175,19 +1279,25 @@ function defineEvent(tag) {
|
|
|
1175
1279
|
};
|
|
1176
1280
|
}
|
|
1177
1281
|
function defineRule(options) {
|
|
1282
|
+
const contract = options.contract ?? options.meta?.contract;
|
|
1283
|
+
const meta = contract ? { ...options.meta ?? {}, contract } : options.meta;
|
|
1178
1284
|
return {
|
|
1179
1285
|
id: options.id,
|
|
1180
1286
|
description: options.description,
|
|
1181
1287
|
impl: options.impl,
|
|
1182
|
-
|
|
1288
|
+
contract,
|
|
1289
|
+
meta
|
|
1183
1290
|
};
|
|
1184
1291
|
}
|
|
1185
1292
|
function defineConstraint(options) {
|
|
1293
|
+
const contract = options.contract ?? options.meta?.contract;
|
|
1294
|
+
const meta = contract ? { ...options.meta ?? {}, contract } : options.meta;
|
|
1186
1295
|
return {
|
|
1187
1296
|
id: options.id,
|
|
1188
1297
|
description: options.description,
|
|
1189
1298
|
impl: options.impl,
|
|
1190
|
-
|
|
1299
|
+
contract,
|
|
1300
|
+
meta
|
|
1191
1301
|
};
|
|
1192
1302
|
}
|
|
1193
1303
|
function defineModule(options) {
|
|
@@ -1210,6 +1320,461 @@ function findFact(facts, definition) {
|
|
|
1210
1320
|
return facts.find(definition.is);
|
|
1211
1321
|
}
|
|
1212
1322
|
|
|
1323
|
+
// src/decision-ledger/types.ts
|
|
1324
|
+
function isContract(obj) {
|
|
1325
|
+
if (typeof obj !== "object" || obj === null) {
|
|
1326
|
+
return false;
|
|
1327
|
+
}
|
|
1328
|
+
const contract = obj;
|
|
1329
|
+
return typeof contract.ruleId === "string" && typeof contract.behavior === "string" && Array.isArray(contract.examples) && contract.examples.length > 0 && contract.examples.every(
|
|
1330
|
+
(ex) => typeof ex === "object" && ex !== null && typeof ex.given === "string" && typeof ex.when === "string" && typeof ex.then === "string"
|
|
1331
|
+
) && Array.isArray(contract.invariants) && contract.invariants.every((inv) => typeof inv === "string");
|
|
1332
|
+
}
|
|
1333
|
+
function defineContract(options) {
|
|
1334
|
+
if (options.examples.length === 0) {
|
|
1335
|
+
throw new Error("Contract must have at least one example");
|
|
1336
|
+
}
|
|
1337
|
+
if (options.assumptions) {
|
|
1338
|
+
for (const assumption of options.assumptions) {
|
|
1339
|
+
if (assumption.confidence < 0 || assumption.confidence > 1) {
|
|
1340
|
+
throw new Error(
|
|
1341
|
+
`Assumption '${assumption.id}' has invalid confidence value ${assumption.confidence}. Must be between 0.0 and 1.0`
|
|
1342
|
+
);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
return {
|
|
1347
|
+
ruleId: options.ruleId,
|
|
1348
|
+
behavior: options.behavior,
|
|
1349
|
+
examples: options.examples,
|
|
1350
|
+
invariants: options.invariants,
|
|
1351
|
+
assumptions: options.assumptions,
|
|
1352
|
+
references: options.references,
|
|
1353
|
+
version: options.version || "1.0.0",
|
|
1354
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
function getContract(meta) {
|
|
1358
|
+
if (!meta || !meta.contract) {
|
|
1359
|
+
return void 0;
|
|
1360
|
+
}
|
|
1361
|
+
if (isContract(meta.contract)) {
|
|
1362
|
+
return meta.contract;
|
|
1363
|
+
}
|
|
1364
|
+
return void 0;
|
|
1365
|
+
}
|
|
1366
|
+
function getContractFromDescriptor(descriptor) {
|
|
1367
|
+
if (!descriptor) {
|
|
1368
|
+
return void 0;
|
|
1369
|
+
}
|
|
1370
|
+
if (descriptor.contract && isContract(descriptor.contract)) {
|
|
1371
|
+
return descriptor.contract;
|
|
1372
|
+
}
|
|
1373
|
+
return getContract(descriptor.meta);
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
// src/decision-ledger/facts-events.ts
|
|
1377
|
+
var ContractMissing = defineFact("ContractMissing");
|
|
1378
|
+
var ContractValidated = defineFact("ContractValidated");
|
|
1379
|
+
var AcknowledgeContractGap = defineEvent("ACKNOWLEDGE_CONTRACT_GAP");
|
|
1380
|
+
var ValidateContracts = defineEvent("VALIDATE_CONTRACTS");
|
|
1381
|
+
var ContractGapAcknowledged = defineFact("ContractGapAcknowledged");
|
|
1382
|
+
var ContractAdded = defineEvent("CONTRACT_ADDED");
|
|
1383
|
+
var ContractUpdated = defineEvent("CONTRACT_UPDATED");
|
|
1384
|
+
var ContractGapEmitted = defineEvent("CONTRACT_GAP_EMITTED");
|
|
1385
|
+
|
|
1386
|
+
// src/decision-ledger/validation.ts
|
|
1387
|
+
function validateContracts(registry, options = {}) {
|
|
1388
|
+
const {
|
|
1389
|
+
incompleteSeverity = "warning",
|
|
1390
|
+
requiredFields = ["behavior", "examples"],
|
|
1391
|
+
artifactIndex
|
|
1392
|
+
} = options;
|
|
1393
|
+
const complete = [];
|
|
1394
|
+
const incomplete = [];
|
|
1395
|
+
const missing = [];
|
|
1396
|
+
for (const rule of registry.getAllRules()) {
|
|
1397
|
+
const contract = getContractFromDescriptor(rule);
|
|
1398
|
+
if (!contract) {
|
|
1399
|
+
missing.push(rule.id);
|
|
1400
|
+
if (options.missingSeverity) {
|
|
1401
|
+
incomplete.push({
|
|
1402
|
+
ruleId: rule.id,
|
|
1403
|
+
missing: ["contract"],
|
|
1404
|
+
severity: options.missingSeverity,
|
|
1405
|
+
message: `Rule '${rule.id}' has no contract`
|
|
1406
|
+
});
|
|
1407
|
+
}
|
|
1408
|
+
continue;
|
|
1409
|
+
}
|
|
1410
|
+
const gaps = validateContract(contract, requiredFields, artifactIndex);
|
|
1411
|
+
if (gaps.length > 0) {
|
|
1412
|
+
incomplete.push({
|
|
1413
|
+
ruleId: rule.id,
|
|
1414
|
+
missing: gaps,
|
|
1415
|
+
severity: incompleteSeverity,
|
|
1416
|
+
message: `Rule '${rule.id}' contract is incomplete: missing ${gaps.join(", ")}`
|
|
1417
|
+
});
|
|
1418
|
+
} else {
|
|
1419
|
+
complete.push({ ruleId: rule.id, contract });
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
for (const constraint of registry.getAllConstraints()) {
|
|
1423
|
+
const contract = getContractFromDescriptor(constraint);
|
|
1424
|
+
if (!contract) {
|
|
1425
|
+
missing.push(constraint.id);
|
|
1426
|
+
if (options.missingSeverity) {
|
|
1427
|
+
incomplete.push({
|
|
1428
|
+
ruleId: constraint.id,
|
|
1429
|
+
missing: ["contract"],
|
|
1430
|
+
severity: options.missingSeverity,
|
|
1431
|
+
message: `Constraint '${constraint.id}' has no contract`
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
continue;
|
|
1435
|
+
}
|
|
1436
|
+
const gaps = validateContract(contract, requiredFields, artifactIndex);
|
|
1437
|
+
if (gaps.length > 0) {
|
|
1438
|
+
incomplete.push({
|
|
1439
|
+
ruleId: constraint.id,
|
|
1440
|
+
missing: gaps,
|
|
1441
|
+
severity: incompleteSeverity,
|
|
1442
|
+
message: `Constraint '${constraint.id}' contract is incomplete: missing ${gaps.join(", ")}`
|
|
1443
|
+
});
|
|
1444
|
+
} else {
|
|
1445
|
+
complete.push({ ruleId: constraint.id, contract });
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
const total = registry.getAllRules().length + registry.getAllConstraints().length;
|
|
1449
|
+
return {
|
|
1450
|
+
complete,
|
|
1451
|
+
incomplete,
|
|
1452
|
+
missing,
|
|
1453
|
+
total,
|
|
1454
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1457
|
+
function validateContract(contract, requiredFields, artifactIndex) {
|
|
1458
|
+
const missing = [];
|
|
1459
|
+
if (requiredFields.includes("behavior") && isFieldEmpty(contract.behavior)) {
|
|
1460
|
+
missing.push("behavior");
|
|
1461
|
+
}
|
|
1462
|
+
if (requiredFields.includes("examples") && (!contract.examples || contract.examples.length === 0)) {
|
|
1463
|
+
missing.push("examples");
|
|
1464
|
+
}
|
|
1465
|
+
if (requiredFields.includes("invariants") && (!contract.invariants || contract.invariants.length === 0)) {
|
|
1466
|
+
missing.push("invariants");
|
|
1467
|
+
}
|
|
1468
|
+
if (artifactIndex?.tests && !artifactIndex.tests.has(contract.ruleId)) {
|
|
1469
|
+
missing.push("tests");
|
|
1470
|
+
}
|
|
1471
|
+
if (artifactIndex?.spec && !artifactIndex.spec.has(contract.ruleId)) {
|
|
1472
|
+
missing.push("spec");
|
|
1473
|
+
}
|
|
1474
|
+
return missing;
|
|
1475
|
+
}
|
|
1476
|
+
function isFieldEmpty(value) {
|
|
1477
|
+
return !value || value.trim() === "";
|
|
1478
|
+
}
|
|
1479
|
+
function formatValidationReport(report) {
|
|
1480
|
+
const lines = [];
|
|
1481
|
+
lines.push("Contract Validation Report");
|
|
1482
|
+
lines.push("=".repeat(50));
|
|
1483
|
+
lines.push("");
|
|
1484
|
+
lines.push(`Total: ${report.total}`);
|
|
1485
|
+
lines.push(`Complete: ${report.complete.length}`);
|
|
1486
|
+
lines.push(`Incomplete: ${report.incomplete.length}`);
|
|
1487
|
+
lines.push(`Missing: ${report.missing.length}`);
|
|
1488
|
+
lines.push("");
|
|
1489
|
+
if (report.complete.length > 0) {
|
|
1490
|
+
lines.push("\u2713 Complete Contracts:");
|
|
1491
|
+
for (const { ruleId, contract } of report.complete) {
|
|
1492
|
+
lines.push(` \u2713 ${ruleId} (v${contract.version || "1.0.0"})`);
|
|
1493
|
+
}
|
|
1494
|
+
lines.push("");
|
|
1495
|
+
}
|
|
1496
|
+
if (report.incomplete.length > 0) {
|
|
1497
|
+
lines.push("\u2717 Incomplete Contracts:");
|
|
1498
|
+
for (const gap of report.incomplete) {
|
|
1499
|
+
const icon = gap.severity === "error" ? "\u2717" : gap.severity === "warning" ? "\u26A0" : "\u2139";
|
|
1500
|
+
lines.push(` ${icon} ${gap.ruleId} - Missing: ${gap.missing.join(", ")}`);
|
|
1501
|
+
if (gap.message) {
|
|
1502
|
+
lines.push(` ${gap.message}`);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
lines.push("");
|
|
1506
|
+
}
|
|
1507
|
+
if (report.missing.length > 0) {
|
|
1508
|
+
lines.push("\u2717 No Contract:");
|
|
1509
|
+
for (const ruleId of report.missing) {
|
|
1510
|
+
lines.push(` \u2717 ${ruleId}`);
|
|
1511
|
+
}
|
|
1512
|
+
lines.push("");
|
|
1513
|
+
}
|
|
1514
|
+
lines.push(`Validated at: ${report.timestamp}`);
|
|
1515
|
+
return lines.join("\n");
|
|
1516
|
+
}
|
|
1517
|
+
function formatValidationReportJSON(report) {
|
|
1518
|
+
return JSON.stringify(report, null, 2);
|
|
1519
|
+
}
|
|
1520
|
+
function formatValidationReportSARIF(report) {
|
|
1521
|
+
const results = report.incomplete.map((gap) => {
|
|
1522
|
+
const primaryMissing = gap.missing.length > 0 ? gap.missing[0] : "contract";
|
|
1523
|
+
return {
|
|
1524
|
+
ruleId: `decision-ledger/${primaryMissing}`,
|
|
1525
|
+
level: gap.severity === "error" ? "error" : gap.severity === "warning" ? "warning" : "note",
|
|
1526
|
+
message: {
|
|
1527
|
+
text: gap.message || `Missing: ${gap.missing.join(", ")}`
|
|
1528
|
+
},
|
|
1529
|
+
locations: [
|
|
1530
|
+
{
|
|
1531
|
+
physicalLocation: {
|
|
1532
|
+
artifactLocation: {
|
|
1533
|
+
uri: "registry"
|
|
1534
|
+
},
|
|
1535
|
+
region: {
|
|
1536
|
+
startLine: 1
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
],
|
|
1541
|
+
properties: {
|
|
1542
|
+
ruleId: gap.ruleId,
|
|
1543
|
+
missing: gap.missing
|
|
1544
|
+
}
|
|
1545
|
+
};
|
|
1546
|
+
});
|
|
1547
|
+
const sarif = {
|
|
1548
|
+
version: "2.1.0",
|
|
1549
|
+
$schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
|
|
1550
|
+
runs: [
|
|
1551
|
+
{
|
|
1552
|
+
tool: {
|
|
1553
|
+
driver: {
|
|
1554
|
+
name: "Praxis Decision Ledger",
|
|
1555
|
+
version: "1.0.0",
|
|
1556
|
+
informationUri: "https://github.com/plures/praxis",
|
|
1557
|
+
rules: [
|
|
1558
|
+
{
|
|
1559
|
+
id: "decision-ledger/contract",
|
|
1560
|
+
shortDescription: {
|
|
1561
|
+
text: "Rule or constraint missing contract"
|
|
1562
|
+
}
|
|
1563
|
+
},
|
|
1564
|
+
{
|
|
1565
|
+
id: "decision-ledger/behavior",
|
|
1566
|
+
shortDescription: {
|
|
1567
|
+
text: "Contract missing behavior description"
|
|
1568
|
+
}
|
|
1569
|
+
},
|
|
1570
|
+
{
|
|
1571
|
+
id: "decision-ledger/examples",
|
|
1572
|
+
shortDescription: {
|
|
1573
|
+
text: "Contract missing examples"
|
|
1574
|
+
}
|
|
1575
|
+
},
|
|
1576
|
+
{
|
|
1577
|
+
id: "decision-ledger/invariants",
|
|
1578
|
+
shortDescription: {
|
|
1579
|
+
text: "Contract missing invariants"
|
|
1580
|
+
}
|
|
1581
|
+
},
|
|
1582
|
+
{
|
|
1583
|
+
id: "decision-ledger/tests",
|
|
1584
|
+
shortDescription: {
|
|
1585
|
+
text: "Contract missing tests"
|
|
1586
|
+
}
|
|
1587
|
+
},
|
|
1588
|
+
{
|
|
1589
|
+
id: "decision-ledger/spec",
|
|
1590
|
+
shortDescription: {
|
|
1591
|
+
text: "Contract missing spec"
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
]
|
|
1595
|
+
}
|
|
1596
|
+
},
|
|
1597
|
+
results
|
|
1598
|
+
}
|
|
1599
|
+
]
|
|
1600
|
+
};
|
|
1601
|
+
return JSON.stringify(sarif, null, 2);
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
// src/decision-ledger/ledger.ts
|
|
1605
|
+
var BehaviorLedger = class _BehaviorLedger {
|
|
1606
|
+
entries = [];
|
|
1607
|
+
entryMap = /* @__PURE__ */ new Map();
|
|
1608
|
+
/**
|
|
1609
|
+
* Append a new entry to the ledger.
|
|
1610
|
+
*
|
|
1611
|
+
* @param entry The entry to append
|
|
1612
|
+
* @throws Error if entry ID already exists
|
|
1613
|
+
*/
|
|
1614
|
+
append(entry) {
|
|
1615
|
+
if (this.entryMap.has(entry.id)) {
|
|
1616
|
+
throw new Error(`Ledger entry with ID '${entry.id}' already exists`);
|
|
1617
|
+
}
|
|
1618
|
+
if (entry.supersedes) {
|
|
1619
|
+
const superseded = this.entryMap.get(entry.supersedes);
|
|
1620
|
+
if (superseded && superseded.status === "active") {
|
|
1621
|
+
const updatedEntry = {
|
|
1622
|
+
...superseded,
|
|
1623
|
+
status: "superseded"
|
|
1624
|
+
};
|
|
1625
|
+
this.entryMap.set(entry.supersedes, updatedEntry);
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
this.entries.push(entry);
|
|
1629
|
+
this.entryMap.set(entry.id, entry);
|
|
1630
|
+
}
|
|
1631
|
+
/**
|
|
1632
|
+
* Get an entry by ID.
|
|
1633
|
+
*
|
|
1634
|
+
* @param id The entry ID
|
|
1635
|
+
* @returns The entry, or undefined if not found
|
|
1636
|
+
*/
|
|
1637
|
+
getEntry(id) {
|
|
1638
|
+
return this.entryMap.get(id);
|
|
1639
|
+
}
|
|
1640
|
+
/**
|
|
1641
|
+
* Get all entries (in order of append) with current status.
|
|
1642
|
+
*
|
|
1643
|
+
* @returns Array of all entries with current status from the map
|
|
1644
|
+
*/
|
|
1645
|
+
getAllEntries() {
|
|
1646
|
+
return this.entries.map((entry) => this.entryMap.get(entry.id));
|
|
1647
|
+
}
|
|
1648
|
+
/**
|
|
1649
|
+
* Get entries for a specific rule ID.
|
|
1650
|
+
*
|
|
1651
|
+
* @param ruleId The rule ID
|
|
1652
|
+
* @returns Array of entries for this rule with current status
|
|
1653
|
+
*/
|
|
1654
|
+
getEntriesForRule(ruleId) {
|
|
1655
|
+
return this.entries.map((entry) => this.entryMap.get(entry.id)).filter((entry) => entry.contract.ruleId === ruleId);
|
|
1656
|
+
}
|
|
1657
|
+
/**
|
|
1658
|
+
* Get the latest active entry for a rule.
|
|
1659
|
+
*
|
|
1660
|
+
* @param ruleId The rule ID
|
|
1661
|
+
* @returns The latest active entry, or undefined if none
|
|
1662
|
+
*/
|
|
1663
|
+
getLatestEntry(ruleId) {
|
|
1664
|
+
const entries = this.getEntriesForRule(ruleId);
|
|
1665
|
+
const activeEntries = entries.filter((entry) => entry.status === "active");
|
|
1666
|
+
if (activeEntries.length === 0) {
|
|
1667
|
+
return void 0;
|
|
1668
|
+
}
|
|
1669
|
+
return activeEntries[activeEntries.length - 1];
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* Get all active assumptions across all entries.
|
|
1673
|
+
*
|
|
1674
|
+
* @returns Map of assumption ID to assumption
|
|
1675
|
+
*/
|
|
1676
|
+
getActiveAssumptions() {
|
|
1677
|
+
const assumptions = /* @__PURE__ */ new Map();
|
|
1678
|
+
for (const entry of this.entries) {
|
|
1679
|
+
const currentEntry = this.entryMap.get(entry.id);
|
|
1680
|
+
if (currentEntry.status !== "active") {
|
|
1681
|
+
continue;
|
|
1682
|
+
}
|
|
1683
|
+
for (const assumption of currentEntry.contract.assumptions || []) {
|
|
1684
|
+
if (assumption.status === "active") {
|
|
1685
|
+
assumptions.set(assumption.id, assumption);
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
return assumptions;
|
|
1690
|
+
}
|
|
1691
|
+
/**
|
|
1692
|
+
* Find assumptions that impact a specific artifact type.
|
|
1693
|
+
*
|
|
1694
|
+
* @param impactType The artifact type ('spec', 'tests', 'code')
|
|
1695
|
+
* @returns Array of assumptions
|
|
1696
|
+
*/
|
|
1697
|
+
findAssumptionsByImpact(impactType) {
|
|
1698
|
+
const assumptions = [];
|
|
1699
|
+
for (const entry of this.entries) {
|
|
1700
|
+
const currentEntry = this.entryMap.get(entry.id);
|
|
1701
|
+
if (currentEntry.status !== "active") {
|
|
1702
|
+
continue;
|
|
1703
|
+
}
|
|
1704
|
+
for (const assumption of currentEntry.contract.assumptions || []) {
|
|
1705
|
+
if (assumption.status === "active" && assumption.impacts.includes(impactType)) {
|
|
1706
|
+
assumptions.push(assumption);
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
return assumptions;
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* Get ledger statistics.
|
|
1714
|
+
*/
|
|
1715
|
+
getStats() {
|
|
1716
|
+
const currentEntries = this.entries.map((e) => this.entryMap.get(e.id));
|
|
1717
|
+
const active = currentEntries.filter((e) => e.status === "active").length;
|
|
1718
|
+
const superseded = currentEntries.filter((e) => e.status === "superseded").length;
|
|
1719
|
+
const deprecated = currentEntries.filter((e) => e.status === "deprecated").length;
|
|
1720
|
+
const uniqueRules = new Set(currentEntries.map((e) => e.contract.ruleId)).size;
|
|
1721
|
+
return {
|
|
1722
|
+
totalEntries: this.entries.length,
|
|
1723
|
+
activeEntries: active,
|
|
1724
|
+
supersededEntries: superseded,
|
|
1725
|
+
deprecatedEntries: deprecated,
|
|
1726
|
+
uniqueRules
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Export ledger as JSON.
|
|
1731
|
+
*
|
|
1732
|
+
* @returns JSON string with current entry status
|
|
1733
|
+
*/
|
|
1734
|
+
toJSON() {
|
|
1735
|
+
return JSON.stringify(
|
|
1736
|
+
{
|
|
1737
|
+
version: "1.0.0",
|
|
1738
|
+
// Export entries with current status from the map
|
|
1739
|
+
entries: this.entries.map((entry) => this.entryMap.get(entry.id)),
|
|
1740
|
+
stats: this.getStats()
|
|
1741
|
+
},
|
|
1742
|
+
null,
|
|
1743
|
+
2
|
|
1744
|
+
);
|
|
1745
|
+
}
|
|
1746
|
+
/**
|
|
1747
|
+
* Import ledger from JSON.
|
|
1748
|
+
*
|
|
1749
|
+
* Note: The JSON must contain entries in the order they were originally appended.
|
|
1750
|
+
* If a superseding entry appears before the entry it supersedes, the superseding
|
|
1751
|
+
* logic will not work correctly. The toJSON method preserves this order.
|
|
1752
|
+
*
|
|
1753
|
+
* @param json The JSON string
|
|
1754
|
+
* @returns A new BehaviorLedger instance
|
|
1755
|
+
*/
|
|
1756
|
+
static fromJSON(json) {
|
|
1757
|
+
const data = JSON.parse(json);
|
|
1758
|
+
const ledger = new _BehaviorLedger();
|
|
1759
|
+
for (const entry of data.entries || []) {
|
|
1760
|
+
ledger.append(entry);
|
|
1761
|
+
}
|
|
1762
|
+
return ledger;
|
|
1763
|
+
}
|
|
1764
|
+
};
|
|
1765
|
+
function createBehaviorLedger() {
|
|
1766
|
+
return new BehaviorLedger();
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
// src/decision-ledger/logic-ledger.ts
|
|
1770
|
+
var import_node_crypto = require("crypto");
|
|
1771
|
+
var import_node_fs = require("fs");
|
|
1772
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
1773
|
+
|
|
1774
|
+
// src/decision-ledger/scanner.ts
|
|
1775
|
+
var import_node_fs2 = require("fs");
|
|
1776
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
1777
|
+
|
|
1213
1778
|
// src/runtime/terminal-adapter.ts
|
|
1214
1779
|
async function defaultExecutor(command, options) {
|
|
1215
1780
|
try {
|
|
@@ -1330,15 +1895,15 @@ var TerminalAdapter = class {
|
|
|
1330
1895
|
* @param path - PluresDB path for storing results
|
|
1331
1896
|
* @param data - Data to sync
|
|
1332
1897
|
*/
|
|
1333
|
-
async syncToPluresDB(
|
|
1898
|
+
async syncToPluresDB(path3, data) {
|
|
1334
1899
|
if (!this.db) return;
|
|
1335
1900
|
try {
|
|
1336
|
-
await this.db.set(
|
|
1901
|
+
await this.db.set(path3, {
|
|
1337
1902
|
...data,
|
|
1338
1903
|
nodeId: this.state.nodeId,
|
|
1339
1904
|
syncedAt: Date.now()
|
|
1340
1905
|
});
|
|
1341
|
-
const historyPath = `${
|
|
1906
|
+
const historyPath = `${path3}/history`;
|
|
1342
1907
|
const historyKey = `${historyPath}/${data.timestamp}`;
|
|
1343
1908
|
await this.db.set(historyKey, data);
|
|
1344
1909
|
} catch (error) {
|
|
@@ -1807,8 +2372,8 @@ var PraxisDBStore = class {
|
|
|
1807
2372
|
async persistFact(fact) {
|
|
1808
2373
|
const payload = fact.payload;
|
|
1809
2374
|
const id = payload?.id ?? generateId();
|
|
1810
|
-
const
|
|
1811
|
-
await this.db.set(
|
|
2375
|
+
const path3 = getFactPath(fact.tag, id);
|
|
2376
|
+
await this.db.set(path3, fact);
|
|
1812
2377
|
}
|
|
1813
2378
|
/**
|
|
1814
2379
|
* Get a fact by tag and id
|
|
@@ -1818,8 +2383,8 @@ var PraxisDBStore = class {
|
|
|
1818
2383
|
* @returns The fact or undefined if not found
|
|
1819
2384
|
*/
|
|
1820
2385
|
async getFact(factTag, id) {
|
|
1821
|
-
const
|
|
1822
|
-
return this.db.get(
|
|
2386
|
+
const path3 = getFactPath(factTag, id);
|
|
2387
|
+
return this.db.get(path3);
|
|
1823
2388
|
}
|
|
1824
2389
|
/**
|
|
1825
2390
|
* Append an event to the event stream
|
|
@@ -1829,15 +2394,15 @@ var PraxisDBStore = class {
|
|
|
1829
2394
|
* @param event The event to append
|
|
1830
2395
|
*/
|
|
1831
2396
|
async appendEvent(event) {
|
|
1832
|
-
const
|
|
1833
|
-
const existingEvents = await this.db.get(
|
|
2397
|
+
const path3 = getEventPath(event.tag);
|
|
2398
|
+
const existingEvents = await this.db.get(path3) ?? [];
|
|
1834
2399
|
const entry = {
|
|
1835
2400
|
event,
|
|
1836
2401
|
timestamp: Date.now(),
|
|
1837
2402
|
sequence: existingEvents.length
|
|
1838
2403
|
};
|
|
1839
2404
|
const newEvents = [...existingEvents, entry];
|
|
1840
|
-
await this.db.set(
|
|
2405
|
+
await this.db.set(path3, newEvents);
|
|
1841
2406
|
await this.triggerRulesForEvents([event]);
|
|
1842
2407
|
}
|
|
1843
2408
|
/**
|
|
@@ -1852,15 +2417,15 @@ var PraxisDBStore = class {
|
|
|
1852
2417
|
eventsByTag.set(event.tag, [...existing, event]);
|
|
1853
2418
|
}
|
|
1854
2419
|
for (const [tag, tagEvents] of eventsByTag) {
|
|
1855
|
-
const
|
|
1856
|
-
const existingEvents = await this.db.get(
|
|
2420
|
+
const path3 = getEventPath(tag);
|
|
2421
|
+
const existingEvents = await this.db.get(path3) ?? [];
|
|
1857
2422
|
let sequence = existingEvents.length;
|
|
1858
2423
|
const newEntries = tagEvents.map((event) => ({
|
|
1859
2424
|
event,
|
|
1860
2425
|
timestamp: Date.now(),
|
|
1861
2426
|
sequence: sequence++
|
|
1862
2427
|
}));
|
|
1863
|
-
await this.db.set(
|
|
2428
|
+
await this.db.set(path3, [...existingEvents, ...newEntries]);
|
|
1864
2429
|
}
|
|
1865
2430
|
await this.triggerRulesForEvents(events);
|
|
1866
2431
|
}
|
|
@@ -1872,8 +2437,8 @@ var PraxisDBStore = class {
|
|
|
1872
2437
|
* @returns Array of event stream entries
|
|
1873
2438
|
*/
|
|
1874
2439
|
async getEvents(eventTag, options) {
|
|
1875
|
-
const
|
|
1876
|
-
const events = await this.db.get(
|
|
2440
|
+
const path3 = getEventPath(eventTag);
|
|
2441
|
+
const events = await this.db.get(path3) ?? [];
|
|
1877
2442
|
let result = events;
|
|
1878
2443
|
if (options?.since !== void 0) {
|
|
1879
2444
|
const sinceTimestamp = options.since;
|
|
@@ -1892,7 +2457,7 @@ var PraxisDBStore = class {
|
|
|
1892
2457
|
* @returns Unsubscribe function
|
|
1893
2458
|
*/
|
|
1894
2459
|
watchFacts(factTag, callback) {
|
|
1895
|
-
const
|
|
2460
|
+
const path3 = getFactPath(factTag);
|
|
1896
2461
|
if (!this.factWatchers.has(factTag)) {
|
|
1897
2462
|
this.factWatchers.set(factTag, /* @__PURE__ */ new Set());
|
|
1898
2463
|
}
|
|
@@ -1900,7 +2465,7 @@ var PraxisDBStore = class {
|
|
|
1900
2465
|
if (watchers) {
|
|
1901
2466
|
watchers.add(callback);
|
|
1902
2467
|
}
|
|
1903
|
-
const unsubscribe = this.db.watch(
|
|
2468
|
+
const unsubscribe = this.db.watch(path3, (fact) => {
|
|
1904
2469
|
callback([fact]);
|
|
1905
2470
|
});
|
|
1906
2471
|
this.subscriptions.push(unsubscribe);
|
|
@@ -2024,13 +2589,13 @@ var PraxisSchemaRegistry = class {
|
|
|
2024
2589
|
* @param schema The schema to register
|
|
2025
2590
|
*/
|
|
2026
2591
|
async register(schema) {
|
|
2027
|
-
const
|
|
2592
|
+
const path3 = getSchemaPath(schema.name);
|
|
2028
2593
|
const storedSchema = {
|
|
2029
2594
|
schema,
|
|
2030
2595
|
registeredAt: Date.now(),
|
|
2031
2596
|
version: schema.version
|
|
2032
2597
|
};
|
|
2033
|
-
await this.db.set(
|
|
2598
|
+
await this.db.set(path3, storedSchema);
|
|
2034
2599
|
}
|
|
2035
2600
|
/**
|
|
2036
2601
|
* Get a schema by name
|
|
@@ -2039,8 +2604,8 @@ var PraxisSchemaRegistry = class {
|
|
|
2039
2604
|
* @returns The stored schema or undefined if not found
|
|
2040
2605
|
*/
|
|
2041
2606
|
async get(schemaName) {
|
|
2042
|
-
const
|
|
2043
|
-
return this.db.get(
|
|
2607
|
+
const path3 = getSchemaPath(schemaName);
|
|
2608
|
+
return this.db.get(path3);
|
|
2044
2609
|
}
|
|
2045
2610
|
/**
|
|
2046
2611
|
* Check if a schema is registered
|
|
@@ -3348,29 +3913,29 @@ function createMockTauriBridge() {
|
|
|
3348
3913
|
tauriVersion: "mock"
|
|
3349
3914
|
},
|
|
3350
3915
|
fs: {
|
|
3351
|
-
async readFile(
|
|
3352
|
-
const data = storage.get(
|
|
3916
|
+
async readFile(path3) {
|
|
3917
|
+
const data = storage.get(path3);
|
|
3353
3918
|
if (data instanceof Uint8Array) return data;
|
|
3354
|
-
throw new Error(`File not found: ${
|
|
3919
|
+
throw new Error(`File not found: ${path3}`);
|
|
3355
3920
|
},
|
|
3356
|
-
async readTextFile(
|
|
3357
|
-
const data = storage.get(
|
|
3921
|
+
async readTextFile(path3) {
|
|
3922
|
+
const data = storage.get(path3);
|
|
3358
3923
|
if (typeof data === "string") return data;
|
|
3359
|
-
throw new Error(`File not found: ${
|
|
3924
|
+
throw new Error(`File not found: ${path3}`);
|
|
3360
3925
|
},
|
|
3361
|
-
async writeFile(
|
|
3362
|
-
storage.set(
|
|
3926
|
+
async writeFile(path3, data) {
|
|
3927
|
+
storage.set(path3, data);
|
|
3363
3928
|
},
|
|
3364
|
-
async writeTextFile(
|
|
3365
|
-
storage.set(
|
|
3929
|
+
async writeTextFile(path3, data) {
|
|
3930
|
+
storage.set(path3, data);
|
|
3366
3931
|
},
|
|
3367
|
-
async exists(
|
|
3368
|
-
return storage.has(
|
|
3932
|
+
async exists(path3) {
|
|
3933
|
+
return storage.has(path3);
|
|
3369
3934
|
},
|
|
3370
3935
|
async mkdir(_path, _options) {
|
|
3371
3936
|
},
|
|
3372
|
-
async remove(
|
|
3373
|
-
storage.delete(
|
|
3937
|
+
async remove(path3, _options) {
|
|
3938
|
+
storage.delete(path3);
|
|
3374
3939
|
},
|
|
3375
3940
|
async rename(oldPath, newPath) {
|
|
3376
3941
|
const data = storage.get(oldPath);
|
|
@@ -3690,7 +4255,14 @@ async function attachAllIntegrations(engine, registry, options = {}) {
|
|
|
3690
4255
|
}
|
|
3691
4256
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3692
4257
|
0 && (module.exports = {
|
|
4258
|
+
AcknowledgeContractGap,
|
|
3693
4259
|
ActorManager,
|
|
4260
|
+
BehaviorLedger,
|
|
4261
|
+
ContractAdded,
|
|
4262
|
+
ContractGapAcknowledged,
|
|
4263
|
+
ContractMissing,
|
|
4264
|
+
ContractUpdated,
|
|
4265
|
+
ContractValidated,
|
|
3694
4266
|
FrameworkAgnosticReactiveEngine,
|
|
3695
4267
|
InMemoryPraxisDB,
|
|
3696
4268
|
LogicEngine,
|
|
@@ -3705,6 +4277,7 @@ async function attachAllIntegrations(engine, registry, options = {}) {
|
|
|
3705
4277
|
RegistryIntrospector,
|
|
3706
4278
|
StateDocsGenerator,
|
|
3707
4279
|
TerminalAdapter,
|
|
4280
|
+
ValidateContracts,
|
|
3708
4281
|
attachAllIntegrations,
|
|
3709
4282
|
attachTauriToEngine,
|
|
3710
4283
|
attachToEngine,
|
|
@@ -3712,6 +4285,7 @@ async function attachAllIntegrations(engine, registry, options = {}) {
|
|
|
3712
4285
|
canvasToMermaid,
|
|
3713
4286
|
canvasToSchema,
|
|
3714
4287
|
canvasToYaml,
|
|
4288
|
+
createBehaviorLedger,
|
|
3715
4289
|
createCanvasEditor,
|
|
3716
4290
|
createFrameworkAgnosticReactiveEngine,
|
|
3717
4291
|
createInMemoryDB,
|
|
@@ -3723,6 +4297,7 @@ async function attachAllIntegrations(engine, registry, options = {}) {
|
|
|
3723
4297
|
createPluresDBGenerator,
|
|
3724
4298
|
createPraxisDBStore,
|
|
3725
4299
|
createPraxisEngine,
|
|
4300
|
+
createPraxisLocalFirst,
|
|
3726
4301
|
createReactiveEngine,
|
|
3727
4302
|
createSchemaRegistry,
|
|
3728
4303
|
createSchemaTemplate,
|
|
@@ -3733,6 +4308,7 @@ async function attachAllIntegrations(engine, registry, options = {}) {
|
|
|
3733
4308
|
createUnifiedApp,
|
|
3734
4309
|
createUnumAdapter,
|
|
3735
4310
|
defineConstraint,
|
|
4311
|
+
defineContract,
|
|
3736
4312
|
defineEvent,
|
|
3737
4313
|
defineFact,
|
|
3738
4314
|
defineModule,
|
|
@@ -3741,12 +4317,17 @@ async function attachAllIntegrations(engine, registry, options = {}) {
|
|
|
3741
4317
|
filterFacts,
|
|
3742
4318
|
findEvent,
|
|
3743
4319
|
findFact,
|
|
4320
|
+
formatValidationReport,
|
|
4321
|
+
formatValidationReportJSON,
|
|
4322
|
+
formatValidationReportSARIF,
|
|
3744
4323
|
generateDocs,
|
|
3745
4324
|
generateId,
|
|
3746
4325
|
generateTauriConfig,
|
|
4326
|
+
getContract,
|
|
3747
4327
|
getEventPath,
|
|
3748
4328
|
getFactPath,
|
|
3749
4329
|
getSchemaPath,
|
|
4330
|
+
isContract,
|
|
3750
4331
|
loadSchema,
|
|
3751
4332
|
loadSchemaFromFile,
|
|
3752
4333
|
loadSchemaFromJson,
|
|
@@ -3754,6 +4335,7 @@ async function attachAllIntegrations(engine, registry, options = {}) {
|
|
|
3754
4335
|
registerSchema,
|
|
3755
4336
|
runTerminalCommand,
|
|
3756
4337
|
schemaToCanvas,
|
|
4338
|
+
validateContracts,
|
|
3757
4339
|
validateForGeneration,
|
|
3758
4340
|
validateSchema,
|
|
3759
4341
|
validateWithGuardian
|