kubun 0.9.0 → 0.11.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 +22 -234
- package/bin/dev.js +12 -4
- package/bin/run.js +11 -2
- package/lib/account.d.ts +2 -0
- package/lib/account.js +5 -0
- package/lib/client.d.ts +2 -0
- package/{dist → lib}/client.js +4 -1
- package/lib/commands/account.d.ts +2 -0
- package/lib/commands/account.js +24 -0
- package/lib/commands/graph.d.ts +2 -0
- package/lib/commands/graph.js +74 -0
- package/lib/commands/graphql.d.ts +2 -0
- package/lib/commands/graphql.js +33 -0
- package/lib/commands/mcp.d.ts +2 -0
- package/lib/commands/mcp.js +21 -0
- package/lib/commands/model.d.ts +2 -0
- package/lib/commands/model.js +69 -0
- package/lib/commands/serve.d.ts +2 -0
- package/lib/commands/serve.js +116 -0
- package/lib/fs.d.ts +4 -0
- package/{dist → lib}/fs.js +6 -2
- package/lib/identity.d.ts +19 -0
- package/lib/identity.js +31 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +19 -0
- package/lib/options.d.ts +19 -0
- package/lib/options.js +47 -0
- package/lib/program.d.ts +2 -0
- package/lib/program.js +28 -0
- package/lib/ui.d.ts +5 -0
- package/lib/ui.js +23 -0
- package/package.json +36 -45
- package/bin/dev.cmd +0 -3
- package/bin/run.cmd +0 -3
- package/dist/account.js +0 -5
- package/dist/commands/account/generate.js +0 -10
- package/dist/commands/account/id.js +0 -18
- package/dist/commands/graph/deploy.js +0 -32
- package/dist/commands/graph/mutate.js +0 -32
- package/dist/commands/graph/query.js +0 -32
- package/dist/commands/graphql/schema.js +0 -41
- package/dist/commands/mcp.js +0 -33
- package/dist/commands/model/cluster.js +0 -35
- package/dist/commands/model/create.js +0 -69
- package/dist/commands/serve.js +0 -126
- package/dist/index.js +0 -1
- package/oclif.manifest.json +0 -533
package/README.md
CHANGED
|
@@ -1,247 +1,35 @@
|
|
|
1
|
-
kubun
|
|
2
|
-
=================
|
|
1
|
+
# kubun
|
|
3
2
|
|
|
4
|
-
Kubun CLI
|
|
3
|
+
Kubun CLI.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
[](https://oclif.io)
|
|
8
5
|
[](https://npmjs.org/package/kubun)
|
|
9
6
|
[](https://npmjs.org/package/kubun)
|
|
10
7
|
|
|
8
|
+
## Usage
|
|
11
9
|
|
|
12
|
-
<!-- toc -->
|
|
13
|
-
* [Usage](#usage)
|
|
14
|
-
* [Commands](#commands)
|
|
15
|
-
<!-- tocstop -->
|
|
16
|
-
# Usage
|
|
17
|
-
<!-- usage -->
|
|
18
10
|
```sh-session
|
|
19
|
-
$
|
|
20
|
-
$ kubun
|
|
21
|
-
|
|
22
|
-
$ kubun (--version)
|
|
23
|
-
kubun/0.9.0 darwin-arm64 node-v24.15.0
|
|
24
|
-
$ kubun --help [COMMAND]
|
|
25
|
-
USAGE
|
|
26
|
-
$ kubun COMMAND
|
|
27
|
-
...
|
|
28
|
-
```
|
|
29
|
-
<!-- usagestop -->
|
|
30
|
-
# Commands
|
|
31
|
-
<!-- commands -->
|
|
32
|
-
* [`kubun account generate`](#kubun-account-generate)
|
|
33
|
-
* [`kubun account id`](#kubun-account-id)
|
|
34
|
-
* [`kubun graph deploy`](#kubun-graph-deploy)
|
|
35
|
-
* [`kubun graph mutate ID TEXT`](#kubun-graph-mutate-id-text)
|
|
36
|
-
* [`kubun graph query ID TEXT`](#kubun-graph-query-id-text)
|
|
37
|
-
* [`kubun graphql schema`](#kubun-graphql-schema)
|
|
38
|
-
* [`kubun help [COMMAND]`](#kubun-help-command)
|
|
39
|
-
* [`kubun mcp`](#kubun-mcp)
|
|
40
|
-
* [`kubun model cluster`](#kubun-model-cluster)
|
|
41
|
-
* [`kubun model create NAME SCHEMA`](#kubun-model-create-name-schema)
|
|
42
|
-
* [`kubun serve`](#kubun-serve)
|
|
43
|
-
|
|
44
|
-
## `kubun account generate`
|
|
45
|
-
|
|
46
|
-
Generate a random private key to use as account signer
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
USAGE
|
|
50
|
-
$ kubun account generate
|
|
51
|
-
|
|
52
|
-
DESCRIPTION
|
|
53
|
-
Generate a random private key to use as account signer
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## `kubun account id`
|
|
57
|
-
|
|
58
|
-
Display the DID of an account given its private key
|
|
59
|
-
|
|
60
|
-
```
|
|
61
|
-
USAGE
|
|
62
|
-
$ kubun account id -k <value>
|
|
63
|
-
|
|
64
|
-
FLAGS
|
|
65
|
-
-k, --privateKey=<value> (required) [env: KUBUN_PRIVATE_KEY] base64-encoded private key
|
|
66
|
-
|
|
67
|
-
DESCRIPTION
|
|
68
|
-
Display the DID of an account given its private key
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## `kubun graph deploy`
|
|
72
|
-
|
|
73
|
-
Deploy a documents model graph
|
|
74
|
-
|
|
11
|
+
$ pnpm add -g kubun
|
|
12
|
+
$ kubun --help
|
|
13
|
+
$ kubun <command> --help
|
|
75
14
|
```
|
|
76
|
-
USAGE
|
|
77
|
-
$ kubun graph deploy -c <value>... -k <value> [--id <value>] [-n <value>] [--url <value>]
|
|
78
15
|
|
|
79
|
-
|
|
80
|
-
-c, --cluster=<value>... (required) path of the JSON file of the cluster
|
|
81
|
-
-k, --privateKey=<value> (required) [env: KUBUN_PRIVATE_KEY] base64-encoded private key
|
|
82
|
-
-n, --name=<value> graph name
|
|
83
|
-
--id=<value> graph ID
|
|
84
|
-
--url=<value> Kubun server URL
|
|
16
|
+
The CLI is built on [commander](https://github.com/tj/commander.js) with [`@tejika/cli`](https://www.npmjs.com/package/@tejika/cli); status output renders to stderr (via ink) and data payloads to stdout, so command output stays pipeable.
|
|
85
17
|
|
|
86
|
-
|
|
87
|
-
Deploy a documents model graph
|
|
88
|
-
```
|
|
18
|
+
## Commands
|
|
89
19
|
|
|
90
|
-
|
|
20
|
+
Run `kubun <command> --help` for the full, authoritative flag list — the descriptions below are a summary.
|
|
91
21
|
|
|
92
|
-
|
|
22
|
+
| Command | Description |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| `kubun account generate` | Generate a random private key to use as account signer |
|
|
25
|
+
| `kubun account id` | Display the DID of an account given its private key |
|
|
26
|
+
| `kubun graph mutate <id> <text>` | Execute a GraphQL mutation on a graph |
|
|
27
|
+
| `kubun graph query <id> <text>` | Execute a GraphQL query on a graph |
|
|
28
|
+
| `kubun graph deploy` | Deploy a documents model graph |
|
|
29
|
+
| `kubun graphql schema` | Create a GraphQL schema from clusters of document models |
|
|
30
|
+
| `kubun model cluster` | Create a documents cluster model |
|
|
31
|
+
| `kubun model create <name> <schema>` | Create a document model |
|
|
32
|
+
| `kubun mcp` | Start an MCP server for Kubun |
|
|
33
|
+
| `kubun serve` | Start a local Kubun server |
|
|
93
34
|
|
|
94
|
-
|
|
95
|
-
USAGE
|
|
96
|
-
$ kubun graph mutate ID TEXT -k <value> [--url <value>] [--variables <value>]
|
|
97
|
-
|
|
98
|
-
ARGUMENTS
|
|
99
|
-
ID graph ID
|
|
100
|
-
TEXT mutation text
|
|
101
|
-
|
|
102
|
-
FLAGS
|
|
103
|
-
-k, --privateKey=<value> (required) [env: KUBUN_PRIVATE_KEY] base64-encoded private key
|
|
104
|
-
--url=<value> Kubun server URL
|
|
105
|
-
--variables=<value> query variables as JSON string
|
|
106
|
-
|
|
107
|
-
DESCRIPTION
|
|
108
|
-
Execute a GraphQL mutation on a graph
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## `kubun graph query ID TEXT`
|
|
112
|
-
|
|
113
|
-
Execute a GraphQL query on a graph
|
|
114
|
-
|
|
115
|
-
```
|
|
116
|
-
USAGE
|
|
117
|
-
$ kubun graph query ID TEXT -k <value> [--url <value>] [--variables <value>]
|
|
118
|
-
|
|
119
|
-
ARGUMENTS
|
|
120
|
-
ID graph ID
|
|
121
|
-
TEXT query text
|
|
122
|
-
|
|
123
|
-
FLAGS
|
|
124
|
-
-k, --privateKey=<value> (required) [env: KUBUN_PRIVATE_KEY] base64-encoded private key
|
|
125
|
-
--url=<value> Kubun server URL
|
|
126
|
-
--variables=<value> query variables as JSON string
|
|
127
|
-
|
|
128
|
-
DESCRIPTION
|
|
129
|
-
Execute a GraphQL query on a graph
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## `kubun graphql schema`
|
|
133
|
-
|
|
134
|
-
Create a GraphQL schema from clusters of document models
|
|
135
|
-
|
|
136
|
-
```
|
|
137
|
-
USAGE
|
|
138
|
-
$ kubun graphql schema -c <value>... [-o <value>]
|
|
139
|
-
|
|
140
|
-
FLAGS
|
|
141
|
-
-c, --cluster=<value>... (required) path of the JSON file of the cluster
|
|
142
|
-
-o, --output=<value> output file for the GraphQL schema
|
|
143
|
-
|
|
144
|
-
DESCRIPTION
|
|
145
|
-
Create a GraphQL schema from clusters of document models
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
## `kubun help [COMMAND]`
|
|
149
|
-
|
|
150
|
-
Display help for kubun.
|
|
151
|
-
|
|
152
|
-
```
|
|
153
|
-
USAGE
|
|
154
|
-
$ kubun help [COMMAND...] [-n]
|
|
155
|
-
|
|
156
|
-
ARGUMENTS
|
|
157
|
-
[COMMAND...] Command to show help for.
|
|
158
|
-
|
|
159
|
-
FLAGS
|
|
160
|
-
-n, --nested-commands Include all nested commands in the output.
|
|
161
|
-
|
|
162
|
-
DESCRIPTION
|
|
163
|
-
Display help for kubun.
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/6.2.46/src/commands/help.ts)_
|
|
167
|
-
|
|
168
|
-
## `kubun mcp`
|
|
169
|
-
|
|
170
|
-
Start an MCP server for Kubun
|
|
171
|
-
|
|
172
|
-
```
|
|
173
|
-
USAGE
|
|
174
|
-
$ kubun mcp [-c <value> | -d <value>] [-k <value>]
|
|
175
|
-
|
|
176
|
-
FLAGS
|
|
177
|
-
-c, --connect=<value> URL of an existing Kubun HTTP server to connect to
|
|
178
|
-
-d, --db=<value> SQLite database path or PostgreSQL URL
|
|
179
|
-
-k, --privateKey=<value> [env: KUBUN_PRIVATE_KEY] base64-encoded private key
|
|
180
|
-
|
|
181
|
-
DESCRIPTION
|
|
182
|
-
Start an MCP server for Kubun
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
## `kubun model cluster`
|
|
186
|
-
|
|
187
|
-
Create a documents cluster model
|
|
188
|
-
|
|
189
|
-
```
|
|
190
|
-
USAGE
|
|
191
|
-
$ kubun model cluster -m <value>... [-o <value>]
|
|
192
|
-
|
|
193
|
-
FLAGS
|
|
194
|
-
-m, --model=<value>... (required) document model as JSON string
|
|
195
|
-
-o, --output=<value> output file for the cluster
|
|
196
|
-
|
|
197
|
-
DESCRIPTION
|
|
198
|
-
Create a documents cluster model
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
## `kubun model create NAME SCHEMA`
|
|
202
|
-
|
|
203
|
-
Create a document model
|
|
204
|
-
|
|
205
|
-
```
|
|
206
|
-
USAGE
|
|
207
|
-
$ kubun model create NAME SCHEMA [-b default|interface|unique] [-c] [-o <value>] [-u <value>...]
|
|
208
|
-
|
|
209
|
-
ARGUMENTS
|
|
210
|
-
NAME document model name
|
|
211
|
-
SCHEMA document schema as JSON string
|
|
212
|
-
|
|
213
|
-
FLAGS
|
|
214
|
-
-b, --behavior=<option> [default: default] behavior of the document
|
|
215
|
-
<options: default|interface|unique>
|
|
216
|
-
-c, --cluster create a cluster model instead of a document model
|
|
217
|
-
-o, --output=<value> output file
|
|
218
|
-
-u, --uniqueField=<value>... unique field of the document when behavior is set to "unique"
|
|
219
|
-
|
|
220
|
-
DESCRIPTION
|
|
221
|
-
Create a document model
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
## `kubun serve`
|
|
225
|
-
|
|
226
|
-
Start a local Kubun server
|
|
227
|
-
|
|
228
|
-
```
|
|
229
|
-
USAGE
|
|
230
|
-
$ kubun serve [-a <value>] [--autoAcceptPeers <value> --p2p] [--db <value>] [-l
|
|
231
|
-
trace|debug|info|warning|error|fatal] [-p <value>] [-k <value> | --id <value>]
|
|
232
|
-
|
|
233
|
-
FLAGS
|
|
234
|
-
-a, --allowedOrigin=<value> [default: *, env: KUBUN_ALLOWED_ORIGIN] allowed HTTP origin
|
|
235
|
-
-k, --privateKey=<value> [env: KUBUN_PRIVATE_KEY] base64-encoded private key
|
|
236
|
-
-l, --logLevel=<option> [default: warning] log level
|
|
237
|
-
<options: trace|debug|info|warning|error|fatal>
|
|
238
|
-
-p, --port=<value> port to listen on
|
|
239
|
-
--autoAcceptPeers=<value> comma-separated DIDs to auto-accept for peer join flows
|
|
240
|
-
--db=<value> path to the local SQLite database
|
|
241
|
-
--id=<value> server ID
|
|
242
|
-
--p2p enable P2P mode with sync and graph protocols over HTTP
|
|
243
|
-
|
|
244
|
-
DESCRIPTION
|
|
245
|
-
Start a local Kubun server
|
|
246
|
-
```
|
|
247
|
-
<!-- commandsstop -->
|
|
35
|
+
Common flags: `-k, --private-key <value>` (also read from `KUBUN_PRIVATE_KEY`), `--url <value>`, `-l, --log-level <level>`, `-p, --port <port>`, `-a, --allowed-origin <origin>` (also `KUBUN_ALLOWED_ORIGIN`).
|
package/bin/dev.js
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
#!/usr/bin/env -S node --
|
|
1
|
+
#!/usr/bin/env -S node --disable-warning=ExperimentalWarning
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
import { execute } from '@oclif/core'
|
|
3
|
+
import { run } from '../lib/index.js'
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
process.on('unhandledRejection', (reason) => {
|
|
6
|
+
const message = reason instanceof Error ? reason.message : String(reason)
|
|
7
|
+
process.stderr.write(`✘ ${message}\n`)
|
|
8
|
+
if (process.env.KUBUN_DEBUG === '1' && reason instanceof Error && reason.stack != null) {
|
|
9
|
+
process.stderr.write(`${reason.stack}\n`)
|
|
10
|
+
}
|
|
11
|
+
process.exitCode = 1
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
await run(process.argv)
|
package/bin/run.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { run } from '../lib/index.js'
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
process.on('unhandledRejection', (reason) => {
|
|
6
|
+
const message = reason instanceof Error ? reason.message : String(reason)
|
|
7
|
+
process.stderr.write(`✘ ${message}\n`)
|
|
8
|
+
if (process.env.KUBUN_DEBUG === '1' && reason instanceof Error && reason.stack != null) {
|
|
9
|
+
process.stderr.write(`${reason.stack}\n`)
|
|
10
|
+
}
|
|
11
|
+
process.exitCode = 1
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
await run(process.argv)
|
package/lib/account.d.ts
ADDED
package/lib/account.js
ADDED
package/lib/client.d.ts
ADDED
package/{dist → lib}/client.js
RENAMED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { HTTPClient } from '@kubun/http-client';
|
|
2
2
|
import { getSigner } from './account.js';
|
|
3
3
|
export function createClient(signerKey, url = 'http://localhost:4321') {
|
|
4
|
-
return new HTTPClient({
|
|
4
|
+
return new HTTPClient({
|
|
5
|
+
identity: getSigner(signerKey),
|
|
6
|
+
url
|
|
7
|
+
});
|
|
5
8
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { randomPrivateKey } from '@kokuin/token';
|
|
2
|
+
import { toB64 } from '@sozai/codec';
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { getSigner } from '../account.js';
|
|
5
|
+
import { withPrivateKey } from '../options.js';
|
|
6
|
+
function createGenerateCommand() {
|
|
7
|
+
return new Command('generate').description('Generate a random private key to use as account signer').action(async ()=>{
|
|
8
|
+
const key = await randomPrivateKey();
|
|
9
|
+
console.log(toB64(key));
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function createIDCommand() {
|
|
13
|
+
const cmd = new Command('id').description('Display the DID of an account given its private key');
|
|
14
|
+
withPrivateKey(cmd, {
|
|
15
|
+
required: true
|
|
16
|
+
});
|
|
17
|
+
cmd.action((opts)=>{
|
|
18
|
+
console.log(getSigner(opts.privateKey).id);
|
|
19
|
+
});
|
|
20
|
+
return cmd;
|
|
21
|
+
}
|
|
22
|
+
export function createAccountCommand() {
|
|
23
|
+
return new Command('account').description('Account commands').addCommand(createGenerateCommand()).addCommand(createIDCommand());
|
|
24
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { createClient } from '../client.js';
|
|
3
|
+
import { readJSON } from '../fs.js';
|
|
4
|
+
import { withPrivateKey, withURL } from '../options.js';
|
|
5
|
+
import { renderNotice, withSpinner } from '../ui.js';
|
|
6
|
+
function parseVariables(value) {
|
|
7
|
+
if (!value) {
|
|
8
|
+
return {};
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(value);
|
|
12
|
+
} catch {
|
|
13
|
+
throw new Error(`--variables is not valid JSON: ${value}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function createMutateCommand() {
|
|
17
|
+
const cmd = new Command('mutate').description('Execute a GraphQL mutation on a graph').argument('<id>', 'graph ID').argument('<text>', 'mutation text').option('--variables <json>', 'query variables as JSON string');
|
|
18
|
+
withPrivateKey(cmd, {
|
|
19
|
+
required: true
|
|
20
|
+
});
|
|
21
|
+
withURL(cmd);
|
|
22
|
+
cmd.action(async (id, text, opts)=>{
|
|
23
|
+
const client = createClient(opts.privateKey, opts.url);
|
|
24
|
+
const result = await withSpinner('Executing graph mutation...', ()=>client.mutateGraph({
|
|
25
|
+
id,
|
|
26
|
+
text,
|
|
27
|
+
variables: parseVariables(opts.variables)
|
|
28
|
+
}));
|
|
29
|
+
renderNotice('success', 'Graph mutation executed');
|
|
30
|
+
console.log(JSON.stringify(result, null, 2));
|
|
31
|
+
});
|
|
32
|
+
return cmd;
|
|
33
|
+
}
|
|
34
|
+
function createQueryCommand() {
|
|
35
|
+
const cmd = new Command('query').description('Execute a GraphQL query on a graph').argument('<id>', 'graph ID').argument('<text>', 'query text').option('--variables <json>', 'query variables as JSON string');
|
|
36
|
+
withPrivateKey(cmd, {
|
|
37
|
+
required: true
|
|
38
|
+
});
|
|
39
|
+
withURL(cmd);
|
|
40
|
+
cmd.action(async (id, text, opts)=>{
|
|
41
|
+
const client = createClient(opts.privateKey, opts.url);
|
|
42
|
+
const result = await withSpinner('Querying graph...', ()=>client.queryGraph({
|
|
43
|
+
id,
|
|
44
|
+
text,
|
|
45
|
+
variables: parseVariables(opts.variables)
|
|
46
|
+
}));
|
|
47
|
+
renderNotice('success', 'Graph query executed');
|
|
48
|
+
console.log(JSON.stringify(result, null, 2));
|
|
49
|
+
});
|
|
50
|
+
return cmd;
|
|
51
|
+
}
|
|
52
|
+
function createDeployCommand() {
|
|
53
|
+
const cmd = new Command('deploy').description('Deploy a documents model graph').requiredOption('-c, --cluster <path...>', 'path of the JSON file of the cluster (repeatable)').option('--id <id>', 'graph ID').option('-n, --name <name>', 'graph name');
|
|
54
|
+
withPrivateKey(cmd, {
|
|
55
|
+
required: true
|
|
56
|
+
});
|
|
57
|
+
withURL(cmd);
|
|
58
|
+
cmd.action(async (opts)=>{
|
|
59
|
+
const client = createClient(opts.privateKey, opts.url);
|
|
60
|
+
const graph = await withSpinner('Deploying graph clusters...', async ()=>{
|
|
61
|
+
const clusters = await Promise.all(opts.cluster.map((path)=>readJSON(path)));
|
|
62
|
+
return client.deployGraph({
|
|
63
|
+
clusters,
|
|
64
|
+
id: opts.id,
|
|
65
|
+
name: opts.name
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
renderNotice('success', `Deployed graph with ID: ${graph.id}`);
|
|
69
|
+
});
|
|
70
|
+
return cmd;
|
|
71
|
+
}
|
|
72
|
+
export function createGraphCommand() {
|
|
73
|
+
return new Command('graph').description('Graph commands').addCommand(createMutateCommand()).addCommand(createQueryCommand()).addCommand(createDeployCommand());
|
|
74
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createSchema } from '@kubun/graphql';
|
|
2
|
+
import { clusterToRecord, GraphModel } from '@kubun/protocol';
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { printSchema } from 'graphql';
|
|
5
|
+
import { readJSON, writeFile } from '../fs.js';
|
|
6
|
+
import { renderNotice, withSpinner } from '../ui.js';
|
|
7
|
+
function createSchemaCommand() {
|
|
8
|
+
const cmd = new Command('schema').description('Create a GraphQL schema from clusters of document models').requiredOption('-c, --cluster <path...>', 'path of the JSON file of the cluster (repeatable)').option('-o, --output <file>', 'output file for the GraphQL schema');
|
|
9
|
+
cmd.action(async (opts)=>{
|
|
10
|
+
const schema = await withSpinner('Loading clusters...', async ()=>{
|
|
11
|
+
const clusterModels = await Promise.all(opts.cluster.map((path)=>readJSON(path)));
|
|
12
|
+
const clusters = {};
|
|
13
|
+
for (const cluster of clusterModels){
|
|
14
|
+
Object.assign(clusters, clusterToRecord(cluster));
|
|
15
|
+
}
|
|
16
|
+
const model = GraphModel.fromClusters({
|
|
17
|
+
clusters
|
|
18
|
+
});
|
|
19
|
+
return printSchema(createSchema(model));
|
|
20
|
+
});
|
|
21
|
+
if (opts.output == null) {
|
|
22
|
+
renderNotice('success', 'GraphQL schema generated');
|
|
23
|
+
console.log(schema);
|
|
24
|
+
} else {
|
|
25
|
+
await writeFile(opts.output, schema);
|
|
26
|
+
renderNotice('success', `GraphQL schema written to ${opts.output}`);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return cmd;
|
|
30
|
+
}
|
|
31
|
+
export function createGraphQLCommand() {
|
|
32
|
+
return new Command('graphql').description('GraphQL commands').addCommand(createSchemaCommand());
|
|
33
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createConfig } from '@kubun/mcp';
|
|
2
|
+
import { serveProcess } from '@mokei/context-server';
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { getSigner } from '../account.js';
|
|
5
|
+
import { withPrivateKey } from '../options.js';
|
|
6
|
+
export function createMCPCommand() {
|
|
7
|
+
const cmd = new Command('mcp').description('Start an MCP server for Kubun').option('-c, --connect <url>', 'URL of an existing Kubun HTTP server to connect to').option('-d, --db <path>', 'SQLite database path or PostgreSQL URL');
|
|
8
|
+
withPrivateKey(cmd);
|
|
9
|
+
cmd.action(async (opts)=>{
|
|
10
|
+
if (opts.connect != null && opts.db != null) {
|
|
11
|
+
throw new Error('--connect and --db are mutually exclusive');
|
|
12
|
+
}
|
|
13
|
+
const config = await createConfig({
|
|
14
|
+
connect: opts.connect,
|
|
15
|
+
database: opts.db,
|
|
16
|
+
identity: opts.privateKey ? getSigner(opts.privateKey) : undefined
|
|
17
|
+
});
|
|
18
|
+
serveProcess(config);
|
|
19
|
+
});
|
|
20
|
+
return cmd;
|
|
21
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ClusterBuilder } from '@kubun/protocol';
|
|
2
|
+
import { Command, Option } from 'commander';
|
|
3
|
+
import { writeJSON } from '../fs.js';
|
|
4
|
+
import { renderNotice } from '../ui.js';
|
|
5
|
+
function parseJSON(label, value) {
|
|
6
|
+
try {
|
|
7
|
+
return JSON.parse(value);
|
|
8
|
+
} catch {
|
|
9
|
+
throw new Error(`${label} is not valid JSON: ${value}`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function createClusterCommand() {
|
|
13
|
+
const cmd = new Command('cluster').description('Create a documents cluster model').requiredOption('-m, --model <json...>', 'document model as JSON string (repeatable)').option('-o, --output <file>', 'output file for the cluster');
|
|
14
|
+
cmd.action(async (opts)=>{
|
|
15
|
+
const builder = new ClusterBuilder();
|
|
16
|
+
builder.addAll(opts.model.map((model)=>parseJSON('--model', model)));
|
|
17
|
+
const cluster = builder.build();
|
|
18
|
+
if (opts.output == null) {
|
|
19
|
+
renderNotice('success', 'Cluster model created');
|
|
20
|
+
console.log(JSON.stringify(cluster));
|
|
21
|
+
} else {
|
|
22
|
+
await writeJSON(opts.output, cluster);
|
|
23
|
+
renderNotice('success', `Cluster model written to ${opts.output}`);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return cmd;
|
|
27
|
+
}
|
|
28
|
+
function createCreateCommand() {
|
|
29
|
+
const cmd = new Command('create').description('Create a document model').argument('<name>', 'document model name').argument('<schema>', 'document schema as JSON string').addOption(new Option('-b, --behavior <behavior>', 'behavior of the document').choices([
|
|
30
|
+
'default',
|
|
31
|
+
'interface',
|
|
32
|
+
'unique'
|
|
33
|
+
]).default('default')).option('-c, --cluster', 'create a cluster model instead of a document model').option('-o, --output <file>', 'output file').option('-u, --unique-field <field...>', 'unique field of the document when behavior is "unique" (repeatable)');
|
|
34
|
+
cmd.action(async (name, schema, opts)=>{
|
|
35
|
+
const model = {
|
|
36
|
+
name,
|
|
37
|
+
behavior: opts.behavior,
|
|
38
|
+
schema: parseJSON('<schema>', schema)
|
|
39
|
+
};
|
|
40
|
+
if (opts.behavior === 'unique') {
|
|
41
|
+
model.uniqueFields = opts.uniqueField;
|
|
42
|
+
}
|
|
43
|
+
const builder = new ClusterBuilder();
|
|
44
|
+
builder.add(model);
|
|
45
|
+
if (opts.cluster) {
|
|
46
|
+
const cluster = builder.build();
|
|
47
|
+
if (opts.output == null) {
|
|
48
|
+
renderNotice('success', 'Cluster model created');
|
|
49
|
+
console.log(JSON.stringify(cluster));
|
|
50
|
+
} else {
|
|
51
|
+
await writeJSON(opts.output, cluster);
|
|
52
|
+
renderNotice('success', `Cluster model written to ${opts.output}`);
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const document = builder.cluster[0];
|
|
57
|
+
if (opts.output == null) {
|
|
58
|
+
renderNotice('success', 'Document model created');
|
|
59
|
+
console.log(JSON.stringify(document));
|
|
60
|
+
} else {
|
|
61
|
+
await writeJSON(opts.output, document);
|
|
62
|
+
renderNotice('success', `Document model written to ${opts.output}`);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
return cmd;
|
|
66
|
+
}
|
|
67
|
+
export function createModelCommand() {
|
|
68
|
+
return new Command('model').description('Model commands').addCommand(createClusterCommand()).addCommand(createCreateCommand());
|
|
69
|
+
}
|