modscape 2.0.1 → 2.0.3
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/package.json +1 -1
- package/src/column.js +100 -0
- package/src/domain.js +149 -0
- package/src/extract.js +72 -0
- package/src/index.js +24 -2
- package/src/lineage.js +69 -0
- package/src/model-utils.js +53 -0
- package/src/relationship.js +93 -0
- package/src/table.js +118 -0
- package/src/templates/claude/modeling.md +14 -1
- package/src/templates/codex/modscape-modeling/SKILL.md +15 -2
- package/src/templates/gemini/modscape-modeling/SKILL.md +15 -2
- package/src/templates/rules.md +136 -1
- package/visualizer/package.json +1 -1
- package/visualizer-dist/assets/{index-DTXT8yZr.js → index-nIGQ5zIu.js} +51 -51
- package/visualizer-dist/index.html +1 -1
package/src/table.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { readYaml, writeYaml, findTableById, outputError, outputWarn, outputOk } from './model-utils.js';
|
|
3
|
+
|
|
4
|
+
export function tableCommand() {
|
|
5
|
+
const cmd = new Command('table').description('Manage tables in a YAML model');
|
|
6
|
+
|
|
7
|
+
// list
|
|
8
|
+
cmd
|
|
9
|
+
.command('list <file>')
|
|
10
|
+
.description('List all tables in the model')
|
|
11
|
+
.option('--json', 'output as JSON')
|
|
12
|
+
.action((file, opts) => {
|
|
13
|
+
const data = readYaml(file);
|
|
14
|
+
const tables = (data.tables || []).map(t => ({ id: t.id, name: t.name }));
|
|
15
|
+
if (opts.json) {
|
|
16
|
+
console.log(JSON.stringify(tables));
|
|
17
|
+
} else {
|
|
18
|
+
if (tables.length === 0) {
|
|
19
|
+
console.log(' (no tables)');
|
|
20
|
+
} else {
|
|
21
|
+
tables.forEach(t => console.log(` ${t.id} ${t.name || ''}`));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// get
|
|
27
|
+
cmd
|
|
28
|
+
.command('get <file>')
|
|
29
|
+
.description('Get a table definition by ID')
|
|
30
|
+
.requiredOption('--id <id>', 'table ID')
|
|
31
|
+
.option('--json', 'output as JSON')
|
|
32
|
+
.action((file, opts) => {
|
|
33
|
+
const data = readYaml(file);
|
|
34
|
+
const table = findTableById(data, opts.id);
|
|
35
|
+
if (!table) return outputError(opts.json, `Table "${opts.id}" not found`);
|
|
36
|
+
if (opts.json) {
|
|
37
|
+
console.log(JSON.stringify(table));
|
|
38
|
+
} else {
|
|
39
|
+
console.log(JSON.stringify(table, null, 2));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// add
|
|
44
|
+
cmd
|
|
45
|
+
.command('add <file>')
|
|
46
|
+
.description('Add a new table to the model')
|
|
47
|
+
.requiredOption('--id <id>', 'table ID (snake_case)')
|
|
48
|
+
.requiredOption('--name <name>', 'conceptual name')
|
|
49
|
+
.option('--type <type>', 'appearance type (fact|dimension|mart|hub|link|satellite|table)')
|
|
50
|
+
.option('--logical-name <name>', 'logical (business) name')
|
|
51
|
+
.option('--physical-name <name>', 'physical (database) table name')
|
|
52
|
+
.option('--description <text>', 'conceptual description')
|
|
53
|
+
.option('--json', 'output as JSON')
|
|
54
|
+
.action((file, opts) => {
|
|
55
|
+
const data = readYaml(file);
|
|
56
|
+
if (findTableById(data, opts.id)) {
|
|
57
|
+
return outputError(opts.json, `Table "${opts.id}" already exists`, 'Use `table update` instead');
|
|
58
|
+
}
|
|
59
|
+
const table = { id: opts.id, name: opts.name };
|
|
60
|
+
if (opts.logicalName) table.logical_name = opts.logicalName;
|
|
61
|
+
if (opts.physicalName) table.physical_name = opts.physicalName;
|
|
62
|
+
if (opts.type) table.appearance = { type: opts.type };
|
|
63
|
+
if (opts.description) table.conceptual = { description: opts.description };
|
|
64
|
+
if (!data.tables) data.tables = [];
|
|
65
|
+
data.tables.push(table);
|
|
66
|
+
writeYaml(file, data);
|
|
67
|
+
outputOk(opts.json, 'add', 'table', opts.id);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// update
|
|
71
|
+
cmd
|
|
72
|
+
.command('update <file>')
|
|
73
|
+
.description('Update fields of an existing table')
|
|
74
|
+
.requiredOption('--id <id>', 'table ID to update')
|
|
75
|
+
.option('--name <name>', 'conceptual name')
|
|
76
|
+
.option('--type <type>', 'appearance type')
|
|
77
|
+
.option('--logical-name <name>', 'logical (business) name')
|
|
78
|
+
.option('--physical-name <name>', 'physical (database) table name')
|
|
79
|
+
.option('--description <text>', 'conceptual description')
|
|
80
|
+
.option('--json', 'output as JSON')
|
|
81
|
+
.action((file, opts) => {
|
|
82
|
+
const data = readYaml(file);
|
|
83
|
+
const table = findTableById(data, opts.id);
|
|
84
|
+
if (!table) return outputError(opts.json, `Table "${opts.id}" not found`, 'Use `table add` instead');
|
|
85
|
+
if (opts.name) table.name = opts.name;
|
|
86
|
+
if (opts.logicalName) table.logical_name = opts.logicalName;
|
|
87
|
+
if (opts.physicalName) table.physical_name = opts.physicalName;
|
|
88
|
+
if (opts.type) {
|
|
89
|
+
table.appearance = table.appearance || {};
|
|
90
|
+
table.appearance.type = opts.type;
|
|
91
|
+
}
|
|
92
|
+
if (opts.description) {
|
|
93
|
+
table.conceptual = table.conceptual || {};
|
|
94
|
+
table.conceptual.description = opts.description;
|
|
95
|
+
}
|
|
96
|
+
writeYaml(file, data);
|
|
97
|
+
outputOk(opts.json, 'update', 'table', opts.id);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// remove
|
|
101
|
+
cmd
|
|
102
|
+
.command('remove <file>')
|
|
103
|
+
.description('Remove a table from the model')
|
|
104
|
+
.requiredOption('--id <id>', 'table ID to remove')
|
|
105
|
+
.option('--json', 'output as JSON')
|
|
106
|
+
.action((file, opts) => {
|
|
107
|
+
const data = readYaml(file);
|
|
108
|
+
const before = (data.tables || []).length;
|
|
109
|
+
data.tables = (data.tables || []).filter(t => t.id !== opts.id);
|
|
110
|
+
if (data.tables.length === before) {
|
|
111
|
+
return outputWarn(opts.json, `Table "${opts.id}" not found, nothing removed`);
|
|
112
|
+
}
|
|
113
|
+
writeYaml(file, data);
|
|
114
|
+
outputOk(opts.json, 'remove', 'table', opts.id);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return cmd;
|
|
118
|
+
}
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
Start an interactive data modeling session.
|
|
2
2
|
|
|
3
3
|
## Instructions
|
|
4
|
-
1. FIRST, read `.modscape/rules.md` to understand the project strategy, naming conventions, and YAML schema.
|
|
4
|
+
1. FIRST, read `.modscape/rules.md` to understand the project strategy, naming conventions, and YAML schema. If `.modscape/rules.custom.md` exists, read it too — custom rules take priority over the base rules.
|
|
5
5
|
2. SECOND, analyze the existing `model.yaml` if it exists.
|
|
6
6
|
3. Listen to the user's requirements and propose/apply changes to `model.yaml` strictly following the rules.
|
|
7
7
|
|
|
8
|
+
## Mutation CLI — Use Before Editing YAML Directly
|
|
9
|
+
|
|
10
|
+
For targeted changes to tables, columns, relationships, lineage, or domains, **PREFER the mutation CLI commands** over editing YAML directly. CLI commands validate input and write atomically.
|
|
11
|
+
|
|
12
|
+
Recommended flow:
|
|
13
|
+
1. Check existence: `modscape table get model.yaml --id <id> --json`
|
|
14
|
+
2. Add or update: `modscape table add` / `modscape table update`
|
|
15
|
+
3. After adding tables: `modscape layout model.yaml` to assign coordinates
|
|
16
|
+
|
|
17
|
+
See Section 13 of `.modscape/rules.md` for the full command reference.
|
|
18
|
+
|
|
19
|
+
Only edit YAML directly for complex nested fields not covered by CLI flags (e.g., `implementation`, `sampleData`, full `columns` definition).
|
|
20
|
+
|
|
8
21
|
## Appearance & Layout
|
|
9
22
|
- **Appearance**: For new tables, include the `appearance: { type: "..." }` block.
|
|
10
23
|
- **Layout**: When creating new entities, always assign initial `x` and `y` coordinates in the `layout` section. Position them logically near their related entities to avoid stacking.
|
|
@@ -9,15 +9,28 @@ You are a professional Data Modeler. Your primary directive is to manage `model.
|
|
|
9
9
|
|
|
10
10
|
## COMMAND: /modscape:modeling
|
|
11
11
|
When the user issues this command:
|
|
12
|
-
1. READ `.modscape/rules.md` to understand project strategy and conventions.
|
|
12
|
+
1. READ `.modscape/rules.md` to understand project strategy and conventions. If `.modscape/rules.custom.md` exists, read it too — custom rules take priority over the base rules.
|
|
13
13
|
2. ANALYZE `model.yaml` (if present).
|
|
14
14
|
3. INTERACT with the user to gather requirements and update the model strictly following the rules.
|
|
15
15
|
|
|
16
|
+
## Mutation CLI — Use Before Editing YAML Directly
|
|
17
|
+
|
|
18
|
+
For targeted changes to tables, columns, relationships, lineage, or domains, **PREFER the mutation CLI commands** over editing YAML directly. CLI commands validate input and write atomically.
|
|
19
|
+
|
|
20
|
+
Recommended flow:
|
|
21
|
+
1. Check existence: `modscape table get model.yaml --id <id> --json`
|
|
22
|
+
2. Add or update: `modscape table add` / `modscape table update`
|
|
23
|
+
3. After adding tables: `modscape layout model.yaml` to assign coordinates
|
|
24
|
+
|
|
25
|
+
See Section 13 of `.modscape/rules.md` for the full command reference.
|
|
26
|
+
|
|
27
|
+
Only edit YAML directly for complex nested fields not covered by CLI flags (e.g., `implementation`, `sampleData`, full `columns` definition).
|
|
28
|
+
|
|
16
29
|
## Appearance & Layout
|
|
17
30
|
- **Appearance**: When creating new tables, include the `appearance` block with an appropriate `type`.
|
|
18
31
|
- **Layout**: For any new entity, assign logical `x` and `y` coordinates in the `layout` section to prevent overlapping and ensure a clean initial visualization.
|
|
19
32
|
|
|
20
|
-
ALWAYS follow the rules defined in `.modscape/rules.md` for any modeling tasks.
|
|
33
|
+
ALWAYS follow the rules defined in `.modscape/rules.md` (and `.modscape/rules.custom.md` if present) for any modeling tasks.
|
|
21
34
|
|
|
22
35
|
## COMMAND: /modscape:codegen
|
|
23
36
|
When the user issues this command:
|
|
@@ -7,10 +7,23 @@ description: Create the data model defined in `model.yaml` according to project
|
|
|
7
7
|
|
|
8
8
|
You are a professional Data Modeler. Your primary directive is to manage `model.yaml`.
|
|
9
9
|
|
|
10
|
-
BEFORE making any suggestions or changes, you MUST read and strictly follow the rules defined in `.modscape/rules.md`.
|
|
10
|
+
BEFORE making any suggestions or changes, you MUST read and strictly follow the rules defined in `.modscape/rules.md`. If `.modscape/rules.custom.md` exists, read it too — custom rules take priority over the base rules.
|
|
11
11
|
|
|
12
12
|
If a requested change violates these rules, warn the user.
|
|
13
13
|
|
|
14
|
+
## Mutation CLI — Use Before Editing YAML Directly
|
|
15
|
+
|
|
16
|
+
For targeted changes to tables, columns, relationships, lineage, or domains, **PREFER the mutation CLI commands** over editing YAML directly. CLI commands validate input and write atomically.
|
|
17
|
+
|
|
18
|
+
Recommended flow:
|
|
19
|
+
1. Check existence: `modscape table get model.yaml --id <id> --json`
|
|
20
|
+
2. Add or update: `modscape table add` / `modscape table update`
|
|
21
|
+
3. After adding tables: `modscape layout model.yaml` to assign coordinates
|
|
22
|
+
|
|
23
|
+
See Section 13 of `.modscape/rules.md` for the full command reference.
|
|
24
|
+
|
|
25
|
+
Only edit YAML directly for complex nested fields not covered by CLI flags (e.g., `implementation`, `sampleData`, full `columns` definition).
|
|
26
|
+
|
|
14
27
|
## 📁 Multi-file Awareness
|
|
15
28
|
`modscape dev` supports pointing to a directory (e.g., `modscape dev samples/`).
|
|
16
29
|
- **Switching Models**: Identify which YAML file you are editing from the directory.
|
|
@@ -24,4 +37,4 @@ If a requested change violates these rules, warn the user.
|
|
|
24
37
|
## Interactive Modeling
|
|
25
38
|
When the user wants to perform modeling tasks, ensure you are utilizing the strategy and conventions defined in the project rules.
|
|
26
39
|
|
|
27
|
-
ALWAYS follow the rules defined in `.modscape/rules.md` for any modeling tasks.
|
|
40
|
+
ALWAYS follow the rules defined in `.modscape/rules.md` (and `.modscape/rules.custom.md` if present) for any modeling tasks.
|
package/src/templates/rules.md
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
> **Purpose**: This file teaches AI agents how to write valid `model.yaml` files for Modscape.
|
|
4
4
|
> Read this file completely before generating or editing any YAML.
|
|
5
5
|
|
|
6
|
+
> **Extension**: If `.modscape/rules.custom.md` exists in this project, read it **in addition** to this file.
|
|
7
|
+
> Rules in `rules.custom.md` take **priority** over this file when they conflict.
|
|
8
|
+
|
|
6
9
|
---
|
|
7
10
|
|
|
8
11
|
## QUICK REFERENCE (read this first)
|
|
@@ -589,7 +592,139 @@ modscape merge ./sales ./marketing -o combined.yaml
|
|
|
589
592
|
|
|
590
593
|
---
|
|
591
594
|
|
|
592
|
-
## 13.
|
|
595
|
+
## 13. Model Mutation CLI
|
|
596
|
+
|
|
597
|
+
Use the built-in mutation commands to **add, update, or remove individual entities** in a YAML model. These commands validate input and write atomically — safer than editing YAML directly.
|
|
598
|
+
|
|
599
|
+
**MUST** use these commands when making targeted changes. Only edit YAML directly for complex nested fields not covered by CLI flags (e.g., `implementation`, `sampleData`, `columns` full definition).
|
|
600
|
+
|
|
601
|
+
### 13-1. Available Operations
|
|
602
|
+
|
|
603
|
+
| Resource | Operations |
|
|
604
|
+
|----------|-----------|
|
|
605
|
+
| `table` | `list` `get` `add` `update` `remove` |
|
|
606
|
+
| `column` | `add` `update` `remove` |
|
|
607
|
+
| `relationship` | `list` `add` `remove` |
|
|
608
|
+
| `lineage` | `list` `add` `remove` |
|
|
609
|
+
| `domain` | `list` `get` `add` `update` `remove` |
|
|
610
|
+
| `domain member` | `add` `remove` |
|
|
611
|
+
|
|
612
|
+
### 13-2. Recommended AI Agent Flow
|
|
613
|
+
|
|
614
|
+
Before `add` or `update`, check existence with `get` or `list`:
|
|
615
|
+
|
|
616
|
+
```bash
|
|
617
|
+
# 1. Check if table exists
|
|
618
|
+
modscape table get model.yaml --id fct_orders --json
|
|
619
|
+
# → found: use update / not found: use add
|
|
620
|
+
|
|
621
|
+
# 2a. Add new table
|
|
622
|
+
modscape table add model.yaml --id fct_orders --name "Orders" --type fact
|
|
623
|
+
|
|
624
|
+
# 2b. Update existing table
|
|
625
|
+
modscape table update model.yaml --id fct_orders --physical-name fct_sales_orders
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### 13-3. CLI Flag Reference
|
|
629
|
+
|
|
630
|
+
**table add / update**
|
|
631
|
+
```bash
|
|
632
|
+
modscape table add model.yaml \
|
|
633
|
+
--id <id> --name <name> \
|
|
634
|
+
[--type fact|dimension|mart|hub|link|satellite|table] \
|
|
635
|
+
[--logical-name <name>] [--physical-name <name>] \
|
|
636
|
+
[--description <text>] [--json]
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
**column add / update**
|
|
640
|
+
```bash
|
|
641
|
+
modscape column add model.yaml \
|
|
642
|
+
--table <tableId> --id <id> --name <name> \
|
|
643
|
+
[--type Int|String|Decimal|Date|Timestamp|Boolean] \
|
|
644
|
+
[--primary-key] [--foreign-key] \
|
|
645
|
+
[--physical-name <name>] [--physical-type <type>] [--json]
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
**relationship add**
|
|
649
|
+
```bash
|
|
650
|
+
modscape relationship add model.yaml \
|
|
651
|
+
--from <table.column> --to <table.column> \
|
|
652
|
+
--type one-to-one|one-to-many|many-to-one|many-to-many [--json]
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
**lineage add**
|
|
656
|
+
```bash
|
|
657
|
+
modscape lineage add model.yaml --from <tableId> --to <tableId> [--json]
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
**domain add / update**
|
|
661
|
+
```bash
|
|
662
|
+
modscape domain add model.yaml \
|
|
663
|
+
--id <id> --name <name> [--description <text>] [--color <color>] [--json]
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
**domain member add / remove**
|
|
667
|
+
```bash
|
|
668
|
+
modscape domain member add model.yaml --domain <domainId> --table <tableId> [--json]
|
|
669
|
+
modscape domain member remove model.yaml --domain <domainId> --table <tableId> [--json]
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
### 13-4. After Adding Tables
|
|
673
|
+
|
|
674
|
+
`table add` does **not** create layout coordinates. After adding tables, run:
|
|
675
|
+
|
|
676
|
+
```bash
|
|
677
|
+
modscape layout model.yaml
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
This assigns coordinates to all layout-less entries automatically.
|
|
681
|
+
|
|
682
|
+
### 13-5. JSON Output for AI Pipelines
|
|
683
|
+
|
|
684
|
+
All commands support `--json` for machine-readable output:
|
|
685
|
+
|
|
686
|
+
```json
|
|
687
|
+
{ "ok": true, "action": "add", "resource": "table", "id": "fct_orders" }
|
|
688
|
+
{ "ok": false, "error": "Table \"fct_orders\" already exists", "hint": "Use `table update` instead" }
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
---
|
|
692
|
+
|
|
693
|
+
## 15. Project-Specific Rule Extensions
|
|
694
|
+
|
|
695
|
+
A project MAY place a `.modscape/rules.custom.md` file to define rules that extend or override this base file.
|
|
696
|
+
|
|
697
|
+
**How to use it:**
|
|
698
|
+
|
|
699
|
+
- Create `.modscape/rules.custom.md` in the project root (alongside `rules.md`)
|
|
700
|
+
- Write any project-specific rules, naming conventions, or overrides in Markdown
|
|
701
|
+
- AI agents reading this file will also check for `rules.custom.md` and apply it
|
|
702
|
+
|
|
703
|
+
**Priority:** Rules in `rules.custom.md` take priority over this file when they conflict.
|
|
704
|
+
|
|
705
|
+
**What to put in `rules.custom.md`** (examples):
|
|
706
|
+
|
|
707
|
+
```markdown
|
|
708
|
+
## Naming Conventions
|
|
709
|
+
- All fact table IDs must use the prefix `fct_` followed by the domain: e.g., `fct_sales_orders`
|
|
710
|
+
- All dimension table IDs must end in `_dim`: e.g., `customers_dim`
|
|
711
|
+
|
|
712
|
+
## Allowed Table Types
|
|
713
|
+
- This project only uses `fact`, `dimension`, and `mart`. Do NOT use `hub`, `link`, or `satellite`.
|
|
714
|
+
|
|
715
|
+
## Domain Topology
|
|
716
|
+
- This project has three domains: `sales`, `marketing`, `finance`
|
|
717
|
+
- Every new table MUST be assigned to one of these domains
|
|
718
|
+
|
|
719
|
+
## SCD Policy
|
|
720
|
+
- Dimension tables use SCD Type 1 only. Do NOT apply `scd: type2` or higher.
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
`rules.custom.md` is NOT generated by `modscape init`. Create it manually when your project needs it.
|
|
724
|
+
|
|
725
|
+
---
|
|
726
|
+
|
|
727
|
+
## 16. Complete Example
|
|
593
728
|
|
|
594
729
|
```yaml
|
|
595
730
|
domains:
|