graphjin 3.11.3 → 3.13.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/README.md +47 -10
- package/bin/graphjin.js +14 -1
- package/bin/install.js +49 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -61,6 +61,7 @@ GraphJin started
|
|
|
61
61
|
Web UI: http://localhost:8080/
|
|
62
62
|
GraphQL: http://localhost:8080/api/v1/graphql
|
|
63
63
|
REST API: http://localhost:8080/api/v1/rest/
|
|
64
|
+
Workflows: http://localhost:8080/api/v1/workflows/<name>
|
|
64
65
|
MCP: http://localhost:8080/api/v1/mcp
|
|
65
66
|
|
|
66
67
|
Claude Desktop Configuration
|
|
@@ -89,7 +90,7 @@ Copy the JSON config shown and add it to your Claude Desktop config file (see be
|
|
|
89
90
|
GraphJin includes a guided installer that configures MCP for OpenAI Codex, Claude Code, or both.
|
|
90
91
|
|
|
91
92
|
```bash
|
|
92
|
-
# Guided mode (asks target client
|
|
93
|
+
# Guided mode (asks target client and scope)
|
|
93
94
|
graphjin mcp install
|
|
94
95
|
```
|
|
95
96
|
|
|
@@ -109,15 +110,12 @@ graphjin mcp install --client codex --scope project --yes
|
|
|
109
110
|
graphjin mcp install --client claude --scope project --yes
|
|
110
111
|
```
|
|
111
112
|
|
|
112
|
-
Backwards compatibility alias:
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
graphjin mcp plugin install
|
|
116
|
-
```
|
|
117
|
-
|
|
118
113
|
#### Troubleshooting
|
|
119
114
|
|
|
120
|
-
- `graphjin mcp install`
|
|
115
|
+
- `graphjin mcp install` defaults to `--server http://localhost:8080/`.
|
|
116
|
+
- Set a custom server URL with `--server`, for example:
|
|
117
|
+
- `graphjin mcp install --client codex --server http://my-host:8080/ --yes`
|
|
118
|
+
- Claude installs use `graphjin mcp --server <url>` under the hood.
|
|
121
119
|
- If Codex CLI does not support `codex mcp add --scope` (older versions), GraphJin automatically falls back to updating:
|
|
122
120
|
- global scope: `~/.codex/config.toml`
|
|
123
121
|
- local scope: `.codex/config.toml`
|
|
@@ -155,7 +153,8 @@ Copy paste the Claude Desktop Config provided by `graphjin serve` into the Claud
|
|
|
155
153
|
1. **Connects to database** - Reads your schema automatically
|
|
156
154
|
2. **Discovers relationships** - Foreign keys become navigable joins
|
|
157
155
|
3. **Exposes MCP tools** - Teach any LLM the query syntax
|
|
158
|
-
4. **
|
|
156
|
+
4. **Runs JS workflows** - Chain multiple GraphJin MCP tools in one reusable workflow
|
|
157
|
+
5. **Compiles to SQL** - Every request becomes a single optimized query
|
|
159
158
|
|
|
160
159
|
No resolvers. No ORM. No N+1 queries. Just point and query.
|
|
161
160
|
|
|
@@ -221,7 +220,45 @@ Works from Node.js, Go, or any WebSocket client.
|
|
|
221
220
|
|
|
222
221
|
## MCP Tools
|
|
223
222
|
|
|
224
|
-
GraphJin exposes several tools that guide AI models to write valid queries. Key tools: `list_tables` and `describe_table` for schema discovery, `get_query_syntax` for learning the DSL, `execute_graphql` for running queries, and `execute_saved_query` for production-approved queries.
|
|
223
|
+
GraphJin exposes several tools that guide AI models to write valid queries. Key tools: `list_tables` and `describe_table` for schema discovery, `get_query_syntax` for learning the DSL, `execute_graphql` for running queries, and `execute_saved_query` for production-approved queries.
|
|
224
|
+
|
|
225
|
+
For JS orchestration, use:
|
|
226
|
+
- `get_js_runtime_api` to discover exactly which globals/functions are available inside workflow scripts
|
|
227
|
+
- `execute_workflow` to run `./workflows/<name>.js` with input variables
|
|
228
|
+
|
|
229
|
+
Prompts like `write_query` and `fix_query_error` help models construct and debug queries.
|
|
230
|
+
|
|
231
|
+
## JS Workflows (MCP + REST)
|
|
232
|
+
|
|
233
|
+
Workflows let an LLM run multi-step logic in JavaScript while still using GraphJin MCP tools for DB-aware operations.
|
|
234
|
+
|
|
235
|
+
Create a file in `./workflows`, for example `./workflows/customer_insights.js`:
|
|
236
|
+
|
|
237
|
+
```js
|
|
238
|
+
function main(input) {
|
|
239
|
+
const tables = gj.tools.listTables({});
|
|
240
|
+
const top = gj.tools.executeSavedQuery({
|
|
241
|
+
name: "top_customers",
|
|
242
|
+
variables: { limit: input.limit || 5 }
|
|
243
|
+
});
|
|
244
|
+
return { tables, top };
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Run via MCP
|
|
249
|
+
|
|
250
|
+
Call:
|
|
251
|
+
- `get_js_runtime_api` first (for exact runtime schema)
|
|
252
|
+
- `execute_workflow` with:
|
|
253
|
+
- `name`: workflow file name (with or without `.js`)
|
|
254
|
+
- `variables`: input payload passed to global `input` and `main(input)`
|
|
255
|
+
|
|
256
|
+
### Run via REST
|
|
257
|
+
|
|
258
|
+
- `POST /api/v1/workflows/<name>` with JSON body
|
|
259
|
+
- `GET /api/v1/workflows/<name>?variables={...json...}`
|
|
260
|
+
|
|
261
|
+
Both map variables to the same workflow input object.
|
|
225
262
|
|
|
226
263
|
## Chat Walkthroughs
|
|
227
264
|
|
package/bin/graphjin.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const { spawn } = require('child_process');
|
|
3
3
|
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
4
5
|
|
|
5
6
|
const ext = process.platform === 'win32' ? '.exe' : '';
|
|
6
7
|
const binary = path.join(__dirname, 'graphjin' + ext);
|
|
7
8
|
|
|
9
|
+
if (!fs.existsSync(binary)) {
|
|
10
|
+
console.error(`GraphJin binary not found at: ${binary}`);
|
|
11
|
+
console.error('Try reinstalling: npm install -g graphjin');
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
8
15
|
const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
9
16
|
|
|
10
17
|
child.on('error', (err) => {
|
|
@@ -13,4 +20,10 @@ child.on('error', (err) => {
|
|
|
13
20
|
process.exit(1);
|
|
14
21
|
});
|
|
15
22
|
|
|
16
|
-
child.on('exit', (code) =>
|
|
23
|
+
child.on('exit', (code, signal) => {
|
|
24
|
+
if (signal) {
|
|
25
|
+
console.error(`graphjin terminated by signal: ${signal}`);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
process.exit(code ?? 0);
|
|
29
|
+
});
|
package/bin/install.js
CHANGED
|
@@ -39,6 +39,29 @@ async function download(url, dest) {
|
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
async function downloadWithFallback(candidates, binDir) {
|
|
43
|
+
let lastErr;
|
|
44
|
+
|
|
45
|
+
for (const candidate of candidates) {
|
|
46
|
+
const archivePath = path.join(binDir, candidate.filename);
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
await download(candidate.url, archivePath);
|
|
50
|
+
return {
|
|
51
|
+
archivePath,
|
|
52
|
+
filename: candidate.filename,
|
|
53
|
+
};
|
|
54
|
+
} catch (err) {
|
|
55
|
+
lastErr = err;
|
|
56
|
+
try {
|
|
57
|
+
fs.unlinkSync(archivePath);
|
|
58
|
+
} catch {}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
throw lastErr || new Error('No download candidates available');
|
|
63
|
+
}
|
|
64
|
+
|
|
42
65
|
async function extract(tarPath, destDir) {
|
|
43
66
|
// Use tar module for extraction
|
|
44
67
|
const tar = require('tar');
|
|
@@ -62,14 +85,28 @@ async function install() {
|
|
|
62
85
|
process.exit(1);
|
|
63
86
|
}
|
|
64
87
|
|
|
65
|
-
const ext = platform === 'windows' ? '.zip' : '.tar.gz';
|
|
66
|
-
const filename = `graphjin_${platform}_${arch}${ext}`;
|
|
67
|
-
const url = `https://github.com/dosco/graphjin/releases/download/v${version}/${filename}`;
|
|
68
|
-
|
|
69
88
|
const binDir = __dirname;
|
|
70
|
-
const archivePath = path.join(binDir, filename);
|
|
71
89
|
const binaryName = platform === 'windows' ? 'graphjin.exe' : 'graphjin';
|
|
72
90
|
const binaryPath = path.join(binDir, binaryName);
|
|
91
|
+
const releaseBase = `https://github.com/dosco/graphjin/releases/download/v${version}`;
|
|
92
|
+
|
|
93
|
+
// New releases include version in the archive name. Keep legacy fallback
|
|
94
|
+
// names to remain backward compatible with older tags.
|
|
95
|
+
const filenames = platform === 'windows'
|
|
96
|
+
? [
|
|
97
|
+
`graphjin_${version}_${platform}_${arch}.tar.gz`,
|
|
98
|
+
`graphjin_${version}_${platform}_${arch}.zip`,
|
|
99
|
+
`graphjin_${platform}_${arch}.tar.gz`,
|
|
100
|
+
`graphjin_${platform}_${arch}.zip`,
|
|
101
|
+
]
|
|
102
|
+
: [
|
|
103
|
+
`graphjin_${version}_${platform}_${arch}.tar.gz`,
|
|
104
|
+
`graphjin_${platform}_${arch}.tar.gz`,
|
|
105
|
+
];
|
|
106
|
+
const candidates = filenames.map((filename) => ({
|
|
107
|
+
filename,
|
|
108
|
+
url: `${releaseBase}/${filename}`,
|
|
109
|
+
}));
|
|
73
110
|
|
|
74
111
|
// Skip if binary already exists
|
|
75
112
|
if (fs.existsSync(binaryPath)) {
|
|
@@ -79,12 +116,17 @@ async function install() {
|
|
|
79
116
|
|
|
80
117
|
console.log(`Downloading GraphJin v${version} for ${platform}/${arch}...`);
|
|
81
118
|
|
|
119
|
+
let archivePath = '';
|
|
120
|
+
let selectedFilename = '';
|
|
121
|
+
|
|
82
122
|
try {
|
|
83
|
-
await
|
|
123
|
+
const selected = await downloadWithFallback(candidates, binDir);
|
|
124
|
+
archivePath = selected.archivePath;
|
|
125
|
+
selectedFilename = selected.filename;
|
|
84
126
|
|
|
85
127
|
console.log('Extracting...');
|
|
86
128
|
|
|
87
|
-
if (platform === 'windows') {
|
|
129
|
+
if (platform === 'windows' && selectedFilename.endsWith('.zip')) {
|
|
88
130
|
// For Windows, use PowerShell to extract
|
|
89
131
|
execSync(`powershell -command "Expand-Archive -Path '${archivePath}' -DestinationPath '${binDir}' -Force"`, {
|
|
90
132
|
stdio: 'inherit',
|