tablewalk 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -61
- package/dist/server/index.js +16 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,38 +1,35 @@
|
|
|
1
1
|
# tablewalk
|
|
2
2
|
|
|
3
|
-
**Follow the data
|
|
3
|
+
**[Follow the data.](https://tablewalk.pages.dev)** — [tablewalk.pages.dev](https://tablewalk.pages.dev)
|
|
4
4
|
|
|
5
5
|
Most database tools are SQL clients that happen to render a grid. tablewalk
|
|
6
|
-
starts somewhere else: a foreign key is a place you can go.
|
|
6
|
+
starts somewhere else: a foreign key is a place you can go. Open a row and it
|
|
7
|
+
shows you every row elsewhere that points at it — the orders on a customer, the
|
|
8
|
+
customer on an order — so you follow the data instead of writing joins to reach
|
|
9
|
+
it. The same machinery answers over **MCP**, so a coding agent sees what you
|
|
10
|
+
see ([jump to setup](#for-coding-agents-mcp)).
|
|
7
11
|
|
|
8
12
|
```bash
|
|
9
|
-
npx tablewalk --demo
|
|
10
|
-
npx tablewalk
|
|
11
|
-
npx tablewalk
|
|
12
|
-
npx tablewalk postgres://user:pass@localhost/appdb
|
|
13
|
-
npx tablewalk mydata.sqlite --export md >> CLAUDE.md # the schema, as a committed brief
|
|
14
|
-
npx tablewalk postgres://… --lint --fail-on high # what the shape costs, for CI
|
|
15
|
-
npx tablewalk --config ./tablewalk.json --diff staging # is staging the same shape?
|
|
13
|
+
npx tablewalk --demo # build a sample database and open it — an instant try
|
|
14
|
+
npx tablewalk mydata.sqlite # or your own: SQLite, Postgres, MySQL
|
|
15
|
+
npx tablewalk # or nothing, and the page asks for a connection
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
No config
|
|
19
|
-
|
|
18
|
+
No config, no build step, no schema to define first — it reads the catalog on
|
|
19
|
+
connect. **Read-only** until you turn editing on, per connection. Runs from
|
|
20
|
+
`npx`, a [Docker image](#docker-and-a-desktop-app), or a desktop app.
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
keychain rather than into the file.
|
|
22
|
+
`npx tablewalk` with no target opens a page that asks for a connection: a form
|
|
23
|
+
that takes a URL or its parts, tests it before keeping it, and reads the
|
|
24
|
+
password from an environment variable or the keychain rather than the string.
|
|
25
|
+
The print-and-exit commands need a target, though — there is nothing for
|
|
26
|
+
`--export`, `--lint`, `--diff` or `--mcp` to read without one:
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
one the screenshots use) in a temp directory and opens it, so there is
|
|
34
|
-
something to walk before you have a database of your own. Nothing of yours is
|
|
35
|
-
touched, and the file is thrown away.
|
|
28
|
+
```bash
|
|
29
|
+
npx tablewalk mydata.sqlite --export md >> CLAUDE.md # the schema, as a committed brief
|
|
30
|
+
npx tablewalk postgres://… --lint --fail-on high # what the shape costs, for CI
|
|
31
|
+
npx tablewalk --config ./tablewalk.json --diff staging # is staging the same shape?
|
|
32
|
+
```
|
|
36
33
|
|
|
37
34
|
## The idea
|
|
38
35
|
|
|
@@ -201,39 +198,45 @@ npx tablewalk --mcp --config ./tablewalk.json # speaks MCP on stdio
|
|
|
201
198
|
{ "mcpServers": { "tablewalk": { "command": "npx", "args": ["tablewalk", "--mcp", "--config", "./tablewalk.json"] } } }
|
|
202
199
|
```
|
|
203
200
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
`
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
`
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
`
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
`
|
|
201
|
+
Or point it at a database instead of a config file: `"args": ["tablewalk",
|
|
202
|
+
"--mcp", "--db", "postgres://localhost/app"]`. **Twenty-three tools** —
|
|
203
|
+
seventeen read-only, and six writes offered only when a connection is
|
|
204
|
+
`"writable": true`. Every answer carries a deep link the human beside the
|
|
205
|
+
agent can open in the UI, and says what it cost in rows and milliseconds.
|
|
206
|
+
|
|
207
|
+
**Reading**
|
|
208
|
+
|
|
209
|
+
| tool | what it answers |
|
|
210
|
+
|---|---|
|
|
211
|
+
| `schema_summary` | orientation in a few hundred tokens — hubs, event tables, the deepest reference chain |
|
|
212
|
+
| `tables` / `table` | the list; then a table's columns, DDL, and foreign keys in **both** directions |
|
|
213
|
+
| `find` | where a name lives, across every table and column |
|
|
214
|
+
| `query` | the query language; its errors carry suggestions and the table's real columns, so a mistake is fixed in one retry |
|
|
215
|
+
| `breakdown` | counts and sums grouped by something — `invoice count by month invoice_date` |
|
|
216
|
+
| `record` | one row, its human name, and everything that points at it |
|
|
217
|
+
| `sql` | read-only, for whatever the language cannot say |
|
|
218
|
+
| `explain` | the planner's account of a statement without running it — feed a `query` answer's `sql` back |
|
|
219
|
+
| `profile` | what a column actually holds: null share, distinct count, range, the values that repeat |
|
|
220
|
+
| `lint` | what the shape will cost: keyless tables, unindexed references, naive timestamps |
|
|
221
|
+
| `change_impact` | what breaks if you change a table or column — asked *before* the migration is written |
|
|
222
|
+
| `diff` | whether two connections are still the same shape |
|
|
223
|
+
| `order` | what has to exist before what, and the reverse for teardown |
|
|
224
|
+
| `fixture` | a real row and the graph it belongs to, ready to replay into a test database |
|
|
225
|
+
| `refresh` | re-read the catalog after a migration |
|
|
226
|
+
| `connections` | list them; the call to start with |
|
|
227
|
+
|
|
228
|
+
**Writing** — offered only when a connection is marked `"writable": true`; a
|
|
229
|
+
read-only server does not list tools it would refuse.
|
|
230
|
+
|
|
231
|
+
| tool | what it does |
|
|
232
|
+
|---|---|
|
|
233
|
+
| `insert` | one row; answers with what the database stored, defaults filled and key assigned |
|
|
234
|
+
| `update` | one row, by its primary key |
|
|
235
|
+
| `delete` | reports its impact first — every table pointing at the row, counts, `ON DELETE` rules — and removes nothing until called again with `confirm: true` |
|
|
236
|
+
| `insert_graph` / `delete_graph` | several related rows in one all-or-nothing transaction |
|
|
237
|
+
| `revert` | undo the last write, behind the same two-call `confirm` gate; a raw `sql` write is recorded but marked unrevertible, since it has no general inverse |
|
|
238
|
+
|
|
239
|
+
Write answers carry `rowsInserted` / `rowsWritten` / `rowsDeleted`.
|
|
237
240
|
|
|
238
241
|
A fixture is a graph, so `insert_graph` takes one: several related rows in one
|
|
239
242
|
transaction, where either all of them land or none does. A row that cannot
|
|
@@ -493,10 +496,22 @@ is your own machine; bind wider and it is whoever else can reach you.
|
|
|
493
496
|
|
|
494
497
|
## Docker, and a desktop app
|
|
495
498
|
|
|
496
|
-
|
|
497
|
-
|
|
499
|
+
**Container** — `ghcr.io/rbaljinder/tablewalk`. It reads its connections from a
|
|
500
|
+
mounted `tablewalk.json` and holds no configuration of its own:
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
docker run --rm -p 127.0.0.1:4111:4111 -v "$PWD:/config:ro" ghcr.io/rbaljinder/tablewalk
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
[DEPLOY.md](DEPLOY.md) covers the two things a container changes about the
|
|
498
507
|
security model — binding `0.0.0.0` inside while publishing only to the host's
|
|
499
|
-
loopback, and `--allowed-host` for reaching it by
|
|
508
|
+
loopback, and `--allowed-host` for reaching it by a name other than
|
|
509
|
+
`localhost`.
|
|
510
|
+
|
|
511
|
+
**Desktop** — a native app (macOS, Windows, Linux) is attached to each
|
|
512
|
+
[GitHub release](https://github.com/rbaljinder/tablewalk/releases). The builds
|
|
513
|
+
are currently unsigned, so the first open needs an "open anyway" past the OS
|
|
514
|
+
warning; `npx tablewalk` and the container need no such thing.
|
|
500
515
|
|
|
501
516
|
## Keyboard
|
|
502
517
|
|
package/dist/server/index.js
CHANGED
|
@@ -2170,7 +2170,22 @@ async function readJson(req) {
|
|
|
2170
2170
|
async function openBrowser(url) {
|
|
2171
2171
|
const { spawn } = await import('node:child_process');
|
|
2172
2172
|
const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
2173
|
-
|
|
2173
|
+
try {
|
|
2174
|
+
const child = spawn(cmd, [url], { detached: true, stdio: 'ignore' });
|
|
2175
|
+
/* A headless box — a container, a server, an SSH session — has no
|
|
2176
|
+
`xdg-open`, and `spawn` reports that as an `error` event, not a throw.
|
|
2177
|
+
With no handler Node re-raises it as an uncaught exception and takes the
|
|
2178
|
+
whole process down — so `--open`, and `--demo` which implies it, crashed
|
|
2179
|
+
exactly where it was most useful: the container serving the demo. A
|
|
2180
|
+
missing opener is not fatal. The server is already listening and the URL
|
|
2181
|
+
is already printed; opening it is a convenience, not a requirement. */
|
|
2182
|
+
child.once('error', () => { });
|
|
2183
|
+
child.unref();
|
|
2184
|
+
}
|
|
2185
|
+
catch {
|
|
2186
|
+
/* Some platforms throw synchronously instead. Same non-answer: the server
|
|
2187
|
+
stays up, the URL is on screen, the reader opens it themselves. */
|
|
2188
|
+
}
|
|
2174
2189
|
}
|
|
2175
2190
|
/* Started only when run, not when imported.
|
|
2176
2191
|
|