erdraft 0.0.0-stage → 0.0.2
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/LICENSE +21 -0
- package/README.md +221 -2
- package/dist/chunk-IQ5YYSCP.js +2464 -0
- package/dist/chunk-VSN3XJPO.js +99 -0
- package/dist/cli.js +758 -0
- package/dist/inspect/index.js +373 -0
- package/dist/inspect/logger.js +64 -0
- package/dist/read-schema-child.js +238 -0
- package/dist/studio-config-TCMRAVMR.js +32 -0
- package/dist/types/core/fields.d.ts +39 -0
- package/dist/types/inspect/field-of.d.ts +3 -0
- package/dist/types/inspect/holds-value.d.ts +2 -0
- package/dist/types/inspect/inspect-logger.d.ts +2 -0
- package/dist/types/inspect/inspector.d.ts +5 -0
- package/dist/types/inspect/listen-on-document.d.ts +5 -0
- package/dist/types/inspect/read-write.d.ts +5 -0
- package/dist/types/inspect/use-field-changes.d.ts +6 -0
- package/dist/types/inspect/watch-storage.d.ts +8 -0
- package/dist/window/apple-touch-icon.png +0 -0
- package/dist/window/assets/index-BCt7ERad.css +2 -0
- package/dist/window/assets/index-v2x3QhC-.js +132 -0
- package/dist/window/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/window/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/window/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/window/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/window/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/window/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/window/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/window/favicon.ico +0 -0
- package/dist/window/favicon.png +0 -0
- package/dist/window/favicon.svg +1 -0
- package/dist/window/index.html +23 -0
- package/package.json +97 -3
- package/skill/SKILL.md +47 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="4.5 4.5 52 52"><path fill="#7CD06A" d="M13.72 9.05A1 1 0 0 1 14.62 8.5L45.38 8.5A1 1 0 0 1 46.28 9.95L41.28 19.95A1 1 0 0 1 40.38 20.5L21.31 20.5A0.5 0.5 0 0 0 20.86 20.78L19.36 23.78A0.5 0.5 0 0 0 19.81 24.5L49.38 24.5A1 1 0 0 1 50.28 25.95L45.28 35.95A1 1 0 0 1 44.38 36.5L25.31 36.5A0.5 0.5 0 0 0 24.86 36.78L23.36 39.78A0.5 0.5 0 0 0 23.81 40.5L53.38 40.5A1 1 0 0 1 54.28 41.95L49.28 51.95A1 1 0 0 1 48.38 52.5L17.62 52.5A1 1 0 0 1 16.72 51.05L21.64 41.22A0.5 0.5 0 0 0 21.19 40.5L11.62 40.5A1 1 0 0 1 10.72 39.05L17.64 25.22A0.5 0.5 0 0 0 17.19 24.5L7.62 24.5A1 1 0 0 1 6.72 23.05Z"/></svg>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Erdraft</title>
|
|
7
|
+
<link rel="icon" href="/favicon.ico" sizes="48x48" />
|
|
8
|
+
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
|
9
|
+
<link rel="icon" href="/favicon.png" type="image/png" sizes="32x32" />
|
|
10
|
+
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
11
|
+
<script>
|
|
12
|
+
// The theme chosen before, or the system's, set before the page is drawn so it never flashes the other
|
|
13
|
+
const chosen = localStorage.getItem('erdraft-theme')
|
|
14
|
+
const dark = chosen ? chosen === 'dark' : matchMedia('(prefers-color-scheme: dark)').matches
|
|
15
|
+
document.documentElement.classList.toggle('dark', dark)
|
|
16
|
+
</script>
|
|
17
|
+
<script type="module" crossorigin src="/assets/index-v2x3QhC-.js"></script>
|
|
18
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BCt7ERad.css">
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<div id="root"></div>
|
|
22
|
+
</body>
|
|
23
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,100 @@
|
|
|
1
1
|
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package.json",
|
|
2
3
|
"name": "erdraft",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
4
|
+
"version": "0.0.2",
|
|
5
|
+
"description": "A project's data model drafted with an agent while a person watches: drafts proposed through MCP, drawn live beside the schema, one adopted before any code is written",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"database",
|
|
8
|
+
"schema",
|
|
9
|
+
"data-model",
|
|
10
|
+
"erd",
|
|
11
|
+
"drizzle",
|
|
12
|
+
"postgres",
|
|
13
|
+
"mcp",
|
|
14
|
+
"claude-code",
|
|
15
|
+
"agent"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://erdraft.com",
|
|
18
|
+
"bugs": "https://github.com/erdraft/erdraft/issues",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/erdraft/erdraft.git"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"type": "module",
|
|
25
|
+
"bin": {
|
|
26
|
+
"erdraft": "dist/cli.js"
|
|
27
|
+
},
|
|
28
|
+
"exports": {
|
|
29
|
+
"./inspect": {
|
|
30
|
+
"types": "./dist/types/inspect/inspector.d.ts",
|
|
31
|
+
"default": "./dist/inspect/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./inspect/logger": {
|
|
34
|
+
"types": "./dist/types/inspect/inspect-logger.d.ts",
|
|
35
|
+
"default": "./dist/inspect/logger.js"
|
|
36
|
+
},
|
|
37
|
+
"./package.json": "./package.json"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"dist",
|
|
41
|
+
"skill"
|
|
42
|
+
],
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=22"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@modelcontextprotocol/sdk": "~1.32.2",
|
|
51
|
+
"@napi-rs/keyring": "~2.1.2",
|
|
52
|
+
"tsx": "~4.23.15",
|
|
53
|
+
"zod": "~4.6.7"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"@ngrok/ngrok": ">=1.7.0",
|
|
57
|
+
"drizzle-orm": ">=0.44.0",
|
|
58
|
+
"react": ">=19.2"
|
|
59
|
+
},
|
|
60
|
+
"peerDependenciesMeta": {
|
|
61
|
+
"@ngrok/ngrok": {
|
|
62
|
+
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"react": {
|
|
65
|
+
"optional": true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@arcnote/typescript-config": "~0.0.0",
|
|
70
|
+
"@arcnote/ui": "~0.0.0",
|
|
71
|
+
"@dagrejs/dagre": "~3.1.3",
|
|
72
|
+
"@fontsource-variable/inter": "~5.3.0",
|
|
73
|
+
"@ngrok/ngrok": "~1.7.0",
|
|
74
|
+
"@tailwindcss/vite": "~4.3.3",
|
|
75
|
+
"@testing-library/react": "~16.3.3",
|
|
76
|
+
"@types/node": "~26.6.6",
|
|
77
|
+
"@types/react": "~19.3.0",
|
|
78
|
+
"@types/react-dom": "~19.3.0",
|
|
79
|
+
"@vitejs/plugin-react": "~6.1.2",
|
|
80
|
+
"@vitest/coverage-v8": "~5.0.5",
|
|
81
|
+
"@xyflow/react": "12.12.0",
|
|
82
|
+
"drizzle-orm": "~0.45.4",
|
|
83
|
+
"happy-dom": "~21.0.4",
|
|
84
|
+
"react": "~19.3.1",
|
|
85
|
+
"react-dom": "~19.3.1",
|
|
86
|
+
"tailwindcss": "~4.3.3",
|
|
87
|
+
"tsup": "~9.0.0",
|
|
88
|
+
"typescript": "~7.0.2",
|
|
89
|
+
"vite": "~8.3.5",
|
|
90
|
+
"vitest": "~5.0.5"
|
|
91
|
+
},
|
|
92
|
+
"scripts": {
|
|
93
|
+
"erdraft": "tsx bin/erdraft.ts",
|
|
94
|
+
"dev": "tsx bin/erdraft.ts studio",
|
|
95
|
+
"bundle": "tsup && vite build && tsc -p tsconfig.build.json",
|
|
96
|
+
"check-types": "tsc --noEmit",
|
|
97
|
+
"test": "vitest run",
|
|
98
|
+
"test:coverage": "vitest run --coverage"
|
|
99
|
+
}
|
|
6
100
|
}
|
package/skill/SKILL.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: erdraft
|
|
3
|
+
description: Design or change the project's database schema with Erdraft, a person watching and adopting in its window before any code is written. Use when asked to design, model or change the data model, tables, columns, relations, keys, indexes or constraints ("add a table for invoices", "model the data for the wiki", "what tables do we need for tags", "desenhar a base de dados", "modelar as tabelas"), and whenever a change to the schema's code is about to be made.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Erdraft
|
|
7
|
+
|
|
8
|
+
Erdraft draws the project's data model, read from its schema's code, in a window a person watches (`erdraft studio`, http://localhost:9369 unless `.erdraft.json` says another port). You propose a change as a **draft**, drawn at once beside the schema; the person **adopts** one in the window; only then is it written in the code. Erdraft never changes the code nor the database.
|
|
9
|
+
|
|
10
|
+
Use the `erdraft` MCP's tools. Where they are not connected, the CLI does the same: `erdraft read`, `tables`, `table <name>`, `propose <file|-> --title <title>`, `revise`, `show`, `wait <id>`, `draft <id>` (`erdraft --help`).
|
|
11
|
+
|
|
12
|
+
## 1. Read before proposing
|
|
13
|
+
|
|
14
|
+
- **The project's own conventions for its schema:** the instructions beside the schema module `.erdraft.json` names and above it (`CLAUDE.md`, `AGENTS.md`, a README), and two or three existing tables like the one asked for. Naming, ids, timestamps, how a table is laid out in files, how migrations and seeds are made: the project's, never your habits.
|
|
15
|
+
- **The schema as the code has it:** `list_databases` (the one the person works on), `read_schema` when the code changed, `list_tables`, then `describe_table` on every table the change touches and the tables they join.
|
|
16
|
+
- **What is asked, measured against what is there:** a table that already holds the field, a name already taken, a screen or a feature the data serves.
|
|
17
|
+
|
|
18
|
+
## 2. Propose the whole design
|
|
19
|
+
|
|
20
|
+
- **One draft holds the whole change:** its tables and columns (types as Postgres names them, `not null` and defaults as meant), its foreign keys with what happens on delete, and every rule the database can hold as an operation, never as prose in a note: unique indexes (`add_index` with `unique`), indexes for what is joined or filtered, checks (`add_check`, a name and its SQL). A rule the database cannot hold goes in the table's note, said as checked by the code that writes. **A `json` or `jsonb` column always carries its `shape`:** its TypeScript type as the code's `$type<...>()` will write it (`{ accent?: string; tone?: 'light' | 'dark' }`), every field and its optionality, literal unions spelled out, so the person reads its fields in the window, behind the braces on its row. A rule of its values (a format, a range) is not in the shape: it goes in the column's note and, once written, in its zod schema.
|
|
21
|
+
- **Its title says what it does, its summary why and what it trades.**
|
|
22
|
+
- **When there is more than one good answer** (a flag on a row or a table of its own, one table or two), propose two or three drafts in one `group`, each whole, so the person compares them a tab each.
|
|
23
|
+
- **Build a large draft step by step** with `revise_draft` (mode `append`); the window follows each step.
|
|
24
|
+
- **Show it:** `show_in_window` on the draft's main table with `related`, so the person sees it with the tables it joins.
|
|
25
|
+
|
|
26
|
+
## 3. Wait for the person
|
|
27
|
+
|
|
28
|
+
Tell the person in one line what the draft is and where to see it, and that they can adopt it there or tell you what to change, then call `wait_for_decision` with the draft's id (the CLI's `erdraft wait <id>`), its time left as it is: short, as your turn is held while you wait, and what the person writes to you is read only between two waits. Never ask them to say they adopted.
|
|
29
|
+
|
|
30
|
+
- **Adopted:** write it (step 4).
|
|
31
|
+
- **Another of its group adopted:** write that one.
|
|
32
|
+
- **Set aside:** stop, and ask what to change.
|
|
33
|
+
- **Still proposed, and the person wrote to you meanwhile:** answer them first. A change asked for (a column taken away, a type changed) is `revise_draft` on that draft, or a new draft in its group when it is another answer; say what changed, then wait again.
|
|
34
|
+
- **Still proposed, nothing written:** wait again. After about ten minutes in all, say the draft waits in the window, and stop; wait again when they come back.
|
|
35
|
+
|
|
36
|
+
Never adopt or set aside a draft yourself, and never write a draft that is not adopted.
|
|
37
|
+
|
|
38
|
+
## 4. Write it in the code
|
|
39
|
+
|
|
40
|
+
- **By the project's conventions** read in step 1: the schema's code, its migration made by the project's own tool (never written by hand where the tool makes it), its tests for each constraint where the project tests its schema, its seeds and documents where it keeps them.
|
|
41
|
+
- **A json column's shape is written as a zod 4 schema** the schema's module exports by the column's table and name in camelCase, then `Shape` (`websites.theme` is `websitesThemeShape`, `wiki_pages.page_place` is `wikiPagesPagePlaceShape`), the column's type inferred from it (`jsonb('theme').$type<z.infer<typeof websitesThemeShape>>()`) and the code that writes the column parsing with it. Erdraft reads that export to draw the shape once the draft is written; a type alone (`$type<Theme>()`) is gone when the module runs, and the column loses its braces. Where the project keeps its json types elsewhere, the module re-exports the schema under that name.
|
|
42
|
+
- **What the code must do differently from the draft** (a foreign key's `on delete`, a name the tool gives, a type the ORM writes otherwise) is said to the person in your reply, with why. Postgres checks a `RESTRICT` key at once and a `NO ACTION` key at the statement's end: a row reached by two cascades (a project's pages and the collection they are in, both going with the project) needs `NO ACTION`, or the delete can fail by the order the cascades run. A check that is null lets a row through: write each so it is true or false (`coalesce`, `is null`).
|
|
43
|
+
- **The database itself** is never changed beyond what the project's commands do (its migrations, its seeds), and rows a person changed are never written over without asking.
|
|
44
|
+
|
|
45
|
+
## 5. Check it is written
|
|
46
|
+
|
|
47
|
+
`read_schema`, then `show_draft` on the draft: it says *Written in the code: the schema holds what it does*, and the window says the same on its card. When it does not, it names the step the code does not hold: write what is missing, or say why it differs. Each json column written shows its shape in `describe_table` (`shape { ... }` on its line): one without is a zod schema missing, or exported under another name.
|