@a-company/paradigm 3.28.0 → 3.43.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/{accept-orchestration-6EM5EHXA.js → accept-orchestration-ZUWQUHSK.js} +6 -6
- package/dist/add-VSPZ6FM4.js +81 -0
- package/dist/{aggregate-M5WMUI6B.js → aggregate-SV3VGEIL.js} +2 -2
- package/dist/assess-UHBDYIK7.js +68 -0
- package/dist/{beacon-XL2ALH5O.js → beacon-3SJV4DAP.js} +2 -2
- package/dist/calibration-WWHK73WU.js +135 -0
- package/dist/{chunk-C5ZE6WEX.js → chunk-2SKXFXIT.js} +91 -1
- package/dist/{chunk-AK5M6KJB.js → chunk-36TKPM5Z.js} +20 -2
- package/dist/{chunk-W4VFKZVF.js → chunk-7COU5S2Z.js} +3 -3
- package/dist/{chunk-3BAMPB6I.js → chunk-7WEKMZ46.js} +2 -147
- package/dist/{chunk-SCC77UUP.js → chunk-AKIMFN6I.js} +3 -3
- package/dist/{chunk-3DYYXGDC.js → chunk-CDMAMDSG.js} +33 -0
- package/dist/{chunk-7IJ5JVKT.js → chunk-CZEIK3Y2.js} +913 -40
- package/dist/{chunk-MRENOFTR.js → chunk-EDOAWN7J.js} +6 -1
- package/dist/chunk-F3BCHPYT.js +143 -0
- package/dist/chunk-GT5QGC2H.js +253 -0
- package/dist/{chunk-N6RNYCZD.js → chunk-HIKKOCXY.js} +1 -1
- package/dist/{chunk-J26YQVAK.js → chunk-J4E6K5MG.js} +1 -1
- package/dist/chunk-L27I3CPZ.js +357 -0
- package/dist/{chunk-KWDTBXP2.js → chunk-LHLIAYQ3.js} +1 -1
- package/dist/{chunk-OXG5GVDJ.js → chunk-P7XSBJE3.js} +1 -1
- package/dist/{chunk-Z7W7HNRG.js → chunk-QDXI2DHR.js} +1 -1
- package/dist/{chunk-BRILIG7Z.js → chunk-QIOCFXDQ.js} +42 -0
- package/dist/{chunk-ZOH24ZPF.js → chunk-QWA26UNO.js} +7 -7
- package/dist/{lore-server-ILPHKWLK.js → chunk-RAB5IKPR.js} +77 -112
- package/dist/{chunk-BKMNLROM.js → chunk-RGFANZ4Q.js} +448 -147
- package/dist/{chunk-R2SGQ22F.js → chunk-YW5OCVKB.js} +448 -2
- package/dist/{chunk-6P4IFIK2.js → chunk-ZGUAAVMA.js} +53 -4
- package/dist/{commands-6ZVTD74M.js → commands-LEPFD7S5.js} +452 -1
- package/dist/config-schema-3YNIFJCJ.js +152 -0
- package/dist/{constellation-NXU6Q2HM.js → constellation-FAGT45TU.js} +2 -2
- package/dist/{context-audit-RI4R2WRH.js → context-audit-557EO6PK.js} +138 -8
- package/dist/{cost-CTGSLSOC.js → cost-UD3WPEKZ.js} +1 -1
- package/dist/{cursorrules-XBWFX66V.js → cursorrules-3TKZ4E4R.js} +2 -2
- package/dist/{delete-YTASL4SM.js → delete-RRK4RL6Y.js} +1 -1
- package/dist/{diff-AH7L4PRQ.js → diff-IP5CIARP.js} +6 -6
- package/dist/{dist-AG5JNIZU-HW2FWNTZ.js → dist-5QE2BB2B-X6DYVSUL.js} +59 -5
- package/dist/{dist-KY5HGDDL.js → dist-OGTSAZ55.js} +58 -4
- package/dist/{dist-IKBGY7FQ.js → dist-RVKYUCRU.js} +3 -1
- package/dist/{dist-7U64HDSC.js → dist-UXWV4OKX.js} +8 -2
- package/dist/{dist-RMAIFRTW.js → dist-Y7I3CFY5.js} +5 -3
- package/dist/{doctor-INBOLZC7.js → doctor-GKZJU7QG.js} +1 -1
- package/dist/{edit-S7NZD7H7.js → edit-4CLNN5JG.js} +1 -1
- package/dist/{graph-ERNQQQ7C.js → graph-YYUXI3F7.js} +1 -1
- package/dist/graph-server-ZPXRSGCW.js +116 -0
- package/dist/{habits-7BORPC2F.js → habits-O37HTUKE.js} +2 -2
- package/dist/index.js +207 -89
- package/dist/integrity-MK2OP5TA.js +194 -0
- package/dist/integrity-checker-J7YXRTBT.js +11 -0
- package/dist/{lint-53GPXKKI.js → lint-HYWGS3JJ.js} +1 -1
- package/dist/{list-QTFWN35D.js → list-BTLFHSRC.js} +1 -1
- package/dist/list-IUCYPGMK.js +57 -0
- package/dist/{lore-loader-S5BXMH27.js → lore-loader-VTEEZDX3.js} +3 -1
- package/dist/lore-server-NOOAHKJX.js +118 -0
- package/dist/mcp.js +2616 -112
- package/dist/migrate-FQVGQNXZ.js +889 -0
- package/dist/{migrate-assessments-FPR6C35Z.js → migrate-assessments-JP6Q5KME.js} +1 -1
- package/dist/{orchestrate-HMSQ2CED.js → orchestrate-A226N6FC.js} +6 -6
- package/dist/platform-server-KK4OCRTV.js +891 -0
- package/dist/{probe-SN4BNXOC.js → probe-7JK7IDNI.js} +5 -5
- package/dist/{providers-YW3FG6DA.js → providers-YNFSL6HK.js} +1 -1
- package/dist/quiz-I75NU2QQ.js +99 -0
- package/dist/{record-UGN75GTB.js → record-46CLR4OG.js} +11 -2
- package/dist/{reindex-YG3KIXAK.js → reindex-NZQRGKPN.js} +3 -2
- package/dist/{remember-IEBQHXHZ.js → remember-4EUZKIIB.js} +1 -1
- package/dist/{retag-URLJLMSK.js → retag-KC4JVRLE.js} +1 -1
- package/dist/{review-725ZKA7U.js → review-Q7M4CRB5.js} +1 -1
- package/dist/{ripple-DFMXLFWI.js → ripple-RI3LOT6R.js} +2 -2
- package/dist/{sentinel-FUR3QKCJ.js → sentinel-BKYTBT7M.js} +1 -1
- package/dist/sentinel-bridge-IZTXYS5M.js +109 -0
- package/dist/sentinel-ui/assets/{index-Zh1YM0C9.css → index-CJ1Wx083.css} +1 -1
- package/dist/sentinel-ui/assets/index-S1VJ67dT.js +62 -0
- package/dist/sentinel-ui/assets/index-S1VJ67dT.js.map +1 -0
- package/dist/sentinel-ui/index.html +2 -2
- package/dist/sentinel.js +6 -6
- package/dist/{serve-DIALBCTU.js → serve-22A4XOIG.js} +1 -1
- package/dist/{university-A66BMZ4Z.js → serve-2YJ6D2Y6.js} +9 -8
- package/dist/serve-3V2WXLGM.js +33 -0
- package/dist/{server-2VICPDUR.js → server-OFEJ2HJP.js} +25 -2
- package/dist/{server-OWBK2WFS.js → server-RDLQ3DK7.js} +49 -4
- package/dist/{setup-HOI52TN3.js → setup-M2ZKLKNN.js} +4 -4
- package/dist/{shift-DRF5M3G6.js → shift-LNMKFYLR.js} +73 -14
- package/dist/{show-GEVVQWWG.js → show-P7GYO43X.js} +1 -1
- package/dist/show-PKZMYKRN.js +82 -0
- package/dist/{snapshot-XHINQBZS.js → snapshot-Y3COXK4T.js} +2 -2
- package/dist/{spawn-DIY7T4QW.js → spawn-SSXZX45U.js} +2 -2
- package/dist/status-KLHALGW4.js +71 -0
- package/dist/{summary-NV7SBV5O.js → summary-5NQNOD3F.js} +2 -2
- package/dist/{sweep-5POCF2E4.js → sweep-EZU3GU6S.js} +1 -1
- package/dist/symphony-ROEKK7VD.js +999 -0
- package/dist/{team-YOGT2Q2X.js → team-HGLJXWQG.js} +7 -7
- package/dist/{timeline-RKXNRMKF.js → timeline-ANC7LVDL.js} +1 -1
- package/dist/{triage-GJ6GK647.js → triage-POXJ2TIX.js} +2 -2
- package/dist/university-content/courses/.purpose +7 -1
- package/dist/university-content/courses/para-101.json +53 -0
- package/dist/university-content/courses/para-501.json +166 -0
- package/dist/university-content/plsat/.purpose +6 -0
- package/dist/university-content/plsat/v3.0.json +400 -1
- package/dist/university-content/reference.json +48 -0
- package/dist/university-ui/assets/{index-TcsCEBMo.js → index-tfi5xN4Q.js} +2 -2
- package/dist/university-ui/assets/{index-TcsCEBMo.js.map → index-tfi5xN4Q.js.map} +1 -1
- package/dist/university-ui/index.html +1 -1
- package/dist/{upgrade-65QOQXRC.js → upgrade-ANX3LVSA.js} +1 -0
- package/dist/validate-GD5XWILV.js +134 -0
- package/dist/{validate-TKKRGJKC.js → validate-ZVPNN4FL.js} +1 -1
- package/dist/{workspace-L27RR5MF.js → workspace-UIUTHZTD.js} +6 -6
- package/package.json +4 -2
- package/platform-ui/dist/assets/GitSection-C-GQWHcu.css +1 -0
- package/platform-ui/dist/assets/GitSection-DvyJBF_-.js +4 -0
- package/platform-ui/dist/assets/GraphSection-BiQrXqfs.js +8 -0
- package/platform-ui/dist/assets/GraphSection-BlgXTl53.css +1 -0
- package/platform-ui/dist/assets/LoreSection-BaH1FaRb.js +1 -0
- package/platform-ui/dist/assets/LoreSection-C3EixkjW.css +1 -0
- package/platform-ui/dist/assets/SentinelSection-BI-aIYKL.css +1 -0
- package/platform-ui/dist/assets/SentinelSection-DemAznjI.js +1 -0
- package/platform-ui/dist/assets/index-CfpZFjea.css +1 -0
- package/platform-ui/dist/assets/index-DDKhCt-w.js +57 -0
- package/platform-ui/dist/index.html +14 -0
- package/dist/graph-server-BZ73HTAT.js +0 -251
- package/dist/sentinel-ui/assets/index-C_Wstm64.js +0 -62
- package/dist/sentinel-ui/assets/index-C_Wstm64.js.map +0 -1
- /package/dist/{chunk-5SXMV4SP.js → chunk-FS3WTUHY.js} +0 -0
|
@@ -2,12 +2,17 @@
|
|
|
2
2
|
import {
|
|
3
3
|
loadLoreEntries,
|
|
4
4
|
loadLoreEntry
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-CDMAMDSG.js";
|
|
6
|
+
import {
|
|
7
|
+
checkComponentAnchors,
|
|
8
|
+
checkIntegrity,
|
|
9
|
+
checkPurposeHealth
|
|
10
|
+
} from "./chunk-L27I3CPZ.js";
|
|
6
11
|
|
|
7
12
|
// ../paradigm-mcp/src/tools/reindex.ts
|
|
8
|
-
import * as
|
|
9
|
-
import * as
|
|
10
|
-
import * as
|
|
13
|
+
import * as fs9 from "fs";
|
|
14
|
+
import * as path10 from "path";
|
|
15
|
+
import * as yaml8 from "js-yaml";
|
|
11
16
|
|
|
12
17
|
// ../premise/core/dist/index.js
|
|
13
18
|
import * as yaml3 from "js-yaml";
|
|
@@ -22,6 +27,12 @@ import * as path from "path";
|
|
|
22
27
|
import { glob } from "glob";
|
|
23
28
|
var PurposeItemSchema = z.object({
|
|
24
29
|
description: z.string(),
|
|
30
|
+
// Component type and hierarchy (v4)
|
|
31
|
+
type: z.string().optional(),
|
|
32
|
+
parent: z.string().optional(),
|
|
33
|
+
anchors: z.array(z.string()).optional(),
|
|
34
|
+
tags: z.array(z.string()).optional(),
|
|
35
|
+
// Standard fields
|
|
25
36
|
endpoints: z.array(z.string()).optional(),
|
|
26
37
|
tests: z.array(z.string()).optional(),
|
|
27
38
|
rules: z.record(z.unknown()).optional(),
|
|
@@ -33,7 +44,6 @@ var PurposeItemSchema = z.object({
|
|
|
33
44
|
states: z.array(z.string()).optional(),
|
|
34
45
|
components: z.array(z.string()).optional(),
|
|
35
46
|
// Extra fields preserved
|
|
36
|
-
tags: z.array(z.string()).optional(),
|
|
37
47
|
location: z.string().optional(),
|
|
38
48
|
locations: z.array(z.string()).optional(),
|
|
39
49
|
uses: z.array(z.string()).optional(),
|
|
@@ -620,6 +630,138 @@ function validatePurposeItem(id, item, itemType, prefix, issues) {
|
|
|
620
630
|
}
|
|
621
631
|
}
|
|
622
632
|
}
|
|
633
|
+
function validateCrossFile(allFiles) {
|
|
634
|
+
const issues = [];
|
|
635
|
+
const definedSymbols = /* @__PURE__ */ new Set();
|
|
636
|
+
for (const { data } of allFiles) {
|
|
637
|
+
const components = normalizeToEntries(data.components);
|
|
638
|
+
for (const [id] of components) {
|
|
639
|
+
definedSymbols.add(`#${id}`);
|
|
640
|
+
definedSymbols.add(id);
|
|
641
|
+
}
|
|
642
|
+
const features = normalizeToEntries(data.features);
|
|
643
|
+
for (const [id] of features) {
|
|
644
|
+
definedSymbols.add(`#${id}`);
|
|
645
|
+
definedSymbols.add(id);
|
|
646
|
+
}
|
|
647
|
+
if (data.gates) {
|
|
648
|
+
for (const id of Object.keys(data.gates)) {
|
|
649
|
+
definedSymbols.add(`^${id}`);
|
|
650
|
+
definedSymbols.add(id);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (data.signals) {
|
|
654
|
+
for (const id of Object.keys(data.signals)) {
|
|
655
|
+
definedSymbols.add(`!${id}`);
|
|
656
|
+
definedSymbols.add(id);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (data.flows) {
|
|
660
|
+
if (Array.isArray(data.flows)) {
|
|
661
|
+
for (const flow of data.flows) {
|
|
662
|
+
if (flow?.name) {
|
|
663
|
+
definedSymbols.add(`$${flow.name}`);
|
|
664
|
+
definedSymbols.add(flow.name);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
} else {
|
|
668
|
+
for (const id of Object.keys(data.flows)) {
|
|
669
|
+
definedSymbols.add(`$${id}`);
|
|
670
|
+
definedSymbols.add(id);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
if (data.aspects) {
|
|
675
|
+
for (const id of Object.keys(data.aspects)) {
|
|
676
|
+
definedSymbols.add(`~${id}`);
|
|
677
|
+
definedSymbols.add(id);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
if (data.states) {
|
|
681
|
+
for (const id of Object.keys(data.states)) {
|
|
682
|
+
definedSymbols.add(`#${id}`);
|
|
683
|
+
definedSymbols.add(id);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
for (const { filePath, data } of allFiles) {
|
|
688
|
+
const prefix = filePath ? `${filePath}: ` : "";
|
|
689
|
+
const allEntries = [
|
|
690
|
+
...normalizeToEntries(data.components),
|
|
691
|
+
...normalizeToEntries(data.features)
|
|
692
|
+
];
|
|
693
|
+
for (const [id, item] of allEntries) {
|
|
694
|
+
if (item.parent) {
|
|
695
|
+
const parentRef = item.parent.replace(/^["']|["']$/g, "");
|
|
696
|
+
const bareRef = parentRef.replace(/^[#$^!~@%?&]/, "");
|
|
697
|
+
if (!definedSymbols.has(parentRef) && !definedSymbols.has(bareRef)) {
|
|
698
|
+
issues.push({
|
|
699
|
+
type: "warning",
|
|
700
|
+
message: `${prefix}Component "${id}" references parent "${parentRef}" which is not defined in any .purpose file`,
|
|
701
|
+
path: `components.${id}.parent`
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
const refLists = [
|
|
706
|
+
{ field: "gates", refs: item.gates },
|
|
707
|
+
{ field: "signals", refs: item.signals },
|
|
708
|
+
{ field: "flows", refs: item.flows },
|
|
709
|
+
{ field: "components", refs: item.components },
|
|
710
|
+
{ field: "aspects", refs: item.aspects }
|
|
711
|
+
];
|
|
712
|
+
for (const { field, refs } of refLists) {
|
|
713
|
+
if (!refs) continue;
|
|
714
|
+
for (const ref of refs) {
|
|
715
|
+
const bareRef = ref.replace(/^[#$^!~@%?&]/, "");
|
|
716
|
+
if (!definedSymbols.has(ref) && !definedSymbols.has(bareRef)) {
|
|
717
|
+
issues.push({
|
|
718
|
+
type: "warning",
|
|
719
|
+
message: `${prefix}Symbol "${id}" references ${field} "${ref}" which is not defined`,
|
|
720
|
+
path: `components.${id}.${field}`
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
if (data.flows) {
|
|
727
|
+
if (Array.isArray(data.flows)) {
|
|
728
|
+
for (const flow of data.flows) {
|
|
729
|
+
if (!flow?.steps) continue;
|
|
730
|
+
for (const step of flow.steps) {
|
|
731
|
+
if (typeof step === "string" || !step?.component) continue;
|
|
732
|
+
const bareRef = step.component.replace(/^#/, "");
|
|
733
|
+
if (!definedSymbols.has(step.component) && !definedSymbols.has(bareRef)) {
|
|
734
|
+
issues.push({
|
|
735
|
+
type: "warning",
|
|
736
|
+
message: `${prefix}Flow "${flow.name}" step references "${step.component}" which is not defined`,
|
|
737
|
+
path: `flows.${flow.name}.steps`
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
} else {
|
|
743
|
+
for (const [flowId, flowDef] of Object.entries(data.flows)) {
|
|
744
|
+
if (!flowDef?.steps) continue;
|
|
745
|
+
for (const step of flowDef.steps) {
|
|
746
|
+
if (typeof step === "string" || !step?.component) continue;
|
|
747
|
+
const bareRef = step.component.replace(/^#/, "");
|
|
748
|
+
if (!definedSymbols.has(step.component) && !definedSymbols.has(bareRef)) {
|
|
749
|
+
issues.push({
|
|
750
|
+
type: "warning",
|
|
751
|
+
message: `${prefix}Flow "${flowId}" step references "${step.component}" which is not defined`,
|
|
752
|
+
path: `flows.${flowId}.steps`
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
return {
|
|
761
|
+
valid: issues.filter((i) => i.type === "error").length === 0,
|
|
762
|
+
issues
|
|
763
|
+
};
|
|
764
|
+
}
|
|
623
765
|
|
|
624
766
|
// ../portal/core/dist/index.js
|
|
625
767
|
import * as fs2 from "fs";
|
|
@@ -847,6 +989,7 @@ async function aggregateFromPremise(premiseFile, rootDir) {
|
|
|
847
989
|
purposeFiles.push(...parsed.map((p) => p.filePath));
|
|
848
990
|
const features = extractFeatures(parsed);
|
|
849
991
|
for (const [id, { item, filePath }] of features) {
|
|
992
|
+
const featureTags = ["feature", ...item.tags || []];
|
|
850
993
|
symbols.push(createSymbolEntry({
|
|
851
994
|
id: `purpose-feature-${id}`,
|
|
852
995
|
symbol: `#${id}`,
|
|
@@ -855,7 +998,10 @@ async function aggregateFromPremise(premiseFile, rootDir) {
|
|
|
855
998
|
filePath,
|
|
856
999
|
data: item,
|
|
857
1000
|
description: item.description,
|
|
858
|
-
tags:
|
|
1001
|
+
tags: featureTags,
|
|
1002
|
+
componentType: item.type,
|
|
1003
|
+
parentSymbol: item.parent,
|
|
1004
|
+
anchors: item.anchors?.map((a) => parseAnchorString(a))
|
|
859
1005
|
}));
|
|
860
1006
|
}
|
|
861
1007
|
const components = extractComponents(parsed);
|
|
@@ -867,7 +1013,11 @@ async function aggregateFromPremise(premiseFile, rootDir) {
|
|
|
867
1013
|
source: "purpose",
|
|
868
1014
|
filePath,
|
|
869
1015
|
data: item,
|
|
870
|
-
description: item.description
|
|
1016
|
+
description: item.description,
|
|
1017
|
+
tags: item.tags,
|
|
1018
|
+
componentType: item.type,
|
|
1019
|
+
parentSymbol: item.parent,
|
|
1020
|
+
anchors: item.anchors?.map((a) => parseAnchorString(a))
|
|
871
1021
|
}));
|
|
872
1022
|
}
|
|
873
1023
|
const gates = extractGates(parsed);
|
|
@@ -1033,12 +1183,27 @@ async function aggregateFromPremise(premiseFile, rootDir) {
|
|
|
1033
1183
|
}));
|
|
1034
1184
|
}
|
|
1035
1185
|
resolveReferences(symbols);
|
|
1186
|
+
const symbolFileMap = /* @__PURE__ */ new Map();
|
|
1187
|
+
for (const sym of symbols) {
|
|
1188
|
+
const files = symbolFileMap.get(sym.symbol) || [];
|
|
1189
|
+
if (!files.includes(sym.filePath)) {
|
|
1190
|
+
files.push(sym.filePath);
|
|
1191
|
+
}
|
|
1192
|
+
symbolFileMap.set(sym.symbol, files);
|
|
1193
|
+
}
|
|
1194
|
+
const duplicateSymbols = [];
|
|
1195
|
+
for (const [symbol, files] of symbolFileMap) {
|
|
1196
|
+
if (files.length > 1) {
|
|
1197
|
+
duplicateSymbols.push({ symbol, files });
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1036
1200
|
return {
|
|
1037
1201
|
symbols,
|
|
1038
1202
|
purposeFiles,
|
|
1039
1203
|
portalFiles,
|
|
1040
1204
|
errors,
|
|
1041
|
-
timestamp: Date.now()
|
|
1205
|
+
timestamp: Date.now(),
|
|
1206
|
+
...duplicateSymbols.length > 0 ? { duplicateSymbols } : {}
|
|
1042
1207
|
};
|
|
1043
1208
|
}
|
|
1044
1209
|
function createSymbolEntry(partial) {
|
|
@@ -1191,6 +1356,11 @@ function searchSymbols(index, query) {
|
|
|
1191
1356
|
}
|
|
1192
1357
|
if (entry.tags?.some((tag) => tag.toLowerCase().includes(lowerQuery))) {
|
|
1193
1358
|
results.push(entry);
|
|
1359
|
+
continue;
|
|
1360
|
+
}
|
|
1361
|
+
if (entry.componentType?.toLowerCase().includes(lowerQuery)) {
|
|
1362
|
+
results.push(entry);
|
|
1363
|
+
continue;
|
|
1194
1364
|
}
|
|
1195
1365
|
}
|
|
1196
1366
|
return results;
|
|
@@ -1258,6 +1428,20 @@ function generateScanIndex(input, options) {
|
|
|
1258
1428
|
}
|
|
1259
1429
|
}
|
|
1260
1430
|
}
|
|
1431
|
+
const typeCounts = {};
|
|
1432
|
+
for (const comp of Object.values(index.components)) {
|
|
1433
|
+
if (comp.componentType) {
|
|
1434
|
+
typeCounts[comp.componentType] = (typeCounts[comp.componentType] || 0) + 1;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
for (const feat of Object.values(index.features)) {
|
|
1438
|
+
if (feat.componentType) {
|
|
1439
|
+
typeCounts[feat.componentType] = (typeCounts[feat.componentType] || 0) + 1;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
if (Object.keys(typeCounts).length > 0) {
|
|
1443
|
+
index.$meta.componentTypes = typeCounts;
|
|
1444
|
+
}
|
|
1261
1445
|
buildScreenReferences(index);
|
|
1262
1446
|
return index;
|
|
1263
1447
|
}
|
|
@@ -1313,7 +1497,9 @@ function addComponent(symbol, index, options) {
|
|
|
1313
1497
|
path: symbol.filePath,
|
|
1314
1498
|
description: symbol.description,
|
|
1315
1499
|
visualTags,
|
|
1316
|
-
related: symbol.references
|
|
1500
|
+
related: symbol.references,
|
|
1501
|
+
componentType: symbol.componentType,
|
|
1502
|
+
parent: symbol.parentSymbol
|
|
1317
1503
|
};
|
|
1318
1504
|
index.components[id] = element;
|
|
1319
1505
|
index.symbolMap[symbol.symbol] = { category: "components", id };
|
|
@@ -1329,7 +1515,9 @@ function addFeature(symbol, index, options) {
|
|
|
1329
1515
|
path: symbol.filePath,
|
|
1330
1516
|
description: symbol.description,
|
|
1331
1517
|
visualTags,
|
|
1332
|
-
related: symbol.references
|
|
1518
|
+
related: symbol.references,
|
|
1519
|
+
componentType: symbol.componentType,
|
|
1520
|
+
parent: symbol.parentSymbol
|
|
1333
1521
|
};
|
|
1334
1522
|
index.features[id] = element;
|
|
1335
1523
|
index.symbolMap[symbol.symbol] = { category: "features", id };
|
|
@@ -1997,8 +2185,8 @@ var SessionTracker = class {
|
|
|
1997
2185
|
* Extract resource type from URI
|
|
1998
2186
|
*/
|
|
1999
2187
|
extractResourceType(uri) {
|
|
2000
|
-
const
|
|
2001
|
-
const firstPart =
|
|
2188
|
+
const path11 = uri.replace("paradigm://", "");
|
|
2189
|
+
const firstPart = path11.split("/")[0];
|
|
2002
2190
|
return firstPart || "unknown";
|
|
2003
2191
|
}
|
|
2004
2192
|
/**
|
|
@@ -2752,7 +2940,7 @@ async function buildRecoveryPreamble(rootDir) {
|
|
|
2752
2940
|
} catch {
|
|
2753
2941
|
}
|
|
2754
2942
|
try {
|
|
2755
|
-
const { loadLoreEntries: loadLoreEntries2 } = await import("./lore-loader-
|
|
2943
|
+
const { loadLoreEntries: loadLoreEntries2 } = await import("./lore-loader-VTEEZDX3.js");
|
|
2756
2944
|
const arcEntries = await loadLoreEntries2(rootDir, { limit: 10 });
|
|
2757
2945
|
const entriesWithArcs = arcEntries.filter((e) => e.tags?.some((t) => t.startsWith("arc:")));
|
|
2758
2946
|
if (entriesWithArcs.length > 0) {
|
|
@@ -4136,8 +4324,8 @@ async function getAffectedPersonas(rootDir, symbol) {
|
|
|
4136
4324
|
}
|
|
4137
4325
|
return results;
|
|
4138
4326
|
}
|
|
4139
|
-
function deepGet(obj,
|
|
4140
|
-
const parts =
|
|
4327
|
+
function deepGet(obj, path11) {
|
|
4328
|
+
const parts = path11.split(/[.\[\]]+/).filter(Boolean);
|
|
4141
4329
|
let current = obj;
|
|
4142
4330
|
for (const part of parts) {
|
|
4143
4331
|
if (current == null || typeof current !== "object") return void 0;
|
|
@@ -4217,7 +4405,7 @@ function assertStep(step, event) {
|
|
|
4217
4405
|
async function validateAgainstSentinel(persona, options = {}) {
|
|
4218
4406
|
const steps = [];
|
|
4219
4407
|
try {
|
|
4220
|
-
const { SentinelStorage } = await import("./dist-
|
|
4408
|
+
const { SentinelStorage } = await import("./dist-RVKYUCRU.js");
|
|
4221
4409
|
const storage = new SentinelStorage();
|
|
4222
4410
|
const events = storage.queryEvents?.({
|
|
4223
4411
|
schemaId: "paradigm-personas",
|
|
@@ -4640,6 +4828,604 @@ function slugify(name) {
|
|
|
4640
4828
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
4641
4829
|
}
|
|
4642
4830
|
|
|
4831
|
+
// ../paradigm-mcp/src/utils/university-loader.ts
|
|
4832
|
+
import * as fs8 from "fs";
|
|
4833
|
+
import * as path9 from "path";
|
|
4834
|
+
import * as yaml7 from "js-yaml";
|
|
4835
|
+
var UNIVERSITY_DIR = ".paradigm/university";
|
|
4836
|
+
var CONTENT_DIR = "content";
|
|
4837
|
+
var NOTES_DIR = "notes";
|
|
4838
|
+
var POLICIES_DIR = "policies";
|
|
4839
|
+
var QUIZZES_DIR = "quizzes";
|
|
4840
|
+
var PATHS_DIR = "paths";
|
|
4841
|
+
var DIPLOMAS_DIR = "diplomas";
|
|
4842
|
+
var INDEX_FILE3 = "index.yaml";
|
|
4843
|
+
var CONFIG_FILE = "config.yaml";
|
|
4844
|
+
var DEFAULT_BRANDING = {
|
|
4845
|
+
name: "Project University",
|
|
4846
|
+
tagline: "Learn the codebase",
|
|
4847
|
+
institution: "Paradigm"
|
|
4848
|
+
};
|
|
4849
|
+
var DEFAULT_THEME = {
|
|
4850
|
+
primary: "#6366f1",
|
|
4851
|
+
secondary: "#8b5cf6",
|
|
4852
|
+
accent: "#f59e0b",
|
|
4853
|
+
background: "#0f172a",
|
|
4854
|
+
surface: "#1e293b",
|
|
4855
|
+
text: "#f8fafc",
|
|
4856
|
+
textMuted: "#94a3b8",
|
|
4857
|
+
success: "#22c55e",
|
|
4858
|
+
error: "#ef4444",
|
|
4859
|
+
font: "Inter, system-ui, sans-serif"
|
|
4860
|
+
};
|
|
4861
|
+
var DEFAULT_CONFIG = {
|
|
4862
|
+
branding: DEFAULT_BRANDING,
|
|
4863
|
+
theme: DEFAULT_THEME,
|
|
4864
|
+
content: {
|
|
4865
|
+
categories: [],
|
|
4866
|
+
defaultDifficulty: "beginner",
|
|
4867
|
+
requireApproval: false
|
|
4868
|
+
},
|
|
4869
|
+
diplomas: {
|
|
4870
|
+
includeGlobalPLSAT: true,
|
|
4871
|
+
customCertStyle: null
|
|
4872
|
+
}
|
|
4873
|
+
};
|
|
4874
|
+
function loadUniversityConfig(rootDir) {
|
|
4875
|
+
const configPath = path9.join(rootDir, UNIVERSITY_DIR, CONFIG_FILE);
|
|
4876
|
+
if (!fs8.existsSync(configPath)) {
|
|
4877
|
+
return { ...DEFAULT_CONFIG };
|
|
4878
|
+
}
|
|
4879
|
+
try {
|
|
4880
|
+
const raw = fs8.readFileSync(configPath, "utf8");
|
|
4881
|
+
const data = yaml7.load(raw);
|
|
4882
|
+
if (!data) return { ...DEFAULT_CONFIG };
|
|
4883
|
+
return {
|
|
4884
|
+
branding: { ...DEFAULT_BRANDING, ...data.branding || {} },
|
|
4885
|
+
theme: { ...DEFAULT_THEME, ...data.theme || {} },
|
|
4886
|
+
content: {
|
|
4887
|
+
categories: data.content?.categories || [],
|
|
4888
|
+
defaultDifficulty: data.content?.defaultDifficulty || "beginner",
|
|
4889
|
+
requireApproval: data.content?.requireApproval ?? false
|
|
4890
|
+
},
|
|
4891
|
+
diplomas: {
|
|
4892
|
+
includeGlobalPLSAT: data.diplomas?.includeGlobalPLSAT ?? true,
|
|
4893
|
+
customCertStyle: data.diplomas?.customCertStyle ?? null
|
|
4894
|
+
}
|
|
4895
|
+
};
|
|
4896
|
+
} catch {
|
|
4897
|
+
return { ...DEFAULT_CONFIG };
|
|
4898
|
+
}
|
|
4899
|
+
}
|
|
4900
|
+
function loadUniversityIndex(rootDir) {
|
|
4901
|
+
const indexPath = path9.join(rootDir, UNIVERSITY_DIR, INDEX_FILE3);
|
|
4902
|
+
if (!fs8.existsSync(indexPath)) return null;
|
|
4903
|
+
try {
|
|
4904
|
+
const raw = fs8.readFileSync(indexPath, "utf8");
|
|
4905
|
+
return yaml7.load(raw);
|
|
4906
|
+
} catch {
|
|
4907
|
+
return null;
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4910
|
+
function parseFrontmatter(content) {
|
|
4911
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
4912
|
+
if (!match) return null;
|
|
4913
|
+
try {
|
|
4914
|
+
const frontmatter = yaml7.load(match[1]);
|
|
4915
|
+
return { frontmatter, body: match[2].trim() };
|
|
4916
|
+
} catch {
|
|
4917
|
+
return null;
|
|
4918
|
+
}
|
|
4919
|
+
}
|
|
4920
|
+
function serializeFrontmatter(frontmatter, body) {
|
|
4921
|
+
const fm = yaml7.dump(frontmatter, { lineWidth: -1, noRefs: true, sortKeys: false });
|
|
4922
|
+
return `---
|
|
4923
|
+
${fm}---
|
|
4924
|
+
|
|
4925
|
+
${body}
|
|
4926
|
+
`;
|
|
4927
|
+
}
|
|
4928
|
+
function loadNote(rootDir, id) {
|
|
4929
|
+
const filePath = resolveContentFile(rootDir, id, ".md");
|
|
4930
|
+
if (!filePath) return null;
|
|
4931
|
+
try {
|
|
4932
|
+
const raw = fs8.readFileSync(filePath, "utf8");
|
|
4933
|
+
const parsed = parseFrontmatter(raw);
|
|
4934
|
+
if (!parsed) return null;
|
|
4935
|
+
const fm = parsed.frontmatter;
|
|
4936
|
+
return { frontmatter: normalizeFrontmatter(fm), body: parsed.body };
|
|
4937
|
+
} catch {
|
|
4938
|
+
return null;
|
|
4939
|
+
}
|
|
4940
|
+
}
|
|
4941
|
+
function saveNote(rootDir, frontmatter, body) {
|
|
4942
|
+
const subdir = frontmatter.type === "policy" ? POLICIES_DIR : NOTES_DIR;
|
|
4943
|
+
const dir = path9.join(rootDir, UNIVERSITY_DIR, CONTENT_DIR, subdir);
|
|
4944
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
4945
|
+
const filePath = path9.join(dir, `${frontmatter.id}.md`);
|
|
4946
|
+
const content = serializeFrontmatter(frontmatter, body);
|
|
4947
|
+
fs8.writeFileSync(filePath, content, "utf8");
|
|
4948
|
+
return filePath;
|
|
4949
|
+
}
|
|
4950
|
+
function loadQuiz(rootDir, id) {
|
|
4951
|
+
const filePath = resolveContentFile(rootDir, id, ".yaml");
|
|
4952
|
+
if (!filePath) return null;
|
|
4953
|
+
try {
|
|
4954
|
+
const raw = fs8.readFileSync(filePath, "utf8");
|
|
4955
|
+
const data = yaml7.load(raw);
|
|
4956
|
+
if (!data || !data.id) return null;
|
|
4957
|
+
return normalizeQuiz(data);
|
|
4958
|
+
} catch {
|
|
4959
|
+
return null;
|
|
4960
|
+
}
|
|
4961
|
+
}
|
|
4962
|
+
function saveQuiz(rootDir, quiz) {
|
|
4963
|
+
const dir = path9.join(rootDir, UNIVERSITY_DIR, CONTENT_DIR, QUIZZES_DIR);
|
|
4964
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
4965
|
+
const filePath = path9.join(dir, `${quiz.id}.yaml`);
|
|
4966
|
+
fs8.writeFileSync(filePath, yaml7.dump(quiz, { lineWidth: -1, noRefs: true }), "utf8");
|
|
4967
|
+
return filePath;
|
|
4968
|
+
}
|
|
4969
|
+
function loadPath(rootDir, id) {
|
|
4970
|
+
const filePath = resolveContentFile(rootDir, id, ".yaml");
|
|
4971
|
+
if (!filePath) return null;
|
|
4972
|
+
try {
|
|
4973
|
+
const raw = fs8.readFileSync(filePath, "utf8");
|
|
4974
|
+
const data = yaml7.load(raw);
|
|
4975
|
+
if (!data || !data.id) return null;
|
|
4976
|
+
return data;
|
|
4977
|
+
} catch {
|
|
4978
|
+
return null;
|
|
4979
|
+
}
|
|
4980
|
+
}
|
|
4981
|
+
function savePath(rootDir, lp) {
|
|
4982
|
+
const dir = path9.join(rootDir, UNIVERSITY_DIR, CONTENT_DIR, PATHS_DIR);
|
|
4983
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
4984
|
+
const filePath = path9.join(dir, `${lp.id}.yaml`);
|
|
4985
|
+
fs8.writeFileSync(filePath, yaml7.dump(lp, { lineWidth: -1, noRefs: true }), "utf8");
|
|
4986
|
+
return filePath;
|
|
4987
|
+
}
|
|
4988
|
+
function loadDiplomas(rootDir, filter) {
|
|
4989
|
+
const dir = path9.join(rootDir, UNIVERSITY_DIR, DIPLOMAS_DIR);
|
|
4990
|
+
if (!fs8.existsSync(dir)) return [];
|
|
4991
|
+
const results = [];
|
|
4992
|
+
try {
|
|
4993
|
+
const files = fs8.readdirSync(dir).filter((f) => f.endsWith(".yaml"));
|
|
4994
|
+
for (const file of files) {
|
|
4995
|
+
try {
|
|
4996
|
+
const raw = fs8.readFileSync(path9.join(dir, file), "utf8");
|
|
4997
|
+
const diploma = yaml7.load(raw);
|
|
4998
|
+
if (!diploma || !diploma.id) continue;
|
|
4999
|
+
if (filter?.student && diploma.student !== filter.student) continue;
|
|
5000
|
+
if (filter?.type && diploma.type !== filter.type) continue;
|
|
5001
|
+
results.push(diploma);
|
|
5002
|
+
} catch {
|
|
5003
|
+
}
|
|
5004
|
+
}
|
|
5005
|
+
} catch {
|
|
5006
|
+
}
|
|
5007
|
+
return results.sort((a, b) => b.earnedAt.localeCompare(a.earnedAt));
|
|
5008
|
+
}
|
|
5009
|
+
function saveDiploma(rootDir, diploma) {
|
|
5010
|
+
const dir = path9.join(rootDir, UNIVERSITY_DIR, DIPLOMAS_DIR);
|
|
5011
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
5012
|
+
const filePath = path9.join(dir, `${diploma.id}.yaml`);
|
|
5013
|
+
fs8.writeFileSync(filePath, yaml7.dump(diploma, { lineWidth: -1, noRefs: true }), "utf8");
|
|
5014
|
+
return filePath;
|
|
5015
|
+
}
|
|
5016
|
+
function searchContent(rootDir, filter) {
|
|
5017
|
+
const index = loadUniversityIndex(rootDir);
|
|
5018
|
+
if (!index) return [];
|
|
5019
|
+
let results = [...index.entries];
|
|
5020
|
+
if (filter.type) {
|
|
5021
|
+
results = results.filter((e) => e.type === filter.type);
|
|
5022
|
+
}
|
|
5023
|
+
if (filter.tag) {
|
|
5024
|
+
results = results.filter((e) => e.tags.some((t) => t.startsWith(filter.tag)));
|
|
5025
|
+
}
|
|
5026
|
+
if (filter.difficulty) {
|
|
5027
|
+
results = results.filter((e) => e.difficulty === filter.difficulty);
|
|
5028
|
+
}
|
|
5029
|
+
if (filter.symbol) {
|
|
5030
|
+
results = results.filter((e) => e.symbols.some((s) => s === filter.symbol));
|
|
5031
|
+
}
|
|
5032
|
+
if (filter.author) {
|
|
5033
|
+
results = results.filter((e) => e.author === filter.author);
|
|
5034
|
+
}
|
|
5035
|
+
if (filter.query) {
|
|
5036
|
+
const q = filter.query.toLowerCase();
|
|
5037
|
+
results = results.filter(
|
|
5038
|
+
(e) => e.title.toLowerCase().includes(q) || e.id.toLowerCase().includes(q) || e.tags.some((t) => t.toLowerCase().includes(q))
|
|
5039
|
+
);
|
|
5040
|
+
}
|
|
5041
|
+
const limit = filter.limit || 20;
|
|
5042
|
+
return results.slice(0, limit);
|
|
5043
|
+
}
|
|
5044
|
+
function rebuildUniversityIndex(rootDir) {
|
|
5045
|
+
const uniDir = path9.join(rootDir, UNIVERSITY_DIR);
|
|
5046
|
+
const contentDir = path9.join(uniDir, CONTENT_DIR);
|
|
5047
|
+
const entries = [];
|
|
5048
|
+
for (const subdir of [NOTES_DIR, POLICIES_DIR]) {
|
|
5049
|
+
const dir = path9.join(contentDir, subdir);
|
|
5050
|
+
if (!fs8.existsSync(dir)) continue;
|
|
5051
|
+
try {
|
|
5052
|
+
for (const file of fs8.readdirSync(dir).filter((f) => f.endsWith(".md"))) {
|
|
5053
|
+
try {
|
|
5054
|
+
const raw = fs8.readFileSync(path9.join(dir, file), "utf8");
|
|
5055
|
+
const parsed = parseFrontmatter(raw);
|
|
5056
|
+
if (!parsed) continue;
|
|
5057
|
+
const fm = parsed.frontmatter;
|
|
5058
|
+
entries.push({
|
|
5059
|
+
id: fm.id || file.replace(".md", ""),
|
|
5060
|
+
title: fm.title || file,
|
|
5061
|
+
type: fm.type || (subdir === POLICIES_DIR ? "policy" : "note"),
|
|
5062
|
+
author: fm.author || "unknown",
|
|
5063
|
+
created: fm.created || "",
|
|
5064
|
+
updated: fm.updated || "",
|
|
5065
|
+
tags: Array.isArray(fm.tags) ? fm.tags : [],
|
|
5066
|
+
symbols: Array.isArray(fm.symbols) ? fm.symbols : [],
|
|
5067
|
+
difficulty: fm.difficulty || "beginner",
|
|
5068
|
+
file: `${CONTENT_DIR}/${subdir}/${file}`
|
|
5069
|
+
});
|
|
5070
|
+
} catch {
|
|
5071
|
+
}
|
|
5072
|
+
}
|
|
5073
|
+
} catch {
|
|
5074
|
+
}
|
|
5075
|
+
}
|
|
5076
|
+
const quizDir = path9.join(contentDir, QUIZZES_DIR);
|
|
5077
|
+
if (fs8.existsSync(quizDir)) {
|
|
5078
|
+
try {
|
|
5079
|
+
for (const file of fs8.readdirSync(quizDir).filter((f) => f.endsWith(".yaml"))) {
|
|
5080
|
+
try {
|
|
5081
|
+
const raw = fs8.readFileSync(path9.join(quizDir, file), "utf8");
|
|
5082
|
+
const quiz = yaml7.load(raw);
|
|
5083
|
+
if (!quiz || !quiz.id) continue;
|
|
5084
|
+
entries.push({
|
|
5085
|
+
id: quiz.id,
|
|
5086
|
+
title: quiz.title || file,
|
|
5087
|
+
type: "quiz",
|
|
5088
|
+
author: quiz.author || "unknown",
|
|
5089
|
+
created: quiz.created || "",
|
|
5090
|
+
updated: quiz.updated || "",
|
|
5091
|
+
tags: quiz.tags || [],
|
|
5092
|
+
symbols: quiz.symbols || [],
|
|
5093
|
+
difficulty: quiz.difficulty || "beginner",
|
|
5094
|
+
file: `${CONTENT_DIR}/${QUIZZES_DIR}/${file}`
|
|
5095
|
+
});
|
|
5096
|
+
} catch {
|
|
5097
|
+
}
|
|
5098
|
+
}
|
|
5099
|
+
} catch {
|
|
5100
|
+
}
|
|
5101
|
+
}
|
|
5102
|
+
const pathDir = path9.join(contentDir, PATHS_DIR);
|
|
5103
|
+
if (fs8.existsSync(pathDir)) {
|
|
5104
|
+
try {
|
|
5105
|
+
for (const file of fs8.readdirSync(pathDir).filter((f) => f.endsWith(".yaml"))) {
|
|
5106
|
+
try {
|
|
5107
|
+
const raw = fs8.readFileSync(path9.join(pathDir, file), "utf8");
|
|
5108
|
+
const lp = yaml7.load(raw);
|
|
5109
|
+
if (!lp || !lp.id) continue;
|
|
5110
|
+
entries.push({
|
|
5111
|
+
id: lp.id,
|
|
5112
|
+
title: lp.title || file,
|
|
5113
|
+
type: "path",
|
|
5114
|
+
author: lp.author || "unknown",
|
|
5115
|
+
created: lp.created || "",
|
|
5116
|
+
updated: lp.updated || "",
|
|
5117
|
+
tags: lp.tags || [],
|
|
5118
|
+
symbols: [],
|
|
5119
|
+
file: `${CONTENT_DIR}/${PATHS_DIR}/${file}`
|
|
5120
|
+
});
|
|
5121
|
+
} catch {
|
|
5122
|
+
}
|
|
5123
|
+
}
|
|
5124
|
+
} catch {
|
|
5125
|
+
}
|
|
5126
|
+
}
|
|
5127
|
+
let diplomaCount = 0;
|
|
5128
|
+
const diplomaDir = path9.join(uniDir, DIPLOMAS_DIR);
|
|
5129
|
+
if (fs8.existsSync(diplomaDir)) {
|
|
5130
|
+
try {
|
|
5131
|
+
diplomaCount = fs8.readdirSync(diplomaDir).filter((f) => f.endsWith(".yaml")).length;
|
|
5132
|
+
} catch {
|
|
5133
|
+
}
|
|
5134
|
+
}
|
|
5135
|
+
const index = {
|
|
5136
|
+
version: "1.0",
|
|
5137
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5138
|
+
totalContent: entries.length,
|
|
5139
|
+
entries,
|
|
5140
|
+
diplomaCount
|
|
5141
|
+
};
|
|
5142
|
+
fs8.mkdirSync(uniDir, { recursive: true });
|
|
5143
|
+
const indexPath = path9.join(uniDir, INDEX_FILE3);
|
|
5144
|
+
fs8.writeFileSync(indexPath, yaml7.dump(index, { lineWidth: -1, noRefs: true }), "utf8");
|
|
5145
|
+
return index;
|
|
5146
|
+
}
|
|
5147
|
+
function validateUniversityContent(rootDir, options) {
|
|
5148
|
+
const index = loadUniversityIndex(rootDir) || rebuildUniversityIndex(rootDir);
|
|
5149
|
+
const issues = [];
|
|
5150
|
+
let entriesToCheck = index.entries;
|
|
5151
|
+
if (options?.id) {
|
|
5152
|
+
entriesToCheck = entriesToCheck.filter((e) => e.id === options.id);
|
|
5153
|
+
}
|
|
5154
|
+
let knownSymbols = null;
|
|
5155
|
+
if (options?.deep) {
|
|
5156
|
+
knownSymbols = loadKnownSymbols(rootDir);
|
|
5157
|
+
}
|
|
5158
|
+
const allContentIds = new Set(index.entries.map((e) => e.id));
|
|
5159
|
+
for (const entry of entriesToCheck) {
|
|
5160
|
+
if (!entry.title) {
|
|
5161
|
+
issues.push({
|
|
5162
|
+
contentId: entry.id,
|
|
5163
|
+
severity: "error",
|
|
5164
|
+
check: "missing-title",
|
|
5165
|
+
message: "Content is missing a title",
|
|
5166
|
+
fix: "Add a title field to the content frontmatter"
|
|
5167
|
+
});
|
|
5168
|
+
}
|
|
5169
|
+
if (entry.type === "quiz") {
|
|
5170
|
+
validateQuizContent(rootDir, entry.id, issues);
|
|
5171
|
+
}
|
|
5172
|
+
if (entry.type === "path") {
|
|
5173
|
+
validatePathContent(rootDir, entry.id, allContentIds, issues);
|
|
5174
|
+
}
|
|
5175
|
+
if (knownSymbols && entry.symbols.length > 0) {
|
|
5176
|
+
for (const sym of entry.symbols) {
|
|
5177
|
+
if (!knownSymbols.has(sym)) {
|
|
5178
|
+
issues.push({
|
|
5179
|
+
contentId: entry.id,
|
|
5180
|
+
severity: "warning",
|
|
5181
|
+
check: "broken-symbol-ref",
|
|
5182
|
+
message: `Symbol "${sym}" not found in scan-index`,
|
|
5183
|
+
fix: `Remove or update the symbol reference in ${entry.id}`
|
|
5184
|
+
});
|
|
5185
|
+
}
|
|
5186
|
+
}
|
|
5187
|
+
}
|
|
5188
|
+
if (options?.deep && entry.symbols.length > 0 && entry.updated) {
|
|
5189
|
+
checkContentStaleness(rootDir, entry, issues);
|
|
5190
|
+
}
|
|
5191
|
+
}
|
|
5192
|
+
const diplomas = loadDiplomas(rootDir);
|
|
5193
|
+
for (const diploma of diplomas) {
|
|
5194
|
+
if (diploma.total > 0 && diploma.percentage !== Math.round(diploma.score / diploma.total * 1e4) / 100) {
|
|
5195
|
+
const expected = Math.round(diploma.score / diploma.total * 1e4) / 100;
|
|
5196
|
+
if (Math.abs(diploma.percentage - expected) > 0.1) {
|
|
5197
|
+
issues.push({
|
|
5198
|
+
contentId: diploma.id,
|
|
5199
|
+
severity: "warning",
|
|
5200
|
+
check: "diploma-score-mismatch",
|
|
5201
|
+
message: `Diploma percentage ${diploma.percentage} doesn't match score ${diploma.score}/${diploma.total} (expected ${expected})`
|
|
5202
|
+
});
|
|
5203
|
+
}
|
|
5204
|
+
}
|
|
5205
|
+
}
|
|
5206
|
+
const symbolCoverage = computeSymbolCoverage(rootDir, index);
|
|
5207
|
+
return {
|
|
5208
|
+
status: issues.some((i) => i.severity === "error") ? "errors" : issues.length > 0 ? "warnings" : "healthy",
|
|
5209
|
+
totalContent: index.totalContent,
|
|
5210
|
+
checked: entriesToCheck.length,
|
|
5211
|
+
issues,
|
|
5212
|
+
symbolCoverage
|
|
5213
|
+
};
|
|
5214
|
+
}
|
|
5215
|
+
function validateQuizContent(rootDir, id, issues) {
|
|
5216
|
+
const quiz = loadQuiz(rootDir, id);
|
|
5217
|
+
if (!quiz) {
|
|
5218
|
+
issues.push({
|
|
5219
|
+
contentId: id,
|
|
5220
|
+
severity: "error",
|
|
5221
|
+
check: "unreadable-quiz",
|
|
5222
|
+
message: "Quiz file could not be parsed"
|
|
5223
|
+
});
|
|
5224
|
+
return;
|
|
5225
|
+
}
|
|
5226
|
+
if (!quiz.passThreshold || quiz.passThreshold < 0 || quiz.passThreshold > 1) {
|
|
5227
|
+
issues.push({
|
|
5228
|
+
contentId: id,
|
|
5229
|
+
severity: "warning",
|
|
5230
|
+
check: "invalid-pass-threshold",
|
|
5231
|
+
message: `passThreshold should be between 0 and 1, got ${quiz.passThreshold}`,
|
|
5232
|
+
fix: "Set passThreshold to a value between 0.0 and 1.0"
|
|
5233
|
+
});
|
|
5234
|
+
}
|
|
5235
|
+
for (const q of quiz.questions) {
|
|
5236
|
+
if (!q.choices || typeof q.choices !== "object") {
|
|
5237
|
+
issues.push({
|
|
5238
|
+
contentId: id,
|
|
5239
|
+
severity: "error",
|
|
5240
|
+
check: "invalid-quiz-choices",
|
|
5241
|
+
message: `Question ${q.id} has no choices defined`
|
|
5242
|
+
});
|
|
5243
|
+
continue;
|
|
5244
|
+
}
|
|
5245
|
+
if (!q.correct || !(q.correct in q.choices)) {
|
|
5246
|
+
issues.push({
|
|
5247
|
+
contentId: id,
|
|
5248
|
+
severity: "error",
|
|
5249
|
+
check: "invalid-quiz-answer",
|
|
5250
|
+
message: `Question ${q.id}: correct answer "${q.correct}" not found in choices [${Object.keys(q.choices).join(", ")}]`,
|
|
5251
|
+
fix: `Set correct to one of: ${Object.keys(q.choices).join(", ")}`
|
|
5252
|
+
});
|
|
5253
|
+
}
|
|
5254
|
+
}
|
|
5255
|
+
}
|
|
5256
|
+
function validatePathContent(rootDir, id, allContentIds, issues) {
|
|
5257
|
+
const lp = loadPath(rootDir, id);
|
|
5258
|
+
if (!lp) {
|
|
5259
|
+
issues.push({
|
|
5260
|
+
contentId: id,
|
|
5261
|
+
severity: "error",
|
|
5262
|
+
check: "unreadable-path",
|
|
5263
|
+
message: "Learning path file could not be parsed"
|
|
5264
|
+
});
|
|
5265
|
+
return;
|
|
5266
|
+
}
|
|
5267
|
+
for (const step of lp.steps) {
|
|
5268
|
+
if (step.content.startsWith("plsat:")) continue;
|
|
5269
|
+
if (!allContentIds.has(step.content)) {
|
|
5270
|
+
issues.push({
|
|
5271
|
+
contentId: id,
|
|
5272
|
+
severity: "error",
|
|
5273
|
+
check: "broken-path-step",
|
|
5274
|
+
message: `Learning path step references "${step.content}" which doesn't exist`,
|
|
5275
|
+
fix: `Create content with id "${step.content}" or remove this step`
|
|
5276
|
+
});
|
|
5277
|
+
}
|
|
5278
|
+
}
|
|
5279
|
+
}
|
|
5280
|
+
function getAffectedUniversityContent(rootDir, symbol) {
|
|
5281
|
+
const index = loadUniversityIndex(rootDir);
|
|
5282
|
+
if (!index) return [];
|
|
5283
|
+
const affected = [];
|
|
5284
|
+
for (const entry of index.entries) {
|
|
5285
|
+
if (entry.symbols.includes(symbol)) {
|
|
5286
|
+
const stale = isContentStale(rootDir, entry, symbol);
|
|
5287
|
+
affected.push({
|
|
5288
|
+
id: entry.id,
|
|
5289
|
+
title: entry.title,
|
|
5290
|
+
type: entry.type,
|
|
5291
|
+
stale
|
|
5292
|
+
});
|
|
5293
|
+
}
|
|
5294
|
+
}
|
|
5295
|
+
return affected;
|
|
5296
|
+
}
|
|
5297
|
+
function getOnboardingSequence(rootDir, student) {
|
|
5298
|
+
const index = loadUniversityIndex(rootDir);
|
|
5299
|
+
if (!index) {
|
|
5300
|
+
return { paths: [], suggestedContent: [], diplomaCount: 0, totalContent: 0 };
|
|
5301
|
+
}
|
|
5302
|
+
const pathEntries = index.entries.filter((e) => e.type === "path");
|
|
5303
|
+
const diplomas = student ? loadDiplomas(rootDir, { student }) : [];
|
|
5304
|
+
const diplomaSourceIds = new Set(diplomas.map((d) => d.source));
|
|
5305
|
+
const paths = pathEntries.map((pe) => {
|
|
5306
|
+
const lp = loadPath(rootDir, pe.id);
|
|
5307
|
+
return {
|
|
5308
|
+
id: pe.id,
|
|
5309
|
+
title: pe.title,
|
|
5310
|
+
steps: lp?.steps.length || 0,
|
|
5311
|
+
completed: diplomaSourceIds.has(pe.id)
|
|
5312
|
+
};
|
|
5313
|
+
});
|
|
5314
|
+
const suggestedContent = index.entries.filter((e) => e.type !== "path" && (e.difficulty === "beginner" || e.tags.includes("onboarding"))).slice(0, 10);
|
|
5315
|
+
return {
|
|
5316
|
+
paths,
|
|
5317
|
+
suggestedContent,
|
|
5318
|
+
diplomaCount: diplomas.length,
|
|
5319
|
+
totalContent: index.totalContent
|
|
5320
|
+
};
|
|
5321
|
+
}
|
|
5322
|
+
function resolveContentFile(rootDir, id, ext) {
|
|
5323
|
+
const contentDir = path9.join(rootDir, UNIVERSITY_DIR, CONTENT_DIR);
|
|
5324
|
+
for (const subdir of [NOTES_DIR, POLICIES_DIR, QUIZZES_DIR, PATHS_DIR]) {
|
|
5325
|
+
const filePath = path9.join(contentDir, subdir, `${id}${ext}`);
|
|
5326
|
+
if (fs8.existsSync(filePath)) return filePath;
|
|
5327
|
+
}
|
|
5328
|
+
return null;
|
|
5329
|
+
}
|
|
5330
|
+
function normalizeFrontmatter(fm) {
|
|
5331
|
+
return {
|
|
5332
|
+
id: fm.id || "",
|
|
5333
|
+
title: fm.title || "",
|
|
5334
|
+
type: fm.type || "note",
|
|
5335
|
+
author: fm.author || "unknown",
|
|
5336
|
+
created: fm.created || "",
|
|
5337
|
+
updated: fm.updated || "",
|
|
5338
|
+
tags: Array.isArray(fm.tags) ? fm.tags : [],
|
|
5339
|
+
symbols: Array.isArray(fm.symbols) ? fm.symbols : [],
|
|
5340
|
+
difficulty: fm.difficulty || "beginner",
|
|
5341
|
+
estimatedMinutes: fm.estimatedMinutes,
|
|
5342
|
+
prerequisites: Array.isArray(fm.prerequisites) ? fm.prerequisites : []
|
|
5343
|
+
};
|
|
5344
|
+
}
|
|
5345
|
+
function normalizeQuiz(quiz) {
|
|
5346
|
+
return {
|
|
5347
|
+
...quiz,
|
|
5348
|
+
tags: quiz.tags || [],
|
|
5349
|
+
symbols: quiz.symbols || [],
|
|
5350
|
+
difficulty: quiz.difficulty || "beginner",
|
|
5351
|
+
passThreshold: quiz.passThreshold ?? 0.7,
|
|
5352
|
+
questions: quiz.questions || []
|
|
5353
|
+
};
|
|
5354
|
+
}
|
|
5355
|
+
function loadKnownSymbols(rootDir) {
|
|
5356
|
+
const symbols = /* @__PURE__ */ new Set();
|
|
5357
|
+
const scanIndexPath = path9.join(rootDir, ".paradigm", "scan-index.json");
|
|
5358
|
+
if (!fs8.existsSync(scanIndexPath)) return symbols;
|
|
5359
|
+
try {
|
|
5360
|
+
const raw = fs8.readFileSync(scanIndexPath, "utf8");
|
|
5361
|
+
const index = JSON.parse(raw);
|
|
5362
|
+
if (index.symbols && Array.isArray(index.symbols)) {
|
|
5363
|
+
for (const sym of index.symbols) {
|
|
5364
|
+
if (sym.symbol) symbols.add(sym.symbol);
|
|
5365
|
+
}
|
|
5366
|
+
}
|
|
5367
|
+
} catch {
|
|
5368
|
+
}
|
|
5369
|
+
return symbols;
|
|
5370
|
+
}
|
|
5371
|
+
function computeSymbolCoverage(rootDir, index) {
|
|
5372
|
+
const knownSymbols = loadKnownSymbols(rootDir);
|
|
5373
|
+
const coveredSymbols = /* @__PURE__ */ new Set();
|
|
5374
|
+
for (const entry of index.entries) {
|
|
5375
|
+
for (const sym of entry.symbols) {
|
|
5376
|
+
if (knownSymbols.has(sym)) {
|
|
5377
|
+
coveredSymbols.add(sym);
|
|
5378
|
+
}
|
|
5379
|
+
}
|
|
5380
|
+
}
|
|
5381
|
+
const total = knownSymbols.size;
|
|
5382
|
+
return {
|
|
5383
|
+
totalSymbols: total,
|
|
5384
|
+
coveredByContent: coveredSymbols.size,
|
|
5385
|
+
percentage: total > 0 ? Math.round(coveredSymbols.size / total * 100) : 0
|
|
5386
|
+
};
|
|
5387
|
+
}
|
|
5388
|
+
function isContentStale(rootDir, entry, _symbol) {
|
|
5389
|
+
if (!entry.updated) return false;
|
|
5390
|
+
const contentUpdated = new Date(entry.updated).getTime();
|
|
5391
|
+
if (isNaN(contentUpdated)) return false;
|
|
5392
|
+
const scanIndexPath = path9.join(rootDir, ".paradigm", "scan-index.json");
|
|
5393
|
+
if (!fs8.existsSync(scanIndexPath)) return false;
|
|
5394
|
+
try {
|
|
5395
|
+
const raw = fs8.readFileSync(scanIndexPath, "utf8");
|
|
5396
|
+
const index = JSON.parse(raw);
|
|
5397
|
+
if (index.symbols && Array.isArray(index.symbols)) {
|
|
5398
|
+
for (const sym of index.symbols) {
|
|
5399
|
+
if (sym.symbol === _symbol && sym.filePath) {
|
|
5400
|
+
const purposePath = path9.join(rootDir, sym.filePath);
|
|
5401
|
+
if (fs8.existsSync(purposePath)) {
|
|
5402
|
+
const stat = fs8.statSync(purposePath);
|
|
5403
|
+
if (stat.mtime.getTime() > contentUpdated) {
|
|
5404
|
+
return true;
|
|
5405
|
+
}
|
|
5406
|
+
}
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5410
|
+
} catch {
|
|
5411
|
+
}
|
|
5412
|
+
return false;
|
|
5413
|
+
}
|
|
5414
|
+
function checkContentStaleness(rootDir, entry, issues) {
|
|
5415
|
+
for (const sym of entry.symbols) {
|
|
5416
|
+
if (isContentStale(rootDir, entry, sym)) {
|
|
5417
|
+
issues.push({
|
|
5418
|
+
contentId: entry.id,
|
|
5419
|
+
severity: "warning",
|
|
5420
|
+
check: "stale-content",
|
|
5421
|
+
message: `Content may be stale: symbol "${sym}" was updated after content was last modified`,
|
|
5422
|
+
fix: `Review and update ${entry.id} to reflect changes to ${sym}`
|
|
5423
|
+
});
|
|
5424
|
+
break;
|
|
5425
|
+
}
|
|
5426
|
+
}
|
|
5427
|
+
}
|
|
5428
|
+
|
|
4643
5429
|
// ../paradigm-mcp/src/tools/reindex.ts
|
|
4644
5430
|
var SYMBOL_CATEGORIES = {
|
|
4645
5431
|
"@": { category: "features", prefix: "@" },
|
|
@@ -4728,10 +5514,10 @@ async function rebuildStaticFiles(rootDir, ctx) {
|
|
|
4728
5514
|
} else {
|
|
4729
5515
|
aggregation = await aggregateFromDirectory(rootDir);
|
|
4730
5516
|
}
|
|
4731
|
-
const projectName = ctx?.projectName ||
|
|
4732
|
-
const paradigmDir =
|
|
4733
|
-
if (!
|
|
4734
|
-
|
|
5517
|
+
const projectName = ctx?.projectName || path10.basename(rootDir);
|
|
5518
|
+
const paradigmDir = path10.join(rootDir, ".paradigm");
|
|
5519
|
+
if (!fs9.existsSync(paradigmDir)) {
|
|
5520
|
+
fs9.mkdirSync(paradigmDir, { recursive: true });
|
|
4735
5521
|
}
|
|
4736
5522
|
const scanIndex = generateScanIndex(
|
|
4737
5523
|
{
|
|
@@ -4741,22 +5527,22 @@ async function rebuildStaticFiles(rootDir, ctx) {
|
|
|
4741
5527
|
},
|
|
4742
5528
|
{ projectName }
|
|
4743
5529
|
);
|
|
4744
|
-
const scanIndexPath =
|
|
4745
|
-
|
|
5530
|
+
const scanIndexPath = path10.join(paradigmDir, "scan-index.json");
|
|
5531
|
+
fs9.writeFileSync(scanIndexPath, serializeScanIndex(scanIndex), "utf8");
|
|
4746
5532
|
filesWritten.push(".paradigm/scan-index.json");
|
|
4747
5533
|
const navigatorData = buildNavigatorData(rootDir, aggregation);
|
|
4748
|
-
const navigatorPath =
|
|
4749
|
-
|
|
5534
|
+
const navigatorPath = path10.join(paradigmDir, "navigator.yaml");
|
|
5535
|
+
fs9.writeFileSync(
|
|
4750
5536
|
navigatorPath,
|
|
4751
|
-
|
|
5537
|
+
yaml8.dump(navigatorData, { indent: 2, lineWidth: 120, noRefs: true, sortKeys: false }),
|
|
4752
5538
|
"utf8"
|
|
4753
5539
|
);
|
|
4754
5540
|
filesWritten.push(".paradigm/navigator.yaml");
|
|
4755
5541
|
const flowIndex = generateFlowIndex(rootDir, aggregation.purposeFiles);
|
|
4756
5542
|
let flowCount = 0;
|
|
4757
5543
|
if (flowIndex && Object.keys(flowIndex.flows).length > 0) {
|
|
4758
|
-
const flowIndexPath =
|
|
4759
|
-
|
|
5544
|
+
const flowIndexPath = path10.join(paradigmDir, "flow-index.json");
|
|
5545
|
+
fs9.writeFileSync(flowIndexPath, JSON.stringify(flowIndex, null, 2), "utf8");
|
|
4760
5546
|
filesWritten.push(".paradigm/flow-index.json");
|
|
4761
5547
|
flowCount = Object.keys(flowIndex.flows).length;
|
|
4762
5548
|
}
|
|
@@ -4797,10 +5583,68 @@ async function rebuildStaticFiles(rootDir, ctx) {
|
|
|
4797
5583
|
}
|
|
4798
5584
|
} catch {
|
|
4799
5585
|
}
|
|
5586
|
+
let universityStats;
|
|
5587
|
+
try {
|
|
5588
|
+
const uniDir = path10.join(rootDir, ".paradigm", "university");
|
|
5589
|
+
if (fs9.existsSync(uniDir)) {
|
|
5590
|
+
const uniIndex = rebuildUniversityIndex(rootDir);
|
|
5591
|
+
if (uniIndex.totalContent > 0 || uniIndex.diplomaCount > 0) {
|
|
5592
|
+
universityStats = {
|
|
5593
|
+
totalContent: uniIndex.totalContent,
|
|
5594
|
+
diplomaCount: uniIndex.diplomaCount
|
|
5595
|
+
};
|
|
5596
|
+
filesWritten.push(".paradigm/university/index.yaml");
|
|
5597
|
+
}
|
|
5598
|
+
}
|
|
5599
|
+
} catch {
|
|
5600
|
+
}
|
|
5601
|
+
let integrityReport;
|
|
5602
|
+
try {
|
|
5603
|
+
integrityReport = checkIntegrity(aggregation, rootDir);
|
|
5604
|
+
} catch {
|
|
5605
|
+
}
|
|
5606
|
+
let componentAnchorIssues;
|
|
5607
|
+
try {
|
|
5608
|
+
const anchorReport = checkComponentAnchors(aggregation.symbols, rootDir);
|
|
5609
|
+
const issues = anchorReport.missing + anchorReport.outOfBounds;
|
|
5610
|
+
if (issues > 0) {
|
|
5611
|
+
componentAnchorIssues = issues;
|
|
5612
|
+
}
|
|
5613
|
+
} catch {
|
|
5614
|
+
}
|
|
5615
|
+
let purposeHealth;
|
|
5616
|
+
try {
|
|
5617
|
+
purposeHealth = checkPurposeHealth(aggregation.purposeFiles, rootDir);
|
|
5618
|
+
} catch {
|
|
5619
|
+
}
|
|
5620
|
+
let crossFileIssues;
|
|
5621
|
+
try {
|
|
5622
|
+
const parsedFiles = [];
|
|
5623
|
+
for (const filePath of aggregation.purposeFiles) {
|
|
5624
|
+
const result = parsePurposeFile(filePath);
|
|
5625
|
+
if (result.data) {
|
|
5626
|
+
parsedFiles.push({ filePath, data: result.data });
|
|
5627
|
+
}
|
|
5628
|
+
}
|
|
5629
|
+
if (parsedFiles.length > 0) {
|
|
5630
|
+
const crossResult = validateCrossFile(parsedFiles);
|
|
5631
|
+
const warningCount = crossResult.issues.length;
|
|
5632
|
+
if (warningCount > 0) {
|
|
5633
|
+
crossFileIssues = warningCount;
|
|
5634
|
+
}
|
|
5635
|
+
}
|
|
5636
|
+
} catch {
|
|
5637
|
+
}
|
|
4800
5638
|
const breakdown = {};
|
|
4801
5639
|
for (const sym of aggregation.symbols) {
|
|
4802
5640
|
breakdown[sym.type] = (breakdown[sym.type] || 0) + 1;
|
|
4803
5641
|
}
|
|
5642
|
+
const componentTypeBreakdown = {};
|
|
5643
|
+
for (const sym of aggregation.symbols) {
|
|
5644
|
+
if (sym.type === "component" && sym.componentType) {
|
|
5645
|
+
componentTypeBreakdown[sym.componentType] = (componentTypeBreakdown[sym.componentType] || 0) + 1;
|
|
5646
|
+
}
|
|
5647
|
+
}
|
|
4804
5648
|
return {
|
|
4805
5649
|
action: "reindex",
|
|
4806
5650
|
filesWritten,
|
|
@@ -4809,23 +5653,38 @@ async function rebuildStaticFiles(rootDir, ctx) {
|
|
|
4809
5653
|
flowCount,
|
|
4810
5654
|
aspectGraphStats,
|
|
4811
5655
|
personaCount,
|
|
4812
|
-
protocolHealth
|
|
5656
|
+
protocolHealth,
|
|
5657
|
+
...Object.keys(componentTypeBreakdown).length > 0 ? { componentTypeBreakdown } : {},
|
|
5658
|
+
...universityStats ? { universityStats } : {},
|
|
5659
|
+
...integrityReport ? { integrityReport } : {},
|
|
5660
|
+
...componentAnchorIssues !== void 0 ? { componentAnchorIssues } : {},
|
|
5661
|
+
...purposeHealth ? { purposeHealth } : {},
|
|
5662
|
+
...crossFileIssues !== void 0 ? { crossFileIssues } : {}
|
|
4813
5663
|
};
|
|
4814
5664
|
}
|
|
4815
5665
|
function buildNavigatorData(rootDir, aggregation) {
|
|
5666
|
+
const symbolsByComponentType = {};
|
|
5667
|
+
for (const sym of aggregation.symbols) {
|
|
5668
|
+
if (sym.type === "component" && sym.componentType) {
|
|
5669
|
+
const ct = sym.componentType;
|
|
5670
|
+
if (!symbolsByComponentType[ct]) symbolsByComponentType[ct] = [];
|
|
5671
|
+
symbolsByComponentType[ct].push(sym.symbol);
|
|
5672
|
+
}
|
|
5673
|
+
}
|
|
4816
5674
|
return {
|
|
4817
5675
|
version: "1.0",
|
|
4818
5676
|
generated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4819
5677
|
structure: buildStructure(rootDir),
|
|
4820
5678
|
key_files: buildKeyFiles(rootDir),
|
|
4821
5679
|
skip_patterns: buildSkipPatterns(rootDir),
|
|
4822
|
-
symbols: buildSymbolMap(aggregation.symbols, aggregation.purposeFiles, rootDir)
|
|
5680
|
+
symbols: buildSymbolMap(aggregation.symbols, aggregation.purposeFiles, rootDir),
|
|
5681
|
+
...Object.keys(symbolsByComponentType).length > 0 ? { symbolsByComponentType } : {}
|
|
4823
5682
|
};
|
|
4824
5683
|
}
|
|
4825
5684
|
function buildStructure(rootDir) {
|
|
4826
5685
|
const structure = {};
|
|
4827
5686
|
for (const [category, patterns] of Object.entries(DIRECTORY_PATTERNS)) {
|
|
4828
|
-
const existingPaths = patterns.filter((p) =>
|
|
5687
|
+
const existingPaths = patterns.filter((p) => fs9.existsSync(path10.join(rootDir, p)));
|
|
4829
5688
|
if (existingPaths.length > 0) {
|
|
4830
5689
|
const symbolInfo = Object.values(SYMBOL_CATEGORIES).find((s) => s.category === category);
|
|
4831
5690
|
structure[category] = { paths: existingPaths, symbol: symbolInfo?.prefix || "@" };
|
|
@@ -4836,7 +5695,7 @@ function buildStructure(rootDir) {
|
|
|
4836
5695
|
function buildKeyFiles(rootDir) {
|
|
4837
5696
|
const keyFiles = {};
|
|
4838
5697
|
for (const [category, patterns] of Object.entries(KEY_FILE_PATTERNS)) {
|
|
4839
|
-
const existingPaths = patterns.filter((p) =>
|
|
5698
|
+
const existingPaths = patterns.filter((p) => fs9.existsSync(path10.join(rootDir, p)));
|
|
4840
5699
|
if (existingPaths.length > 0) {
|
|
4841
5700
|
keyFiles[category] = existingPaths;
|
|
4842
5701
|
}
|
|
@@ -4852,10 +5711,10 @@ function buildSkipPatterns(rootDir) {
|
|
|
4852
5711
|
unless_testing: [...DEFAULT_SKIP_PATTERNS.unless_testing],
|
|
4853
5712
|
unless_docs: [...DEFAULT_SKIP_PATTERNS.unless_docs]
|
|
4854
5713
|
};
|
|
4855
|
-
const gitignorePath =
|
|
4856
|
-
if (
|
|
5714
|
+
const gitignorePath = path10.join(rootDir, ".gitignore");
|
|
5715
|
+
if (fs9.existsSync(gitignorePath)) {
|
|
4857
5716
|
try {
|
|
4858
|
-
const content =
|
|
5717
|
+
const content = fs9.readFileSync(gitignorePath, "utf8");
|
|
4859
5718
|
const gitignorePatterns = content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).filter(
|
|
4860
5719
|
(line) => line.endsWith("/") || line.includes("*") || ["node_modules", "dist", "build", ".cache"].some((p) => line.includes(p))
|
|
4861
5720
|
).slice(0, 20);
|
|
@@ -4904,11 +5763,11 @@ function buildSymbolMap(symbols, purposeFiles, _rootDir) {
|
|
|
4904
5763
|
symbolMap[symbolId] = symbol.filePath;
|
|
4905
5764
|
} else {
|
|
4906
5765
|
const matchingPurpose = purposeFiles.find((pf) => {
|
|
4907
|
-
const dir =
|
|
5766
|
+
const dir = path10.dirname(pf);
|
|
4908
5767
|
return dir.toLowerCase().includes(symbol.id.toLowerCase());
|
|
4909
5768
|
});
|
|
4910
5769
|
if (matchingPurpose) {
|
|
4911
|
-
symbolMap[symbolId] =
|
|
5770
|
+
symbolMap[symbolId] = path10.dirname(matchingPurpose) + "/";
|
|
4912
5771
|
}
|
|
4913
5772
|
}
|
|
4914
5773
|
}
|
|
@@ -4919,8 +5778,8 @@ function generateFlowIndex(rootDir, purposeFiles) {
|
|
|
4919
5778
|
const symbolToFlows = {};
|
|
4920
5779
|
for (const filePath of purposeFiles) {
|
|
4921
5780
|
try {
|
|
4922
|
-
const content =
|
|
4923
|
-
const data =
|
|
5781
|
+
const content = fs9.readFileSync(filePath, "utf8");
|
|
5782
|
+
const data = yaml8.load(content);
|
|
4924
5783
|
if (!data?.flows) continue;
|
|
4925
5784
|
if (Array.isArray(data.flows)) {
|
|
4926
5785
|
for (const flowItem of data.flows) {
|
|
@@ -4933,7 +5792,7 @@ function generateFlowIndex(rootDir, purposeFiles) {
|
|
|
4933
5792
|
id: flowId,
|
|
4934
5793
|
description: flow.description || "",
|
|
4935
5794
|
steps,
|
|
4936
|
-
definedIn:
|
|
5795
|
+
definedIn: path10.relative(rootDir, filePath)
|
|
4937
5796
|
};
|
|
4938
5797
|
indexFlowSymbols(flowId, steps, symbolToFlows);
|
|
4939
5798
|
}
|
|
@@ -4949,7 +5808,7 @@ function generateFlowIndex(rootDir, purposeFiles) {
|
|
|
4949
5808
|
trigger: flowDef.trigger,
|
|
4950
5809
|
steps,
|
|
4951
5810
|
validation: flowDef.validation,
|
|
4952
|
-
definedIn:
|
|
5811
|
+
definedIn: path10.relative(rootDir, filePath)
|
|
4953
5812
|
};
|
|
4954
5813
|
indexFlowSymbols(flowId, steps, symbolToFlows);
|
|
4955
5814
|
}
|
|
@@ -5059,6 +5918,20 @@ export {
|
|
|
5059
5918
|
updateProtocol,
|
|
5060
5919
|
validateProtocol,
|
|
5061
5920
|
detectProtocolSuggestion,
|
|
5921
|
+
loadUniversityConfig,
|
|
5922
|
+
loadNote,
|
|
5923
|
+
saveNote,
|
|
5924
|
+
loadQuiz,
|
|
5925
|
+
saveQuiz,
|
|
5926
|
+
loadPath,
|
|
5927
|
+
savePath,
|
|
5928
|
+
loadDiplomas,
|
|
5929
|
+
saveDiploma,
|
|
5930
|
+
searchContent,
|
|
5931
|
+
rebuildUniversityIndex,
|
|
5932
|
+
validateUniversityContent,
|
|
5933
|
+
getAffectedUniversityContent,
|
|
5934
|
+
getOnboardingSequence,
|
|
5062
5935
|
getReindexToolsList,
|
|
5063
5936
|
handleReindexTool,
|
|
5064
5937
|
rebuildStaticFiles
|