@hamak/smart-data-dico 1.19.0 → 1.20.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/backend/dist/server.mjs +544 -440
- package/frontend/dist/assets/{abnfDiagram-VRR7QNED-5bf36645.js → abnfDiagram-VRR7QNED-6f198720.js} +1 -1
- package/frontend/dist/assets/{arc-77b99720.js → arc-54f6dc83.js} +1 -1
- package/frontend/dist/assets/architecture-TIHT7OUA-8222218c.js +1 -0
- package/frontend/dist/assets/{architectureDiagram-ZJ3FMSHR-842d4b7e.js → architectureDiagram-ZJ3FMSHR-6dabc0f0.js} +1 -1
- package/frontend/dist/assets/{blockDiagram-677ZJIJ3-ce2d6065.js → blockDiagram-677ZJIJ3-90ab5147.js} +1 -1
- package/frontend/dist/assets/{c4Diagram-LMCZKHZV-f6f33075.js → c4Diagram-LMCZKHZV-b5a971e3.js} +1 -1
- package/frontend/dist/assets/channel-98106291.js +1 -0
- package/frontend/dist/assets/{chunk-2Q5K7J3B-e048f182.js → chunk-2Q5K7J3B-ac60a5fb.js} +1 -1
- package/frontend/dist/assets/{chunk-32BRIVSS-9f8a0696.js → chunk-32BRIVSS-ddb07474.js} +1 -1
- package/frontend/dist/assets/{chunk-5VM5RSS4-8207b825.js → chunk-5VM5RSS4-2db6a06c.js} +1 -1
- package/frontend/dist/assets/{chunk-EX3LRPZG-4964b359.js → chunk-EX3LRPZG-baa20613.js} +1 -1
- package/frontend/dist/assets/{chunk-JWPE2WC7-8cf4213d.js → chunk-JWPE2WC7-18647660.js} +1 -1
- package/frontend/dist/assets/{chunk-MOJQB5TN-7c50afe9.js → chunk-MOJQB5TN-dc09b962.js} +1 -1
- package/frontend/dist/assets/{chunk-PUDLZKDR-49760488.js → chunk-PUDLZKDR-6287f125.js} +1 -1
- package/frontend/dist/assets/{chunk-RYQCIY6F-0690c709.js → chunk-RYQCIY6F-9786102e.js} +1 -1
- package/frontend/dist/assets/{chunk-V7JOEXUC-4c92f24d.js → chunk-V7JOEXUC-158db19a.js} +1 -1
- package/frontend/dist/assets/{chunk-VR4S4FIN-73477ca7.js → chunk-VR4S4FIN-8a5a7523.js} +1 -1
- package/frontend/dist/assets/{chunk-XXDRQBXY-9faa344e.js → chunk-XXDRQBXY-f0aeb3a2.js} +1 -1
- package/frontend/dist/assets/classDiagram-OUVF2IWQ-6fddb962.js +1 -0
- package/frontend/dist/assets/classDiagram-v2-EOCWNBFH-6fddb962.js +1 -0
- package/frontend/dist/assets/{cose-bilkent-JH36ORCC-eca50abe.js → cose-bilkent-JH36ORCC-97aedf6d.js} +1 -1
- package/frontend/dist/assets/cynefin-VYW2F7L2-39a09b7c.js +1 -0
- package/frontend/dist/assets/{cynefinDiagram-TSTJHNR4-9daa8c60.js → cynefinDiagram-TSTJHNR4-7414b003.js} +1 -1
- package/frontend/dist/assets/{dagre-VKFMJZFB-8cadf293.js → dagre-VKFMJZFB-22f0ea2d.js} +1 -1
- package/frontend/dist/assets/{diagram-FQU43EPY-5e4d3a2a.js → diagram-FQU43EPY-54e670d8.js} +1 -1
- package/frontend/dist/assets/{diagram-G47NLZAW-07630f46.js → diagram-G47NLZAW-41216f63.js} +1 -1
- package/frontend/dist/assets/{diagram-NH7WQ7WH-58c6af5e.js → diagram-NH7WQ7WH-2de1d465.js} +1 -1
- package/frontend/dist/assets/{diagram-OA4YK3LP-b0124115.js → diagram-OA4YK3LP-4be5e2c2.js} +1 -1
- package/frontend/dist/assets/{diagram-WEI45ONY-f942b2f7.js → diagram-WEI45ONY-0d1d5dd3.js} +1 -1
- package/frontend/dist/assets/{ebnfDiagram-CCIWWBDH-42fc377c.js → ebnfDiagram-CCIWWBDH-235afe69.js} +1 -1
- package/frontend/dist/assets/{erDiagram-Q63AITRT-46209ae5.js → erDiagram-Q63AITRT-bfbc0736.js} +1 -1
- package/frontend/dist/assets/eventmodeling-45OFAUF4-c1d13b17.js +1 -0
- package/frontend/dist/assets/flowDiagram-23GEKE2U-50c416a3.js +1 -0
- package/frontend/dist/assets/{ganttDiagram-NO4QXBWP-e368e881.js → ganttDiagram-NO4QXBWP-d767d5bd.js} +1 -1
- package/frontend/dist/assets/gitGraph-TEB2WS4Q-53567b0e.js +1 -0
- package/frontend/dist/assets/{gitGraphDiagram-IHSO6WYX-245b8d31.js → gitGraphDiagram-IHSO6WYX-0af7483d.js} +1 -1
- package/frontend/dist/assets/{index-419b7a82.css → index-017e890a.css} +1 -1
- package/frontend/dist/assets/index-25c4649a.js +574 -0
- package/frontend/dist/assets/info-DKCQHKI2-dfc9537f.js +1 -0
- package/frontend/dist/assets/{infoDiagram-FWYZ7A6U-af51f32a.js → infoDiagram-FWYZ7A6U-703eef1c.js} +1 -1
- package/frontend/dist/assets/{ishikawaDiagram-FXEZZL3T-9f2be8c6.js → ishikawaDiagram-FXEZZL3T-b6e22c6c.js} +1 -1
- package/frontend/dist/assets/{journeyDiagram-5HDEW3XC-1e5b0d35.js → journeyDiagram-5HDEW3XC-7ff9040e.js} +1 -1
- package/frontend/dist/assets/{kanban-definition-HUTT4EX6-89d91f2e.js → kanban-definition-HUTT4EX6-3ec9df2c.js} +1 -1
- package/frontend/dist/assets/{linear-5deaa3d1.js → linear-a840de21.js} +1 -1
- package/frontend/dist/assets/{mermaid-parser.core-a7dd4921.js → mermaid-parser.core-35fa1177.js} +2 -2
- package/frontend/dist/assets/{mermaid.core-d2196c74.js → mermaid.core-33299d26.js} +3 -3
- package/frontend/dist/assets/{mindmap-definition-LN4V7U3C-36c63353.js → mindmap-definition-LN4V7U3C-29c921b2.js} +1 -1
- package/frontend/dist/assets/packet-7NZHBO7P-e3add55d.js +1 -0
- package/frontend/dist/assets/{pegDiagram-2B236MQR-30a8ce0f.js → pegDiagram-2B236MQR-c9fd64ea.js} +1 -1
- package/frontend/dist/assets/pie-RZYD4A2V-3cdcefc3.js +1 -0
- package/frontend/dist/assets/{pieDiagram-ENE6RG2P-639c88ff.js → pieDiagram-ENE6RG2P-d21bc176.js} +1 -1
- package/frontend/dist/assets/{quadrantDiagram-ABIIQ3AL-6ff9cdb3.js → quadrantDiagram-ABIIQ3AL-b4dc829d.js} +1 -1
- package/frontend/dist/assets/radar-I7S5WNFK-29afeb7a.js +1 -0
- package/frontend/dist/assets/railroad-3IZDKUUU-6e6a0bb5.js +1 -0
- package/frontend/dist/assets/railroad-abnf-AHOZXSZD-8e00f421.js +1 -0
- package/frontend/dist/assets/railroad-ebnf-EBAXGLYW-89a4f0dc.js +1 -0
- package/frontend/dist/assets/railroad-peg-LSFZ7HO6-b2782816.js +1 -0
- package/frontend/dist/assets/{railroadDiagram-RFXS5EU6-ac789252.js → railroadDiagram-RFXS5EU6-404ec27d.js} +1 -1
- package/frontend/dist/assets/{requirementDiagram-TGXJPOKE-0ce87e1d.js → requirementDiagram-TGXJPOKE-9b582bdd.js} +1 -1
- package/frontend/dist/assets/{sankeyDiagram-HTMAVEWB-4a0abb39.js → sankeyDiagram-HTMAVEWB-f6e0379c.js} +1 -1
- package/frontend/dist/assets/{sequenceDiagram-DBY2YBRQ-284dc47a.js → sequenceDiagram-DBY2YBRQ-508afe00.js} +1 -1
- package/frontend/dist/assets/{sizeCapture-X5ZJPWSS-253d1130.js → sizeCapture-X5ZJPWSS-ee602857.js} +1 -1
- package/frontend/dist/assets/{stateDiagram-2N3HPSRC-5baf911d.js → stateDiagram-2N3HPSRC-1e66e9f0.js} +1 -1
- package/frontend/dist/assets/stateDiagram-v2-6OUMAXLB-660e6df7.js +1 -0
- package/frontend/dist/assets/{swimlanes-5IMT3BWC-1587bceb.js → swimlanes-5IMT3BWC-5fa2813b.js} +1 -1
- package/frontend/dist/assets/swimlanesDiagram-G3AALYLV-f402ef76.js +8 -0
- package/frontend/dist/assets/{timeline-definition-FHXFAJF6-644a682a.js → timeline-definition-FHXFAJF6-12edf3b3.js} +1 -1
- package/frontend/dist/assets/treeView-QDETBFTQ-144f174a.js +1 -0
- package/frontend/dist/assets/treemap-6X3UGDF4-1c06331f.js +1 -0
- package/frontend/dist/assets/{vennDiagram-L72KCM5P-27901c69.js → vennDiagram-L72KCM5P-6f3acb6a.js} +1 -1
- package/frontend/dist/assets/wardley-OPB4EBWU-abf74bee.js +1 -0
- package/frontend/dist/assets/{wardleyDiagram-EHGQE667-7816c0a5.js → wardleyDiagram-EHGQE667-bf6c6922.js} +1 -1
- package/frontend/dist/assets/{xychartDiagram-FW5EYKEG-a3ce4246.js → xychartDiagram-FW5EYKEG-3f6dfba6.js} +1 -1
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/frontend/dist/assets/architecture-TIHT7OUA-a639eab7.js +0 -1
- package/frontend/dist/assets/channel-58a90d4a.js +0 -1
- package/frontend/dist/assets/classDiagram-OUVF2IWQ-2985892f.js +0 -1
- package/frontend/dist/assets/classDiagram-v2-EOCWNBFH-2985892f.js +0 -1
- package/frontend/dist/assets/cynefin-VYW2F7L2-68d8e42f.js +0 -1
- package/frontend/dist/assets/eventmodeling-45OFAUF4-ca978038.js +0 -1
- package/frontend/dist/assets/flowDiagram-23GEKE2U-e940d995.js +0 -1
- package/frontend/dist/assets/gitGraph-TEB2WS4Q-8176fbb9.js +0 -1
- package/frontend/dist/assets/index-647c7909.js +0 -559
- package/frontend/dist/assets/info-DKCQHKI2-fa612c43.js +0 -1
- package/frontend/dist/assets/packet-7NZHBO7P-069cb37a.js +0 -1
- package/frontend/dist/assets/pie-RZYD4A2V-58f1df35.js +0 -1
- package/frontend/dist/assets/radar-I7S5WNFK-72e8d492.js +0 -1
- package/frontend/dist/assets/railroad-3IZDKUUU-c75f2799.js +0 -1
- package/frontend/dist/assets/railroad-abnf-AHOZXSZD-c58af3ba.js +0 -1
- package/frontend/dist/assets/railroad-ebnf-EBAXGLYW-99be0db3.js +0 -1
- package/frontend/dist/assets/railroad-peg-LSFZ7HO6-e22021de.js +0 -1
- package/frontend/dist/assets/stateDiagram-v2-6OUMAXLB-f84f63b8.js +0 -1
- package/frontend/dist/assets/swimlanesDiagram-G3AALYLV-b6a155f6.js +0 -8
- package/frontend/dist/assets/treeView-QDETBFTQ-d9f2bb66.js +0 -1
- package/frontend/dist/assets/treemap-6X3UGDF4-3377c08d.js +0 -1
- package/frontend/dist/assets/wardley-OPB4EBWU-05517e1a.js +0 -1
package/backend/dist/server.mjs
CHANGED
|
@@ -37683,7 +37683,8 @@ function normalizeRelationship(rel) {
|
|
|
37683
37683
|
}
|
|
37684
37684
|
function fillAttributeDefaults(entity) {
|
|
37685
37685
|
const fix = /* @__PURE__ */ __name((attrs) => {
|
|
37686
|
-
|
|
37686
|
+
if (!Array.isArray(attrs)) return;
|
|
37687
|
+
for (const a of attrs) {
|
|
37687
37688
|
if (a.required === void 0) a.required = false;
|
|
37688
37689
|
if (a.description === void 0) a.description = "";
|
|
37689
37690
|
if (a.properties) fix(a.properties);
|
|
@@ -45760,7 +45761,7 @@ var init_dictionaryService = __esm({
|
|
|
45760
45761
|
let relationships = [];
|
|
45761
45762
|
let cases = [];
|
|
45762
45763
|
try {
|
|
45763
|
-
const model = await loadPackage(
|
|
45764
|
+
const model = await loadPackage(String(dirPath));
|
|
45764
45765
|
entities = model.entities;
|
|
45765
45766
|
relationships = model.relationships;
|
|
45766
45767
|
cases = model.cases.map((c) => ({
|
|
@@ -48645,6 +48646,51 @@ var init_serviceService = __esm({
|
|
|
48645
48646
|
};
|
|
48646
48647
|
}
|
|
48647
48648
|
}
|
|
48649
|
+
/**
|
|
48650
|
+
* Move an entity from one package to another (#move-entity). The entity keeps
|
|
48651
|
+
* its UUID, so every UUID-based reference (relationships — cross-package is
|
|
48652
|
+
* first-class — cases, diagrams, perspectives) keeps resolving; nothing is
|
|
48653
|
+
* orphaned. We write the entity into the target package, then remove it from
|
|
48654
|
+
* the source via the projection directly — this bypasses deleteEntity's
|
|
48655
|
+
* same-package relationship guard, which is meant for destruction, not a
|
|
48656
|
+
* relocation where the references remain valid.
|
|
48657
|
+
*/
|
|
48658
|
+
async moveEntity(sourcePackage, entityName, targetPackage) {
|
|
48659
|
+
logger.info(`Moving entity: ${sourcePackage}.${entityName} -> ${targetPackage}`);
|
|
48660
|
+
if (!targetPackage || targetPackage === sourcePackage) {
|
|
48661
|
+
return { success: false, errors: ["Target package must differ from the source package"] };
|
|
48662
|
+
}
|
|
48663
|
+
try {
|
|
48664
|
+
const entity = await readEntityFile(sourcePackage, entityName);
|
|
48665
|
+
if (!entity) {
|
|
48666
|
+
return { success: false, errors: [`Entity ${sourcePackage}.${entityName} not found`] };
|
|
48667
|
+
}
|
|
48668
|
+
const packages = await listMicroservices();
|
|
48669
|
+
if (!packages.includes(targetPackage)) {
|
|
48670
|
+
return { success: false, errors: [`Target package '${targetPackage}' does not exist`] };
|
|
48671
|
+
}
|
|
48672
|
+
const existingInTarget = await readEntityFile(targetPackage, entityName);
|
|
48673
|
+
if (existingInTarget) {
|
|
48674
|
+
return {
|
|
48675
|
+
success: false,
|
|
48676
|
+
errors: [`Target package '${targetPackage}' already has an entity named '${entityName}'`]
|
|
48677
|
+
};
|
|
48678
|
+
}
|
|
48679
|
+
const projection = getProjection(wsId("dictionaries"));
|
|
48680
|
+
entity.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
48681
|
+
await projection.writeEntity(`packages/${targetPackage}/entities/${entity.name}`, entity);
|
|
48682
|
+
const removed = await projection.deleteEntity(`packages/${sourcePackage}/entities/${entity.name}`);
|
|
48683
|
+
if (!removed) {
|
|
48684
|
+
await projection.deleteEntity(`packages/${targetPackage}/entities/${entity.name}`).catch(() => {
|
|
48685
|
+
});
|
|
48686
|
+
return { success: false, errors: ["Failed to remove the entity from the source package"] };
|
|
48687
|
+
}
|
|
48688
|
+
return { success: true, errors: [] };
|
|
48689
|
+
} catch (error48) {
|
|
48690
|
+
logger.error(`Error moving entity: ${error48}`);
|
|
48691
|
+
return { success: false, errors: [`Error moving entity: ${error48}`] };
|
|
48692
|
+
}
|
|
48693
|
+
}
|
|
48648
48694
|
// --- Relationship CRUD ---
|
|
48649
48695
|
async getPackageRelationships(packageName) {
|
|
48650
48696
|
const packagePath = getPackagePath(packageName);
|
|
@@ -49107,424 +49153,6 @@ var init_serviceService = __esm({
|
|
|
49107
49153
|
}
|
|
49108
49154
|
});
|
|
49109
49155
|
|
|
49110
|
-
// backend/src/models/Rule.ts
|
|
49111
|
-
function validateRule(rule) {
|
|
49112
|
-
const errors = [];
|
|
49113
|
-
if (!rule.name || typeof rule.name !== "string") {
|
|
49114
|
-
errors.push("Rule name is required");
|
|
49115
|
-
} else if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(rule.name)) {
|
|
49116
|
-
errors.push("Rule name must be kebab-case (lowercase letters, numbers, hyphens)");
|
|
49117
|
-
}
|
|
49118
|
-
if (!rule.description || typeof rule.description !== "string") {
|
|
49119
|
-
errors.push("Rule description is required");
|
|
49120
|
-
}
|
|
49121
|
-
if (!rule.severity || !["info", "warning", "error"].includes(rule.severity)) {
|
|
49122
|
-
errors.push("Rule severity must be one of: info, warning, error");
|
|
49123
|
-
}
|
|
49124
|
-
if (!rule.enforcement || !["save", "process", "advisory"].includes(rule.enforcement)) {
|
|
49125
|
-
errors.push("Rule enforcement must be one of: save, process, advisory");
|
|
49126
|
-
}
|
|
49127
|
-
if (!rule.scope || !["entity", "package", "case", "global"].includes(rule.scope)) {
|
|
49128
|
-
errors.push("Rule scope must be one of: entity, package, case, global");
|
|
49129
|
-
}
|
|
49130
|
-
if (!Array.isArray(rule.targets) || rule.targets.length === 0) {
|
|
49131
|
-
errors.push("Rule must have at least one target");
|
|
49132
|
-
}
|
|
49133
|
-
if (rule.scope === "entity" && !rule.entityUuid) {
|
|
49134
|
-
errors.push("Entity-scoped rules must specify entityUuid");
|
|
49135
|
-
}
|
|
49136
|
-
if (rule.scope === "package" && !rule.packageName) {
|
|
49137
|
-
errors.push("Package-scoped rules must specify packageName");
|
|
49138
|
-
}
|
|
49139
|
-
if (rule.scope === "case" && !rule.caseUuid) {
|
|
49140
|
-
errors.push("Case-scoped rules must specify caseUuid");
|
|
49141
|
-
}
|
|
49142
|
-
if (rule.enforcement === "process") {
|
|
49143
|
-
const stageField = (rule.metadata || []).find((m) => m.name === "process-stage-field");
|
|
49144
|
-
if (!stageField || !stageField.value) {
|
|
49145
|
-
errors.push("Process-enforcement rules must reference a metadata field via process-stage-field");
|
|
49146
|
-
}
|
|
49147
|
-
}
|
|
49148
|
-
return errors;
|
|
49149
|
-
}
|
|
49150
|
-
var init_Rule = __esm({
|
|
49151
|
-
"backend/src/models/Rule.ts"() {
|
|
49152
|
-
"use strict";
|
|
49153
|
-
__name(validateRule, "validateRule");
|
|
49154
|
-
}
|
|
49155
|
-
});
|
|
49156
|
-
|
|
49157
|
-
// backend/src/services/ruleService.ts
|
|
49158
|
-
var ruleService_exports = {};
|
|
49159
|
-
__export(ruleService_exports, {
|
|
49160
|
-
ruleService: () => ruleService
|
|
49161
|
-
});
|
|
49162
|
-
var RuleService, ruleService;
|
|
49163
|
-
var init_ruleService = __esm({
|
|
49164
|
-
"backend/src/services/ruleService.ts"() {
|
|
49165
|
-
"use strict";
|
|
49166
|
-
init_Rule();
|
|
49167
|
-
init_fileOperations();
|
|
49168
|
-
init_uuid();
|
|
49169
|
-
init_logger();
|
|
49170
|
-
init_ProjectionRegistry();
|
|
49171
|
-
init_types();
|
|
49172
|
-
RuleService = class {
|
|
49173
|
-
static {
|
|
49174
|
-
__name(this, "RuleService");
|
|
49175
|
-
}
|
|
49176
|
-
/** List all rules from all storage scopes, optionally filtered. */
|
|
49177
|
-
async listRules(filters = {}) {
|
|
49178
|
-
const all = [];
|
|
49179
|
-
if (!filters.scope || filters.scope === "entity") {
|
|
49180
|
-
const files = await listAllEntityRuleFiles();
|
|
49181
|
-
for (const { service, entityUuid } of files) {
|
|
49182
|
-
const rules = await readEntityRules(service, entityUuid);
|
|
49183
|
-
all.push(...rules);
|
|
49184
|
-
}
|
|
49185
|
-
}
|
|
49186
|
-
if (!filters.scope || filters.scope === "package") {
|
|
49187
|
-
const packages = filters.packageName ? [filters.packageName] : await listPackagesWithRules();
|
|
49188
|
-
for (const pkg of packages) {
|
|
49189
|
-
const rules = await readPackageRules(pkg);
|
|
49190
|
-
all.push(...rules);
|
|
49191
|
-
}
|
|
49192
|
-
}
|
|
49193
|
-
if (!filters.scope || filters.scope === "global") {
|
|
49194
|
-
const globalRules = await readGlobalRules();
|
|
49195
|
-
all.push(...globalRules);
|
|
49196
|
-
}
|
|
49197
|
-
if (!filters.scope || filters.scope === "case") {
|
|
49198
|
-
if (filters.caseUuid) {
|
|
49199
|
-
const rules = await readCaseRules(filters.caseUuid);
|
|
49200
|
-
all.push(...rules);
|
|
49201
|
-
} else {
|
|
49202
|
-
const cases = await listCases();
|
|
49203
|
-
for (const c of cases) {
|
|
49204
|
-
const rules = c.rules || [];
|
|
49205
|
-
all.push(...rules);
|
|
49206
|
-
}
|
|
49207
|
-
}
|
|
49208
|
-
}
|
|
49209
|
-
for (const rule of all) {
|
|
49210
|
-
if (!rule.enforcement) rule.enforcement = "advisory";
|
|
49211
|
-
}
|
|
49212
|
-
return all.filter((rule) => {
|
|
49213
|
-
if (filters.severity && rule.severity !== filters.severity) return false;
|
|
49214
|
-
if (filters.enforcement && rule.enforcement !== filters.enforcement) return false;
|
|
49215
|
-
if (filters.targetUuid) {
|
|
49216
|
-
const hit = rule.targets.some(
|
|
49217
|
-
(t) => t.uuid === filters.targetUuid || t.entityUuid === filters.targetUuid
|
|
49218
|
-
);
|
|
49219
|
-
if (!hit) return false;
|
|
49220
|
-
}
|
|
49221
|
-
return true;
|
|
49222
|
-
});
|
|
49223
|
-
}
|
|
49224
|
-
/** Get a single rule by uuid (scans all scopes). */
|
|
49225
|
-
async getRule(uuid3) {
|
|
49226
|
-
const all = await this.listRules();
|
|
49227
|
-
return all.find((r) => r.uuid === uuid3) || null;
|
|
49228
|
-
}
|
|
49229
|
-
/** List rules whose targets include this entity (or any of its attributes). */
|
|
49230
|
-
async listRulesForEntity(entityUuid) {
|
|
49231
|
-
const all = await this.listRules();
|
|
49232
|
-
return all.filter(
|
|
49233
|
-
(rule) => rule.targets.some(
|
|
49234
|
-
(t) => t.uuid === entityUuid || t.entityUuid === entityUuid
|
|
49235
|
-
)
|
|
49236
|
-
);
|
|
49237
|
-
}
|
|
49238
|
-
/** Create a rule. Storage location is determined by `scope`. */
|
|
49239
|
-
async createRule(input) {
|
|
49240
|
-
if (!input.enforcement) input.enforcement = "advisory";
|
|
49241
|
-
const errors = validateRule(input);
|
|
49242
|
-
if (errors.length > 0) {
|
|
49243
|
-
return { success: false, errors };
|
|
49244
|
-
}
|
|
49245
|
-
let rule = {
|
|
49246
|
-
uuid: generateUUID(),
|
|
49247
|
-
name: input.name,
|
|
49248
|
-
description: input.description,
|
|
49249
|
-
severity: input.severity,
|
|
49250
|
-
enforcement: input.enforcement,
|
|
49251
|
-
scope: input.scope,
|
|
49252
|
-
targets: input.targets,
|
|
49253
|
-
packageName: input.packageName,
|
|
49254
|
-
entityUuid: input.entityUuid,
|
|
49255
|
-
caseUuid: input.caseUuid,
|
|
49256
|
-
expression: input.expression,
|
|
49257
|
-
tags: input.tags,
|
|
49258
|
-
metadata: input.metadata,
|
|
49259
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
49260
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
49261
|
-
};
|
|
49262
|
-
rule = await this.applyAutoScope(rule);
|
|
49263
|
-
const saved = await this.saveRuleToScope(rule);
|
|
49264
|
-
if (!saved) return { success: false, errors: ["Failed to write rule to storage"] };
|
|
49265
|
-
return { success: true, rule };
|
|
49266
|
-
}
|
|
49267
|
-
/** Update an existing rule by uuid. Re-routes to new scope if scope changed. */
|
|
49268
|
-
async updateRule(uuid3, input) {
|
|
49269
|
-
const existing = await this.getRule(uuid3);
|
|
49270
|
-
if (!existing) return { success: false, errors: [`Rule ${uuid3} not found`] };
|
|
49271
|
-
let merged = {
|
|
49272
|
-
...existing,
|
|
49273
|
-
...input,
|
|
49274
|
-
uuid: existing.uuid,
|
|
49275
|
-
createdAt: existing.createdAt,
|
|
49276
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
49277
|
-
};
|
|
49278
|
-
const errors = validateRule(merged);
|
|
49279
|
-
if (errors.length > 0) return { success: false, errors };
|
|
49280
|
-
merged = await this.applyAutoScope(merged, existing.scope, existing.packageName);
|
|
49281
|
-
const scopeMoved = existing.scope !== merged.scope || existing.packageName !== merged.packageName || existing.entityUuid !== merged.entityUuid || existing.caseUuid !== merged.caseUuid;
|
|
49282
|
-
if (scopeMoved) {
|
|
49283
|
-
await this.removeRuleFromScope(existing);
|
|
49284
|
-
}
|
|
49285
|
-
const saved = await this.saveRuleToScope(merged);
|
|
49286
|
-
if (!saved) return { success: false, errors: ["Failed to write updated rule to storage"] };
|
|
49287
|
-
return { success: true, rule: merged };
|
|
49288
|
-
}
|
|
49289
|
-
/** Delete a rule by uuid. */
|
|
49290
|
-
async deleteRule(uuid3) {
|
|
49291
|
-
const existing = await this.getRule(uuid3);
|
|
49292
|
-
if (!existing) return { success: false, errors: [`Rule ${uuid3} not found`] };
|
|
49293
|
-
const removed = await this.removeRuleFromScope(existing);
|
|
49294
|
-
if (!removed) return { success: false, errors: ["Failed to remove rule from storage"] };
|
|
49295
|
-
return { success: true };
|
|
49296
|
-
}
|
|
49297
|
-
// ─── Private helpers: route to the right storage location ────────────────
|
|
49298
|
-
async saveRuleToScope(rule) {
|
|
49299
|
-
const projection = getProjection(wsId("dictionaries"));
|
|
49300
|
-
switch (rule.scope) {
|
|
49301
|
-
case "entity": {
|
|
49302
|
-
if (!rule.entityUuid) return false;
|
|
49303
|
-
const files = await listAllEntityRuleFiles();
|
|
49304
|
-
let service = files.find((f) => f.entityUuid === rule.entityUuid)?.service;
|
|
49305
|
-
if (!service) service = rule.packageName;
|
|
49306
|
-
if (!service) {
|
|
49307
|
-
logger.error(`Cannot determine service for entity ${rule.entityUuid}`);
|
|
49308
|
-
return false;
|
|
49309
|
-
}
|
|
49310
|
-
const entity = await this.findEntityByUuid(service, rule.entityUuid);
|
|
49311
|
-
if (!entity) {
|
|
49312
|
-
logger.error(`Entity ${rule.entityUuid} not found in service ${service}`);
|
|
49313
|
-
return false;
|
|
49314
|
-
}
|
|
49315
|
-
const existing = entity.rules || [];
|
|
49316
|
-
const updatedRules = [...existing.filter((r) => r.uuid !== rule.uuid), rule];
|
|
49317
|
-
entity.rules = updatedRules.length > 0 ? updatedRules : void 0;
|
|
49318
|
-
const logicalPath = `packages/${service}/entities/${entity.name}`;
|
|
49319
|
-
try {
|
|
49320
|
-
await projection.writeEntity(logicalPath, entity);
|
|
49321
|
-
return true;
|
|
49322
|
-
} catch (e) {
|
|
49323
|
-
logger.error(`Failed to write entity-scope rule via projection: ${e.message}`);
|
|
49324
|
-
return false;
|
|
49325
|
-
}
|
|
49326
|
-
}
|
|
49327
|
-
case "package": {
|
|
49328
|
-
if (!rule.packageName) return false;
|
|
49329
|
-
const existing = await readPackageRules(rule.packageName);
|
|
49330
|
-
const updated = [...existing.filter((r) => r.uuid !== rule.uuid), rule];
|
|
49331
|
-
const packageLogicalPath = `packages/${rule.packageName}`;
|
|
49332
|
-
try {
|
|
49333
|
-
await projection.writePackageRules(packageLogicalPath, updated);
|
|
49334
|
-
return true;
|
|
49335
|
-
} catch (e) {
|
|
49336
|
-
logger.error(`Failed to write package-scope rules via projection: ${e.message}`);
|
|
49337
|
-
return false;
|
|
49338
|
-
}
|
|
49339
|
-
}
|
|
49340
|
-
case "case": {
|
|
49341
|
-
if (!rule.caseUuid) return false;
|
|
49342
|
-
const c = await readCaseFile(rule.caseUuid);
|
|
49343
|
-
if (!c) return false;
|
|
49344
|
-
const existing = c.rules || [];
|
|
49345
|
-
c.rules = [...existing.filter((r) => r.uuid !== rule.uuid), rule];
|
|
49346
|
-
c.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
49347
|
-
const targetPackage = await this.resolveCaseHomePackage(c);
|
|
49348
|
-
if (!targetPackage) return false;
|
|
49349
|
-
const caseLogicalPath = `packages/${targetPackage}/cases/${c.name}`;
|
|
49350
|
-
try {
|
|
49351
|
-
await projection.writeCase(caseLogicalPath, c);
|
|
49352
|
-
return true;
|
|
49353
|
-
} catch (e) {
|
|
49354
|
-
logger.error(`Failed to write case-scope rule via projection: ${e.message}`);
|
|
49355
|
-
return false;
|
|
49356
|
-
}
|
|
49357
|
-
}
|
|
49358
|
-
case "global": {
|
|
49359
|
-
const existing = await readGlobalRules();
|
|
49360
|
-
const updated = [...existing.filter((r) => r.uuid !== rule.uuid), rule];
|
|
49361
|
-
try {
|
|
49362
|
-
await projection.writeGlobalRules(updated);
|
|
49363
|
-
return true;
|
|
49364
|
-
} catch (e) {
|
|
49365
|
-
logger.error(`Failed to write global rules via projection: ${e.message}`);
|
|
49366
|
-
return false;
|
|
49367
|
-
}
|
|
49368
|
-
}
|
|
49369
|
-
default:
|
|
49370
|
-
return false;
|
|
49371
|
-
}
|
|
49372
|
-
}
|
|
49373
|
-
async removeRuleFromScope(rule) {
|
|
49374
|
-
const projection = getProjection(wsId("dictionaries"));
|
|
49375
|
-
switch (rule.scope) {
|
|
49376
|
-
case "entity": {
|
|
49377
|
-
if (!rule.entityUuid) return false;
|
|
49378
|
-
const files = await listAllEntityRuleFiles();
|
|
49379
|
-
const service = files.find((f) => f.entityUuid === rule.entityUuid)?.service ?? rule.packageName;
|
|
49380
|
-
if (!service) return false;
|
|
49381
|
-
const entity = await this.findEntityByUuid(service, rule.entityUuid);
|
|
49382
|
-
if (!entity) return false;
|
|
49383
|
-
const existing = entity.rules || [];
|
|
49384
|
-
const updatedRules = existing.filter((r) => r.uuid !== rule.uuid);
|
|
49385
|
-
entity.rules = updatedRules.length > 0 ? updatedRules : void 0;
|
|
49386
|
-
const logicalPath = `packages/${service}/entities/${entity.name}`;
|
|
49387
|
-
try {
|
|
49388
|
-
await projection.writeEntity(logicalPath, entity);
|
|
49389
|
-
return true;
|
|
49390
|
-
} catch (e) {
|
|
49391
|
-
logger.error(`Failed to remove entity-scope rule via projection: ${e.message}`);
|
|
49392
|
-
return false;
|
|
49393
|
-
}
|
|
49394
|
-
}
|
|
49395
|
-
case "package": {
|
|
49396
|
-
if (!rule.packageName) return false;
|
|
49397
|
-
const existing = await readPackageRules(rule.packageName);
|
|
49398
|
-
const updated = existing.filter((r) => r.uuid !== rule.uuid);
|
|
49399
|
-
const packageLogicalPath = `packages/${rule.packageName}`;
|
|
49400
|
-
try {
|
|
49401
|
-
await projection.writePackageRules(packageLogicalPath, updated);
|
|
49402
|
-
return true;
|
|
49403
|
-
} catch (e) {
|
|
49404
|
-
logger.error(`Failed to remove package-scope rule via projection: ${e.message}`);
|
|
49405
|
-
return false;
|
|
49406
|
-
}
|
|
49407
|
-
}
|
|
49408
|
-
case "case": {
|
|
49409
|
-
if (!rule.caseUuid) return false;
|
|
49410
|
-
const c = await readCaseFile(rule.caseUuid);
|
|
49411
|
-
if (!c) return false;
|
|
49412
|
-
const existing = c.rules || [];
|
|
49413
|
-
const updated = existing.filter((r) => r.uuid !== rule.uuid);
|
|
49414
|
-
c.rules = updated.length > 0 ? updated : void 0;
|
|
49415
|
-
c.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
49416
|
-
const targetPackage = await this.resolveCaseHomePackage(c);
|
|
49417
|
-
if (!targetPackage) return false;
|
|
49418
|
-
const caseLogicalPath = `packages/${targetPackage}/cases/${c.name}`;
|
|
49419
|
-
try {
|
|
49420
|
-
await projection.writeCase(caseLogicalPath, c);
|
|
49421
|
-
return true;
|
|
49422
|
-
} catch (e) {
|
|
49423
|
-
logger.error(`Failed to remove case-scope rule via projection: ${e.message}`);
|
|
49424
|
-
return false;
|
|
49425
|
-
}
|
|
49426
|
-
}
|
|
49427
|
-
case "global": {
|
|
49428
|
-
const existing = await readGlobalRules();
|
|
49429
|
-
const updated = existing.filter((r) => r.uuid !== rule.uuid);
|
|
49430
|
-
try {
|
|
49431
|
-
await projection.writeGlobalRules(updated);
|
|
49432
|
-
return true;
|
|
49433
|
-
} catch (e) {
|
|
49434
|
-
logger.error(`Failed to remove global rule via projection: ${e.message}`);
|
|
49435
|
-
return false;
|
|
49436
|
-
}
|
|
49437
|
-
}
|
|
49438
|
-
default:
|
|
49439
|
-
return false;
|
|
49440
|
-
}
|
|
49441
|
-
}
|
|
49442
|
-
/**
|
|
49443
|
-
* Load an entity from a package by uuid. Returns null if not found.
|
|
49444
|
-
* Used by entity-scope rule writes to round-trip the parent entity
|
|
49445
|
-
* through `projection.writeEntity`.
|
|
49446
|
-
*/
|
|
49447
|
-
async findEntityByUuid(service, entityUuid) {
|
|
49448
|
-
try {
|
|
49449
|
-
const pkg = await loadPackage(service);
|
|
49450
|
-
return pkg.entities.find((e) => e.uuid === entityUuid) ?? null;
|
|
49451
|
-
} catch (error48) {
|
|
49452
|
-
logger.error(`Error loading package ${service} for entity lookup: ${error48}`);
|
|
49453
|
-
return null;
|
|
49454
|
-
}
|
|
49455
|
-
}
|
|
49456
|
-
/**
|
|
49457
|
-
* Resolve the home package for a case so we can construct a
|
|
49458
|
-
* `packages/<pkg>/cases/<name>` logical path. Mirrors the heuristic in
|
|
49459
|
-
* caseService.ts / fileOperations.ts: existing-owner lookup by uuid first,
|
|
49460
|
-
* then first root entity's package, then first package on disk.
|
|
49461
|
-
*/
|
|
49462
|
-
async resolveCaseHomePackage(c) {
|
|
49463
|
-
const { listPackages: listPackages3 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
|
|
49464
|
-
const packages = await listPackages3();
|
|
49465
|
-
for (const pkg of packages) {
|
|
49466
|
-
try {
|
|
49467
|
-
const model = await loadPackage(pkg);
|
|
49468
|
-
if (model.ownership.caseByUuid.has(c.uuid)) return pkg;
|
|
49469
|
-
} catch {
|
|
49470
|
-
}
|
|
49471
|
-
}
|
|
49472
|
-
if (c.rootEntities && c.rootEntities.length > 0) {
|
|
49473
|
-
const rootUuid = c.rootEntities[0];
|
|
49474
|
-
for (const pkg of packages) {
|
|
49475
|
-
try {
|
|
49476
|
-
const model = await loadPackage(pkg);
|
|
49477
|
-
if (model.ownership.entityByUuid.has(rootUuid)) return pkg;
|
|
49478
|
-
} catch {
|
|
49479
|
-
}
|
|
49480
|
-
}
|
|
49481
|
-
}
|
|
49482
|
-
return packages[0] || null;
|
|
49483
|
-
}
|
|
49484
|
-
// ─── Auto-promote / auto-demote (#75) ────────────────────────────────
|
|
49485
|
-
/**
|
|
49486
|
-
* Determine the correct scope for a rule based on its targets.
|
|
49487
|
-
* Called before save. If targets span 2+ packages → global.
|
|
49488
|
-
* If all targets are in one package → that package's scope (keep
|
|
49489
|
-
* the caller's intent for entity vs package).
|
|
49490
|
-
*/
|
|
49491
|
-
resolveScope(rule) {
|
|
49492
|
-
const packages = /* @__PURE__ */ new Set();
|
|
49493
|
-
for (const t of rule.targets) {
|
|
49494
|
-
if (t.packageName) packages.add(t.packageName);
|
|
49495
|
-
}
|
|
49496
|
-
if (packages.size >= 2) {
|
|
49497
|
-
return { scope: "global" };
|
|
49498
|
-
}
|
|
49499
|
-
if (packages.size === 1) {
|
|
49500
|
-
const pkg = [...packages][0];
|
|
49501
|
-
if (rule.scope === "global") {
|
|
49502
|
-
return { scope: "package", packageName: pkg };
|
|
49503
|
-
}
|
|
49504
|
-
}
|
|
49505
|
-
return { scope: rule.scope, packageName: rule.packageName };
|
|
49506
|
-
}
|
|
49507
|
-
/**
|
|
49508
|
-
* Wrap around createRule/updateRule to apply auto-promote/demote.
|
|
49509
|
-
* Checks if the resolved scope differs from what the caller requested
|
|
49510
|
-
* and adjusts accordingly — including moving the rule between files.
|
|
49511
|
-
*/
|
|
49512
|
-
async applyAutoScope(rule, _oldScope, _oldPkg) {
|
|
49513
|
-
const resolved = this.resolveScope(rule);
|
|
49514
|
-
if (resolved.scope !== rule.scope) {
|
|
49515
|
-
logger.info(`Auto-${resolved.scope === "global" ? "promote" : "demote"} rule ${rule.uuid}: ${rule.scope} \u2192 ${resolved.scope}`);
|
|
49516
|
-
}
|
|
49517
|
-
rule.scope = resolved.scope;
|
|
49518
|
-
if (resolved.packageName !== void 0) {
|
|
49519
|
-
rule.packageName = resolved.packageName;
|
|
49520
|
-
}
|
|
49521
|
-
return rule;
|
|
49522
|
-
}
|
|
49523
|
-
};
|
|
49524
|
-
ruleService = new RuleService();
|
|
49525
|
-
}
|
|
49526
|
-
});
|
|
49527
|
-
|
|
49528
49156
|
// backend/node_modules/zod/v4/core/core.js
|
|
49529
49157
|
// @__NO_SIDE_EFFECTS__
|
|
49530
49158
|
function $constructor(name21, initializer3, params) {
|
|
@@ -50508,7 +50136,7 @@ var init_errors = __esm({
|
|
|
50508
50136
|
});
|
|
50509
50137
|
|
|
50510
50138
|
// backend/node_modules/zod/v4/core/parse.js
|
|
50511
|
-
var _parse,
|
|
50139
|
+
var _parse, parse3, _parseAsync, parseAsync, _safeParse, safeParse, _safeParseAsync, safeParseAsync, _encode, encode, _decode, decode, _encodeAsync, encodeAsync, _decodeAsync, decodeAsync, _safeEncode, safeEncode, _safeDecode, safeDecode, _safeEncodeAsync, safeEncodeAsync, _safeDecodeAsync, safeDecodeAsync;
|
|
50512
50140
|
var init_parse = __esm({
|
|
50513
50141
|
"backend/node_modules/zod/v4/core/parse.js"() {
|
|
50514
50142
|
init_core();
|
|
@@ -50527,7 +50155,7 @@ var init_parse = __esm({
|
|
|
50527
50155
|
}
|
|
50528
50156
|
return result.value;
|
|
50529
50157
|
}, "_parse");
|
|
50530
|
-
|
|
50158
|
+
parse3 = /* @__PURE__ */ _parse($ZodRealError);
|
|
50531
50159
|
_parseAsync = /* @__PURE__ */ __name((_Err) => async (schema, value, _ctx, params) => {
|
|
50532
50160
|
const ctx = _ctx ? Object.assign(_ctx, { async: true }) : { async: true };
|
|
50533
50161
|
let result = schema._zod.run({ value, issues: [] }, ctx);
|
|
@@ -53285,10 +52913,10 @@ var init_schemas = __esm({
|
|
|
53285
52913
|
throw new Error("implement() must be called with a function");
|
|
53286
52914
|
}
|
|
53287
52915
|
return function(...args) {
|
|
53288
|
-
const parsedArgs = inst._def.input ?
|
|
52916
|
+
const parsedArgs = inst._def.input ? parse3(inst._def.input, args) : args;
|
|
53289
52917
|
const result = Reflect.apply(func, this, parsedArgs);
|
|
53290
52918
|
if (inst._def.output) {
|
|
53291
|
-
return
|
|
52919
|
+
return parse3(inst._def.output, result);
|
|
53292
52920
|
}
|
|
53293
52921
|
return result;
|
|
53294
52922
|
};
|
|
@@ -61906,7 +61534,7 @@ __export(core_exports2, {
|
|
|
61906
61534
|
isValidJWT: () => isValidJWT,
|
|
61907
61535
|
locales: () => locales_exports,
|
|
61908
61536
|
meta: () => meta,
|
|
61909
|
-
parse: () =>
|
|
61537
|
+
parse: () => parse3,
|
|
61910
61538
|
parseAsync: () => parseAsync,
|
|
61911
61539
|
prettifyError: () => prettifyError,
|
|
61912
61540
|
process: () => process2,
|
|
@@ -62085,12 +61713,12 @@ var init_errors2 = __esm({
|
|
|
62085
61713
|
});
|
|
62086
61714
|
|
|
62087
61715
|
// backend/node_modules/zod/v4/classic/parse.js
|
|
62088
|
-
var
|
|
61716
|
+
var parse4, parseAsync2, safeParse2, safeParseAsync2, encode2, decode2, encodeAsync2, decodeAsync2, safeEncode2, safeDecode2, safeEncodeAsync2, safeDecodeAsync2;
|
|
62089
61717
|
var init_parse2 = __esm({
|
|
62090
61718
|
"backend/node_modules/zod/v4/classic/parse.js"() {
|
|
62091
61719
|
init_core2();
|
|
62092
61720
|
init_errors2();
|
|
62093
|
-
|
|
61721
|
+
parse4 = /* @__PURE__ */ _parse(ZodRealError);
|
|
62094
61722
|
parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
|
|
62095
61723
|
safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
|
|
62096
61724
|
safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
|
|
@@ -62766,7 +62394,7 @@ var init_schemas2 = __esm({
|
|
|
62766
62394
|
reg.add(inst, meta3);
|
|
62767
62395
|
return inst;
|
|
62768
62396
|
});
|
|
62769
|
-
inst.parse = (data, params) =>
|
|
62397
|
+
inst.parse = (data, params) => parse4(inst, data, params, { callee: inst.parse });
|
|
62770
62398
|
inst.safeParse = (data, params) => safeParse2(inst, data, params);
|
|
62771
62399
|
inst.parseAsync = async (data, params) => parseAsync2(inst, data, params, { callee: inst.parseAsync });
|
|
62772
62400
|
inst.safeParseAsync = async (data, params) => safeParseAsync2(inst, data, params);
|
|
@@ -64193,7 +63821,7 @@ __export(external_exports, {
|
|
|
64193
63821
|
object: () => object,
|
|
64194
63822
|
optional: () => optional,
|
|
64195
63823
|
overwrite: () => _overwrite,
|
|
64196
|
-
parse: () =>
|
|
63824
|
+
parse: () => parse4,
|
|
64197
63825
|
parseAsync: () => parseAsync2,
|
|
64198
63826
|
partialRecord: () => partialRecord,
|
|
64199
63827
|
pipe: () => pipe,
|
|
@@ -64308,6 +63936,424 @@ var init_agentToolRegistry = __esm({
|
|
|
64308
63936
|
}
|
|
64309
63937
|
});
|
|
64310
63938
|
|
|
63939
|
+
// backend/src/models/Rule.ts
|
|
63940
|
+
function validateRule(rule) {
|
|
63941
|
+
const errors = [];
|
|
63942
|
+
if (!rule.name || typeof rule.name !== "string") {
|
|
63943
|
+
errors.push("Rule name is required");
|
|
63944
|
+
} else if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(rule.name)) {
|
|
63945
|
+
errors.push("Rule name must be kebab-case (lowercase letters, numbers, hyphens)");
|
|
63946
|
+
}
|
|
63947
|
+
if (!rule.description || typeof rule.description !== "string") {
|
|
63948
|
+
errors.push("Rule description is required");
|
|
63949
|
+
}
|
|
63950
|
+
if (!rule.severity || !["info", "warning", "error"].includes(rule.severity)) {
|
|
63951
|
+
errors.push("Rule severity must be one of: info, warning, error");
|
|
63952
|
+
}
|
|
63953
|
+
if (!rule.enforcement || !["save", "process", "advisory"].includes(rule.enforcement)) {
|
|
63954
|
+
errors.push("Rule enforcement must be one of: save, process, advisory");
|
|
63955
|
+
}
|
|
63956
|
+
if (!rule.scope || !["entity", "package", "case", "global"].includes(rule.scope)) {
|
|
63957
|
+
errors.push("Rule scope must be one of: entity, package, case, global");
|
|
63958
|
+
}
|
|
63959
|
+
if (!Array.isArray(rule.targets) || rule.targets.length === 0) {
|
|
63960
|
+
errors.push("Rule must have at least one target");
|
|
63961
|
+
}
|
|
63962
|
+
if (rule.scope === "entity" && !rule.entityUuid) {
|
|
63963
|
+
errors.push("Entity-scoped rules must specify entityUuid");
|
|
63964
|
+
}
|
|
63965
|
+
if (rule.scope === "package" && !rule.packageName) {
|
|
63966
|
+
errors.push("Package-scoped rules must specify packageName");
|
|
63967
|
+
}
|
|
63968
|
+
if (rule.scope === "case" && !rule.caseUuid) {
|
|
63969
|
+
errors.push("Case-scoped rules must specify caseUuid");
|
|
63970
|
+
}
|
|
63971
|
+
if (rule.enforcement === "process") {
|
|
63972
|
+
const stageField = (rule.metadata || []).find((m) => m.name === "process-stage-field");
|
|
63973
|
+
if (!stageField || !stageField.value) {
|
|
63974
|
+
errors.push("Process-enforcement rules must reference a metadata field via process-stage-field");
|
|
63975
|
+
}
|
|
63976
|
+
}
|
|
63977
|
+
return errors;
|
|
63978
|
+
}
|
|
63979
|
+
var init_Rule = __esm({
|
|
63980
|
+
"backend/src/models/Rule.ts"() {
|
|
63981
|
+
"use strict";
|
|
63982
|
+
__name(validateRule, "validateRule");
|
|
63983
|
+
}
|
|
63984
|
+
});
|
|
63985
|
+
|
|
63986
|
+
// backend/src/services/ruleService.ts
|
|
63987
|
+
var ruleService_exports = {};
|
|
63988
|
+
__export(ruleService_exports, {
|
|
63989
|
+
ruleService: () => ruleService
|
|
63990
|
+
});
|
|
63991
|
+
var RuleService, ruleService;
|
|
63992
|
+
var init_ruleService = __esm({
|
|
63993
|
+
"backend/src/services/ruleService.ts"() {
|
|
63994
|
+
"use strict";
|
|
63995
|
+
init_Rule();
|
|
63996
|
+
init_fileOperations();
|
|
63997
|
+
init_uuid();
|
|
63998
|
+
init_logger();
|
|
63999
|
+
init_ProjectionRegistry();
|
|
64000
|
+
init_types();
|
|
64001
|
+
RuleService = class {
|
|
64002
|
+
static {
|
|
64003
|
+
__name(this, "RuleService");
|
|
64004
|
+
}
|
|
64005
|
+
/** List all rules from all storage scopes, optionally filtered. */
|
|
64006
|
+
async listRules(filters = {}) {
|
|
64007
|
+
const all = [];
|
|
64008
|
+
if (!filters.scope || filters.scope === "entity") {
|
|
64009
|
+
const files = await listAllEntityRuleFiles();
|
|
64010
|
+
for (const { service, entityUuid } of files) {
|
|
64011
|
+
const rules = await readEntityRules(service, entityUuid);
|
|
64012
|
+
all.push(...rules);
|
|
64013
|
+
}
|
|
64014
|
+
}
|
|
64015
|
+
if (!filters.scope || filters.scope === "package") {
|
|
64016
|
+
const packages = filters.packageName ? [filters.packageName] : await listPackagesWithRules();
|
|
64017
|
+
for (const pkg of packages) {
|
|
64018
|
+
const rules = await readPackageRules(pkg);
|
|
64019
|
+
all.push(...rules);
|
|
64020
|
+
}
|
|
64021
|
+
}
|
|
64022
|
+
if (!filters.scope || filters.scope === "global") {
|
|
64023
|
+
const globalRules = await readGlobalRules();
|
|
64024
|
+
all.push(...globalRules);
|
|
64025
|
+
}
|
|
64026
|
+
if (!filters.scope || filters.scope === "case") {
|
|
64027
|
+
if (filters.caseUuid) {
|
|
64028
|
+
const rules = await readCaseRules(filters.caseUuid);
|
|
64029
|
+
all.push(...rules);
|
|
64030
|
+
} else {
|
|
64031
|
+
const cases = await listCases();
|
|
64032
|
+
for (const c of cases) {
|
|
64033
|
+
const rules = c.rules || [];
|
|
64034
|
+
all.push(...rules);
|
|
64035
|
+
}
|
|
64036
|
+
}
|
|
64037
|
+
}
|
|
64038
|
+
for (const rule of all) {
|
|
64039
|
+
if (!rule.enforcement) rule.enforcement = "advisory";
|
|
64040
|
+
}
|
|
64041
|
+
return all.filter((rule) => {
|
|
64042
|
+
if (filters.severity && rule.severity !== filters.severity) return false;
|
|
64043
|
+
if (filters.enforcement && rule.enforcement !== filters.enforcement) return false;
|
|
64044
|
+
if (filters.targetUuid) {
|
|
64045
|
+
const hit = rule.targets.some(
|
|
64046
|
+
(t) => t.uuid === filters.targetUuid || t.entityUuid === filters.targetUuid
|
|
64047
|
+
);
|
|
64048
|
+
if (!hit) return false;
|
|
64049
|
+
}
|
|
64050
|
+
return true;
|
|
64051
|
+
});
|
|
64052
|
+
}
|
|
64053
|
+
/** Get a single rule by uuid (scans all scopes). */
|
|
64054
|
+
async getRule(uuid3) {
|
|
64055
|
+
const all = await this.listRules();
|
|
64056
|
+
return all.find((r) => r.uuid === uuid3) || null;
|
|
64057
|
+
}
|
|
64058
|
+
/** List rules whose targets include this entity (or any of its attributes). */
|
|
64059
|
+
async listRulesForEntity(entityUuid) {
|
|
64060
|
+
const all = await this.listRules();
|
|
64061
|
+
return all.filter(
|
|
64062
|
+
(rule) => rule.targets.some(
|
|
64063
|
+
(t) => t.uuid === entityUuid || t.entityUuid === entityUuid
|
|
64064
|
+
)
|
|
64065
|
+
);
|
|
64066
|
+
}
|
|
64067
|
+
/** Create a rule. Storage location is determined by `scope`. */
|
|
64068
|
+
async createRule(input) {
|
|
64069
|
+
if (!input.enforcement) input.enforcement = "advisory";
|
|
64070
|
+
const errors = validateRule(input);
|
|
64071
|
+
if (errors.length > 0) {
|
|
64072
|
+
return { success: false, errors };
|
|
64073
|
+
}
|
|
64074
|
+
let rule = {
|
|
64075
|
+
uuid: generateUUID(),
|
|
64076
|
+
name: input.name,
|
|
64077
|
+
description: input.description,
|
|
64078
|
+
severity: input.severity,
|
|
64079
|
+
enforcement: input.enforcement,
|
|
64080
|
+
scope: input.scope,
|
|
64081
|
+
targets: input.targets,
|
|
64082
|
+
packageName: input.packageName,
|
|
64083
|
+
entityUuid: input.entityUuid,
|
|
64084
|
+
caseUuid: input.caseUuid,
|
|
64085
|
+
expression: input.expression,
|
|
64086
|
+
tags: input.tags,
|
|
64087
|
+
metadata: input.metadata,
|
|
64088
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
64089
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
64090
|
+
};
|
|
64091
|
+
rule = await this.applyAutoScope(rule);
|
|
64092
|
+
const saved = await this.saveRuleToScope(rule);
|
|
64093
|
+
if (!saved) return { success: false, errors: ["Failed to write rule to storage"] };
|
|
64094
|
+
return { success: true, rule };
|
|
64095
|
+
}
|
|
64096
|
+
/** Update an existing rule by uuid. Re-routes to new scope if scope changed. */
|
|
64097
|
+
async updateRule(uuid3, input) {
|
|
64098
|
+
const existing = await this.getRule(uuid3);
|
|
64099
|
+
if (!existing) return { success: false, errors: [`Rule ${uuid3} not found`] };
|
|
64100
|
+
let merged = {
|
|
64101
|
+
...existing,
|
|
64102
|
+
...input,
|
|
64103
|
+
uuid: existing.uuid,
|
|
64104
|
+
createdAt: existing.createdAt,
|
|
64105
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
64106
|
+
};
|
|
64107
|
+
const errors = validateRule(merged);
|
|
64108
|
+
if (errors.length > 0) return { success: false, errors };
|
|
64109
|
+
merged = await this.applyAutoScope(merged, existing.scope, existing.packageName);
|
|
64110
|
+
const scopeMoved = existing.scope !== merged.scope || existing.packageName !== merged.packageName || existing.entityUuid !== merged.entityUuid || existing.caseUuid !== merged.caseUuid;
|
|
64111
|
+
if (scopeMoved) {
|
|
64112
|
+
await this.removeRuleFromScope(existing);
|
|
64113
|
+
}
|
|
64114
|
+
const saved = await this.saveRuleToScope(merged);
|
|
64115
|
+
if (!saved) return { success: false, errors: ["Failed to write updated rule to storage"] };
|
|
64116
|
+
return { success: true, rule: merged };
|
|
64117
|
+
}
|
|
64118
|
+
/** Delete a rule by uuid. */
|
|
64119
|
+
async deleteRule(uuid3) {
|
|
64120
|
+
const existing = await this.getRule(uuid3);
|
|
64121
|
+
if (!existing) return { success: false, errors: [`Rule ${uuid3} not found`] };
|
|
64122
|
+
const removed = await this.removeRuleFromScope(existing);
|
|
64123
|
+
if (!removed) return { success: false, errors: ["Failed to remove rule from storage"] };
|
|
64124
|
+
return { success: true };
|
|
64125
|
+
}
|
|
64126
|
+
// ─── Private helpers: route to the right storage location ────────────────
|
|
64127
|
+
async saveRuleToScope(rule) {
|
|
64128
|
+
const projection = getProjection(wsId("dictionaries"));
|
|
64129
|
+
switch (rule.scope) {
|
|
64130
|
+
case "entity": {
|
|
64131
|
+
if (!rule.entityUuid) return false;
|
|
64132
|
+
const files = await listAllEntityRuleFiles();
|
|
64133
|
+
let service = files.find((f) => f.entityUuid === rule.entityUuid)?.service;
|
|
64134
|
+
if (!service) service = rule.packageName;
|
|
64135
|
+
if (!service) {
|
|
64136
|
+
logger.error(`Cannot determine service for entity ${rule.entityUuid}`);
|
|
64137
|
+
return false;
|
|
64138
|
+
}
|
|
64139
|
+
const entity = await this.findEntityByUuid(service, rule.entityUuid);
|
|
64140
|
+
if (!entity) {
|
|
64141
|
+
logger.error(`Entity ${rule.entityUuid} not found in service ${service}`);
|
|
64142
|
+
return false;
|
|
64143
|
+
}
|
|
64144
|
+
const existing = entity.rules || [];
|
|
64145
|
+
const updatedRules = [...existing.filter((r) => r.uuid !== rule.uuid), rule];
|
|
64146
|
+
entity.rules = updatedRules.length > 0 ? updatedRules : void 0;
|
|
64147
|
+
const logicalPath = `packages/${service}/entities/${entity.name}`;
|
|
64148
|
+
try {
|
|
64149
|
+
await projection.writeEntity(logicalPath, entity);
|
|
64150
|
+
return true;
|
|
64151
|
+
} catch (e) {
|
|
64152
|
+
logger.error(`Failed to write entity-scope rule via projection: ${e.message}`);
|
|
64153
|
+
return false;
|
|
64154
|
+
}
|
|
64155
|
+
}
|
|
64156
|
+
case "package": {
|
|
64157
|
+
if (!rule.packageName) return false;
|
|
64158
|
+
const existing = await readPackageRules(rule.packageName);
|
|
64159
|
+
const updated = [...existing.filter((r) => r.uuid !== rule.uuid), rule];
|
|
64160
|
+
const packageLogicalPath = `packages/${rule.packageName}`;
|
|
64161
|
+
try {
|
|
64162
|
+
await projection.writePackageRules(packageLogicalPath, updated);
|
|
64163
|
+
return true;
|
|
64164
|
+
} catch (e) {
|
|
64165
|
+
logger.error(`Failed to write package-scope rules via projection: ${e.message}`);
|
|
64166
|
+
return false;
|
|
64167
|
+
}
|
|
64168
|
+
}
|
|
64169
|
+
case "case": {
|
|
64170
|
+
if (!rule.caseUuid) return false;
|
|
64171
|
+
const c = await readCaseFile(rule.caseUuid);
|
|
64172
|
+
if (!c) return false;
|
|
64173
|
+
const existing = c.rules || [];
|
|
64174
|
+
c.rules = [...existing.filter((r) => r.uuid !== rule.uuid), rule];
|
|
64175
|
+
c.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
64176
|
+
const targetPackage = await this.resolveCaseHomePackage(c);
|
|
64177
|
+
if (!targetPackage) return false;
|
|
64178
|
+
const caseLogicalPath = `packages/${targetPackage}/cases/${c.name}`;
|
|
64179
|
+
try {
|
|
64180
|
+
await projection.writeCase(caseLogicalPath, c);
|
|
64181
|
+
return true;
|
|
64182
|
+
} catch (e) {
|
|
64183
|
+
logger.error(`Failed to write case-scope rule via projection: ${e.message}`);
|
|
64184
|
+
return false;
|
|
64185
|
+
}
|
|
64186
|
+
}
|
|
64187
|
+
case "global": {
|
|
64188
|
+
const existing = await readGlobalRules();
|
|
64189
|
+
const updated = [...existing.filter((r) => r.uuid !== rule.uuid), rule];
|
|
64190
|
+
try {
|
|
64191
|
+
await projection.writeGlobalRules(updated);
|
|
64192
|
+
return true;
|
|
64193
|
+
} catch (e) {
|
|
64194
|
+
logger.error(`Failed to write global rules via projection: ${e.message}`);
|
|
64195
|
+
return false;
|
|
64196
|
+
}
|
|
64197
|
+
}
|
|
64198
|
+
default:
|
|
64199
|
+
return false;
|
|
64200
|
+
}
|
|
64201
|
+
}
|
|
64202
|
+
async removeRuleFromScope(rule) {
|
|
64203
|
+
const projection = getProjection(wsId("dictionaries"));
|
|
64204
|
+
switch (rule.scope) {
|
|
64205
|
+
case "entity": {
|
|
64206
|
+
if (!rule.entityUuid) return false;
|
|
64207
|
+
const files = await listAllEntityRuleFiles();
|
|
64208
|
+
const service = files.find((f) => f.entityUuid === rule.entityUuid)?.service ?? rule.packageName;
|
|
64209
|
+
if (!service) return false;
|
|
64210
|
+
const entity = await this.findEntityByUuid(service, rule.entityUuid);
|
|
64211
|
+
if (!entity) return false;
|
|
64212
|
+
const existing = entity.rules || [];
|
|
64213
|
+
const updatedRules = existing.filter((r) => r.uuid !== rule.uuid);
|
|
64214
|
+
entity.rules = updatedRules.length > 0 ? updatedRules : void 0;
|
|
64215
|
+
const logicalPath = `packages/${service}/entities/${entity.name}`;
|
|
64216
|
+
try {
|
|
64217
|
+
await projection.writeEntity(logicalPath, entity);
|
|
64218
|
+
return true;
|
|
64219
|
+
} catch (e) {
|
|
64220
|
+
logger.error(`Failed to remove entity-scope rule via projection: ${e.message}`);
|
|
64221
|
+
return false;
|
|
64222
|
+
}
|
|
64223
|
+
}
|
|
64224
|
+
case "package": {
|
|
64225
|
+
if (!rule.packageName) return false;
|
|
64226
|
+
const existing = await readPackageRules(rule.packageName);
|
|
64227
|
+
const updated = existing.filter((r) => r.uuid !== rule.uuid);
|
|
64228
|
+
const packageLogicalPath = `packages/${rule.packageName}`;
|
|
64229
|
+
try {
|
|
64230
|
+
await projection.writePackageRules(packageLogicalPath, updated);
|
|
64231
|
+
return true;
|
|
64232
|
+
} catch (e) {
|
|
64233
|
+
logger.error(`Failed to remove package-scope rule via projection: ${e.message}`);
|
|
64234
|
+
return false;
|
|
64235
|
+
}
|
|
64236
|
+
}
|
|
64237
|
+
case "case": {
|
|
64238
|
+
if (!rule.caseUuid) return false;
|
|
64239
|
+
const c = await readCaseFile(rule.caseUuid);
|
|
64240
|
+
if (!c) return false;
|
|
64241
|
+
const existing = c.rules || [];
|
|
64242
|
+
const updated = existing.filter((r) => r.uuid !== rule.uuid);
|
|
64243
|
+
c.rules = updated.length > 0 ? updated : void 0;
|
|
64244
|
+
c.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
64245
|
+
const targetPackage = await this.resolveCaseHomePackage(c);
|
|
64246
|
+
if (!targetPackage) return false;
|
|
64247
|
+
const caseLogicalPath = `packages/${targetPackage}/cases/${c.name}`;
|
|
64248
|
+
try {
|
|
64249
|
+
await projection.writeCase(caseLogicalPath, c);
|
|
64250
|
+
return true;
|
|
64251
|
+
} catch (e) {
|
|
64252
|
+
logger.error(`Failed to remove case-scope rule via projection: ${e.message}`);
|
|
64253
|
+
return false;
|
|
64254
|
+
}
|
|
64255
|
+
}
|
|
64256
|
+
case "global": {
|
|
64257
|
+
const existing = await readGlobalRules();
|
|
64258
|
+
const updated = existing.filter((r) => r.uuid !== rule.uuid);
|
|
64259
|
+
try {
|
|
64260
|
+
await projection.writeGlobalRules(updated);
|
|
64261
|
+
return true;
|
|
64262
|
+
} catch (e) {
|
|
64263
|
+
logger.error(`Failed to remove global rule via projection: ${e.message}`);
|
|
64264
|
+
return false;
|
|
64265
|
+
}
|
|
64266
|
+
}
|
|
64267
|
+
default:
|
|
64268
|
+
return false;
|
|
64269
|
+
}
|
|
64270
|
+
}
|
|
64271
|
+
/**
|
|
64272
|
+
* Load an entity from a package by uuid. Returns null if not found.
|
|
64273
|
+
* Used by entity-scope rule writes to round-trip the parent entity
|
|
64274
|
+
* through `projection.writeEntity`.
|
|
64275
|
+
*/
|
|
64276
|
+
async findEntityByUuid(service, entityUuid) {
|
|
64277
|
+
try {
|
|
64278
|
+
const pkg = await loadPackage(service);
|
|
64279
|
+
return pkg.entities.find((e) => e.uuid === entityUuid) ?? null;
|
|
64280
|
+
} catch (error48) {
|
|
64281
|
+
logger.error(`Error loading package ${service} for entity lookup: ${error48}`);
|
|
64282
|
+
return null;
|
|
64283
|
+
}
|
|
64284
|
+
}
|
|
64285
|
+
/**
|
|
64286
|
+
* Resolve the home package for a case so we can construct a
|
|
64287
|
+
* `packages/<pkg>/cases/<name>` logical path. Mirrors the heuristic in
|
|
64288
|
+
* caseService.ts / fileOperations.ts: existing-owner lookup by uuid first,
|
|
64289
|
+
* then first root entity's package, then first package on disk.
|
|
64290
|
+
*/
|
|
64291
|
+
async resolveCaseHomePackage(c) {
|
|
64292
|
+
const { listPackages: listPackages3 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
|
|
64293
|
+
const packages = await listPackages3();
|
|
64294
|
+
for (const pkg of packages) {
|
|
64295
|
+
try {
|
|
64296
|
+
const model = await loadPackage(pkg);
|
|
64297
|
+
if (model.ownership.caseByUuid.has(c.uuid)) return pkg;
|
|
64298
|
+
} catch {
|
|
64299
|
+
}
|
|
64300
|
+
}
|
|
64301
|
+
if (c.rootEntities && c.rootEntities.length > 0) {
|
|
64302
|
+
const rootUuid = c.rootEntities[0];
|
|
64303
|
+
for (const pkg of packages) {
|
|
64304
|
+
try {
|
|
64305
|
+
const model = await loadPackage(pkg);
|
|
64306
|
+
if (model.ownership.entityByUuid.has(rootUuid)) return pkg;
|
|
64307
|
+
} catch {
|
|
64308
|
+
}
|
|
64309
|
+
}
|
|
64310
|
+
}
|
|
64311
|
+
return packages[0] || null;
|
|
64312
|
+
}
|
|
64313
|
+
// ─── Auto-promote / auto-demote (#75) ────────────────────────────────
|
|
64314
|
+
/**
|
|
64315
|
+
* Determine the correct scope for a rule based on its targets.
|
|
64316
|
+
* Called before save. If targets span 2+ packages → global.
|
|
64317
|
+
* If all targets are in one package → that package's scope (keep
|
|
64318
|
+
* the caller's intent for entity vs package).
|
|
64319
|
+
*/
|
|
64320
|
+
resolveScope(rule) {
|
|
64321
|
+
const packages = /* @__PURE__ */ new Set();
|
|
64322
|
+
for (const t of rule.targets) {
|
|
64323
|
+
if (t.packageName) packages.add(t.packageName);
|
|
64324
|
+
}
|
|
64325
|
+
if (packages.size >= 2) {
|
|
64326
|
+
return { scope: "global" };
|
|
64327
|
+
}
|
|
64328
|
+
if (packages.size === 1) {
|
|
64329
|
+
const pkg = [...packages][0];
|
|
64330
|
+
if (rule.scope === "global") {
|
|
64331
|
+
return { scope: "package", packageName: pkg };
|
|
64332
|
+
}
|
|
64333
|
+
}
|
|
64334
|
+
return { scope: rule.scope, packageName: rule.packageName };
|
|
64335
|
+
}
|
|
64336
|
+
/**
|
|
64337
|
+
* Wrap around createRule/updateRule to apply auto-promote/demote.
|
|
64338
|
+
* Checks if the resolved scope differs from what the caller requested
|
|
64339
|
+
* and adjusts accordingly — including moving the rule between files.
|
|
64340
|
+
*/
|
|
64341
|
+
async applyAutoScope(rule, _oldScope, _oldPkg) {
|
|
64342
|
+
const resolved = this.resolveScope(rule);
|
|
64343
|
+
if (resolved.scope !== rule.scope) {
|
|
64344
|
+
logger.info(`Auto-${resolved.scope === "global" ? "promote" : "demote"} rule ${rule.uuid}: ${rule.scope} \u2192 ${resolved.scope}`);
|
|
64345
|
+
}
|
|
64346
|
+
rule.scope = resolved.scope;
|
|
64347
|
+
if (resolved.packageName !== void 0) {
|
|
64348
|
+
rule.packageName = resolved.packageName;
|
|
64349
|
+
}
|
|
64350
|
+
return rule;
|
|
64351
|
+
}
|
|
64352
|
+
};
|
|
64353
|
+
ruleService = new RuleService();
|
|
64354
|
+
}
|
|
64355
|
+
});
|
|
64356
|
+
|
|
64311
64357
|
// backend/src/services/versionService.ts
|
|
64312
64358
|
var versionService_exports = {};
|
|
64313
64359
|
__export(versionService_exports, {
|
|
@@ -116930,8 +116976,8 @@ function resolveToolCategory(toolName, trustByName) {
|
|
|
116930
116976
|
const clean = toolName.replace(/^functions\./, "").split(":")[0];
|
|
116931
116977
|
const builtin = TOOL_CATEGORY_MAP[clean];
|
|
116932
116978
|
if (builtin) return builtin;
|
|
116933
|
-
const
|
|
116934
|
-
if (
|
|
116979
|
+
const registered5 = getAgentTool(clean)?.category;
|
|
116980
|
+
if (registered5) return registered5;
|
|
116935
116981
|
if (clean.includes(".")) {
|
|
116936
116982
|
const trust = trustByName.get(clean);
|
|
116937
116983
|
return trust === "auto" ? "read" : "modify";
|
|
@@ -159537,6 +159583,24 @@ var setEntityHidden = /* @__PURE__ */ __name(async (req, res) => {
|
|
|
159537
159583
|
res.status(500).json({ message: "Error setting entity visibility", error: error48 });
|
|
159538
159584
|
}
|
|
159539
159585
|
}, "setEntityHidden");
|
|
159586
|
+
var moveEntity = /* @__PURE__ */ __name(async (req, res) => {
|
|
159587
|
+
try {
|
|
159588
|
+
const { service, entity } = req.params;
|
|
159589
|
+
const targetPackage = typeof req.body?.targetPackage === "string" ? req.body.targetPackage : "";
|
|
159590
|
+
if (!targetPackage) {
|
|
159591
|
+
return res.status(400).json({ message: "targetPackage is required" });
|
|
159592
|
+
}
|
|
159593
|
+
const result = await serviceService.moveEntity(service, entity, targetPackage);
|
|
159594
|
+
if (!result.success) {
|
|
159595
|
+
const notFound = result.errors.some((e) => e.includes("not found"));
|
|
159596
|
+
return res.status(notFound ? 404 : 400).json({ message: "Failed to move entity", errors: result.errors });
|
|
159597
|
+
}
|
|
159598
|
+
res.json({ message: "Entity moved", data: { service, entity, targetPackage } });
|
|
159599
|
+
} catch (error48) {
|
|
159600
|
+
logger.error(`Error moving entity: ${error48}`);
|
|
159601
|
+
res.status(500).json({ message: "Error moving entity", error: error48 });
|
|
159602
|
+
}
|
|
159603
|
+
}, "moveEntity");
|
|
159540
159604
|
var setEntityStyle = /* @__PURE__ */ __name(async (req, res) => {
|
|
159541
159605
|
try {
|
|
159542
159606
|
const { service, entity } = req.params;
|
|
@@ -159763,7 +159827,46 @@ var deleteRelationship = /* @__PURE__ */ __name(async (req, res) => {
|
|
|
159763
159827
|
}
|
|
159764
159828
|
}, "deleteRelationship");
|
|
159765
159829
|
|
|
159830
|
+
// backend/src/services/entityMove/agentTools.ts
|
|
159831
|
+
init_zod();
|
|
159832
|
+
init_agentToolRegistry();
|
|
159833
|
+
init_serviceService();
|
|
159834
|
+
var registered = false;
|
|
159835
|
+
function registerMoveEntityAgentTool() {
|
|
159836
|
+
if (registered) return;
|
|
159837
|
+
registered = true;
|
|
159838
|
+
registerAgentTool({
|
|
159839
|
+
name: "moveEntity",
|
|
159840
|
+
category: "modify",
|
|
159841
|
+
description: "Move an entity from one package to another. The entity keeps its UUID, so relationships (cross-package is first-class), cases and diagrams that reference it keep resolving \u2014 nothing is orphaned. Fails if the target package doesn't exist or already has an entity with the same name.",
|
|
159842
|
+
jsonSchema: {
|
|
159843
|
+
type: "object",
|
|
159844
|
+
required: ["sourcePackage", "entityName", "targetPackage"],
|
|
159845
|
+
properties: {
|
|
159846
|
+
sourcePackage: { type: "string", description: "Package the entity currently lives in" },
|
|
159847
|
+
entityName: { type: "string", description: "Name of the entity to move" },
|
|
159848
|
+
targetPackage: { type: "string", description: "Package to move the entity into" }
|
|
159849
|
+
}
|
|
159850
|
+
},
|
|
159851
|
+
inputSchema: external_exports.object({
|
|
159852
|
+
sourcePackage: external_exports.string(),
|
|
159853
|
+
entityName: external_exports.string(),
|
|
159854
|
+
targetPackage: external_exports.string()
|
|
159855
|
+
}),
|
|
159856
|
+
execute: /* @__PURE__ */ __name(async (args) => {
|
|
159857
|
+
const r = await serviceService.moveEntity(
|
|
159858
|
+
String(args.sourcePackage),
|
|
159859
|
+
String(args.entityName),
|
|
159860
|
+
String(args.targetPackage)
|
|
159861
|
+
);
|
|
159862
|
+
return r.success ? { success: true, entity: args.entityName, from: args.sourcePackage, to: args.targetPackage } : { success: false, errors: r.errors };
|
|
159863
|
+
}, "execute")
|
|
159864
|
+
});
|
|
159865
|
+
}
|
|
159866
|
+
__name(registerMoveEntityAgentTool, "registerMoveEntityAgentTool");
|
|
159867
|
+
|
|
159766
159868
|
// backend/src/routes/data-dictionary/entity.routes.ts
|
|
159869
|
+
registerMoveEntityAgentTool();
|
|
159767
159870
|
var router3 = (0, import_express4.Router)();
|
|
159768
159871
|
router3.get("/api/entities/:microservice/:entityName/attributes", getEntityAttributes);
|
|
159769
159872
|
router3.get("/api/entities/:microservice/:entityName/related", getRelatedEntities);
|
|
@@ -159777,6 +159880,7 @@ router3.put("/api/services/:service/entities/:entity", authorizeJwt(["admin" /*
|
|
|
159777
159880
|
router3.delete("/api/services/:service/entities/:entity", authorizeJwt(["admin" /* ADMIN */]), deleteEntity);
|
|
159778
159881
|
router3.put("/api/services/:service/entities/:entity/hidden", authorizeJwt(["admin" /* ADMIN */, "editor" /* EDITOR */]), setEntityHidden);
|
|
159779
159882
|
router3.put("/api/services/:service/entities/:entity/style", authorizeJwt(["admin" /* ADMIN */, "editor" /* EDITOR */]), setEntityStyle);
|
|
159883
|
+
router3.put("/api/services/:service/entities/:entity/move", authorizeJwt(["admin" /* ADMIN */, "editor" /* EDITOR */]), moveEntity);
|
|
159780
159884
|
router3.post("/api/services/:service/entities/:entity/submit", authorizeJwt(["admin" /* ADMIN */, "editor" /* EDITOR */]), submitEntity);
|
|
159781
159885
|
router3.post("/api/services/:service/entities/:entity/approve", authorizeJwt(["admin" /* ADMIN */]), approveEntity);
|
|
159782
159886
|
router3.post("/api/services/:service/entities/:entity/return", authorizeJwt(["admin" /* ADMIN */]), returnEntity);
|
|
@@ -160321,10 +160425,10 @@ init_zod();
|
|
|
160321
160425
|
init_agentToolRegistry();
|
|
160322
160426
|
init_dicoConfigService();
|
|
160323
160427
|
init_serviceService();
|
|
160324
|
-
var
|
|
160428
|
+
var registered2 = false;
|
|
160325
160429
|
function registerElementStyleAgentTools() {
|
|
160326
|
-
if (
|
|
160327
|
-
|
|
160430
|
+
if (registered2) return;
|
|
160431
|
+
registered2 = true;
|
|
160328
160432
|
registerAgentTool({
|
|
160329
160433
|
name: "defineElementStyle",
|
|
160330
160434
|
category: "modify",
|
|
@@ -165089,10 +165193,10 @@ init_zod();
|
|
|
165089
165193
|
init_agentToolRegistry();
|
|
165090
165194
|
init_searchIndexService();
|
|
165091
165195
|
var KINDS = ["entity", "attribute", "package", "relationship", "rule", "metadata", "case"];
|
|
165092
|
-
var
|
|
165196
|
+
var registered3 = false;
|
|
165093
165197
|
function registerSearchAgentTools() {
|
|
165094
|
-
if (
|
|
165095
|
-
|
|
165198
|
+
if (registered3) return;
|
|
165199
|
+
registered3 = true;
|
|
165096
165200
|
registerAgentTool({
|
|
165097
165201
|
name: "searchModel",
|
|
165098
165202
|
category: "read",
|
|
@@ -173535,10 +173639,10 @@ function getSynthesisBrief(dataDir, entityName) {
|
|
|
173535
173639
|
__name(getSynthesisBrief, "getSynthesisBrief");
|
|
173536
173640
|
|
|
173537
173641
|
// backend/src/services/reverseEngineer/agentTools.ts
|
|
173538
|
-
var
|
|
173642
|
+
var registered4 = false;
|
|
173539
173643
|
function registerReverseEngineerAgentTools() {
|
|
173540
|
-
if (
|
|
173541
|
-
|
|
173644
|
+
if (registered4) return;
|
|
173645
|
+
registered4 = true;
|
|
173542
173646
|
registerAgentTool({
|
|
173543
173647
|
name: "listSynthesisBriefs",
|
|
173544
173648
|
category: "read",
|