@kubun/mcp 0.1.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/LICENSE.md +57 -0
- package/lib/client.d.ts +20 -0
- package/lib/client.d.ts.map +1 -0
- package/lib/client.js +31 -0
- package/lib/config.d.ts +9 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +45 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +2 -0
- package/lib/prompts/data-model-designer.d.ts +2 -0
- package/lib/prompts/data-model-designer.d.ts.map +1 -0
- package/lib/prompts/data-model-designer.js +354 -0
- package/lib/prompts/index.d.ts +15 -0
- package/lib/prompts/index.d.ts.map +1 -0
- package/lib/prompts/index.js +19 -0
- package/lib/run.d.ts +3 -0
- package/lib/run.d.ts.map +1 -0
- package/lib/run.js +19 -0
- package/lib/tools/cluster.d.ts +6 -0
- package/lib/tools/cluster.d.ts.map +1 -0
- package/lib/tools/cluster.js +71 -0
- package/lib/tools/graph.d.ts +6 -0
- package/lib/tools/graph.d.ts.map +1 -0
- package/lib/tools/graph.js +248 -0
- package/lib/tools/index.d.ts +3 -0
- package/lib/tools/index.d.ts.map +1 -0
- package/lib/tools/index.js +2 -0
- package/package.json +47 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# The Prosperity Public License 3.0.0
|
|
2
|
+
|
|
3
|
+
Contributor: Paul Le Cam
|
|
4
|
+
|
|
5
|
+
Source Code: https://github.com/PaulLeCam/kubun
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
This license allows you to use and share this software for noncommercial purposes for free and to try this software for commercial purposes for thirty days.
|
|
10
|
+
|
|
11
|
+
## Agreement
|
|
12
|
+
|
|
13
|
+
In order to receive this license, you have to agree to its rules. Those rules are both obligations under that agreement and conditions to your license. Don't do anything with this software that triggers a rule you can't or won't follow.
|
|
14
|
+
|
|
15
|
+
## Notices
|
|
16
|
+
|
|
17
|
+
Make sure everyone who gets a copy of any part of this software from you, with or without changes, also gets the text of this license and the contributor and source code lines above.
|
|
18
|
+
|
|
19
|
+
## Commercial Trial
|
|
20
|
+
|
|
21
|
+
Limit your use of this software for commercial purposes to a thirty-day trial period. If you use this software for work, your company gets one trial period for all personnel, not one trial per person.
|
|
22
|
+
|
|
23
|
+
## Contributions Back
|
|
24
|
+
|
|
25
|
+
Developing feedback, changes, or additions that you contribute back to the contributor on the terms of a standardized public software license such as [the Blue Oak Model License 1.0.0](https://blueoakcouncil.org/license/1.0.0), [the Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.html), [the MIT license](https://spdx.org/licenses/MIT.html), or [the two-clause BSD license](https://spdx.org/licenses/BSD-2-Clause.html) doesn't count as use for a commercial purpose.
|
|
26
|
+
|
|
27
|
+
## Personal Uses
|
|
28
|
+
|
|
29
|
+
Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, doesn't count as use for a commercial purpose.
|
|
30
|
+
|
|
31
|
+
## Noncommercial Organizations
|
|
32
|
+
|
|
33
|
+
Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution doesn't count as use for a commercial purpose regardless of the source of funding or obligations resulting from the funding.
|
|
34
|
+
|
|
35
|
+
## Defense
|
|
36
|
+
|
|
37
|
+
Don't make any legal claim against anyone accusing this software, with or without changes, alone or with other technology, of infringing any patent.
|
|
38
|
+
|
|
39
|
+
## Copyright
|
|
40
|
+
|
|
41
|
+
The contributor licenses you to do everything with this software that would otherwise infringe their copyright in it.
|
|
42
|
+
|
|
43
|
+
## Patent
|
|
44
|
+
|
|
45
|
+
The contributor licenses you to do everything with this software that would otherwise infringe any patents they can license or become able to license.
|
|
46
|
+
|
|
47
|
+
## Reliability
|
|
48
|
+
|
|
49
|
+
The contributor can't revoke this license.
|
|
50
|
+
|
|
51
|
+
## Excuse
|
|
52
|
+
|
|
53
|
+
You're excused for unknowingly breaking [Notices](#notices) if you take all practical steps to comply within thirty days of learning you broke the rule.
|
|
54
|
+
|
|
55
|
+
## No Liability
|
|
56
|
+
|
|
57
|
+
***As far as the law allows, this software comes as is, without any warranty or condition, and the contributor won't be liable to anyone for any damages related to this software or this license, under any kind of legal claim.***
|
package/lib/client.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type TokenSigner } from '@enkaku/token';
|
|
2
|
+
import type { KubunClient } from '@kubun/client';
|
|
3
|
+
export type ClientConfig = {
|
|
4
|
+
type: 'memory';
|
|
5
|
+
} | {
|
|
6
|
+
type: 'sqlite';
|
|
7
|
+
path: string;
|
|
8
|
+
} | {
|
|
9
|
+
type: 'postgres';
|
|
10
|
+
url: string;
|
|
11
|
+
} | {
|
|
12
|
+
type: 'http';
|
|
13
|
+
url: string;
|
|
14
|
+
serverID?: string;
|
|
15
|
+
};
|
|
16
|
+
export type ClientParams = ClientConfig & {
|
|
17
|
+
signer?: TokenSigner;
|
|
18
|
+
};
|
|
19
|
+
export declare function createClient(params: ClientParams): KubunClient;
|
|
20
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,eAAe,CAAA;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAOhD,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AACpD,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,CAAA;AAElE,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW,CAkB9D"}
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { randomTokenSigner } from '@enkaku/token';
|
|
2
|
+
import { KubunDB } from '@kubun/db';
|
|
3
|
+
import { PostgresAdapter } from '@kubun/db-postgres';
|
|
4
|
+
import { SQLiteAdapter } from '@kubun/db-sqlite';
|
|
5
|
+
import { HTTPClient } from '@kubun/http-client';
|
|
6
|
+
import { KubunServer } from '@kubun/server';
|
|
7
|
+
export function createClient(params) {
|
|
8
|
+
const signer = params.signer ?? randomTokenSigner();
|
|
9
|
+
if (params.type === 'http') {
|
|
10
|
+
return new HTTPClient({
|
|
11
|
+
url: params.url,
|
|
12
|
+
signer,
|
|
13
|
+
serverID: params.serverID
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
const adapter = params.type === 'postgres' ? new PostgresAdapter({
|
|
17
|
+
url: params.url
|
|
18
|
+
}) : new SQLiteAdapter({
|
|
19
|
+
database: params.type === 'sqlite' ? params.path : ':memory:'
|
|
20
|
+
});
|
|
21
|
+
const db = new KubunDB({
|
|
22
|
+
adapter
|
|
23
|
+
});
|
|
24
|
+
const server = new KubunServer({
|
|
25
|
+
db,
|
|
26
|
+
id: signer.id
|
|
27
|
+
});
|
|
28
|
+
return server.createClient({
|
|
29
|
+
signer
|
|
30
|
+
});
|
|
31
|
+
}
|
package/lib/config.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { TokenSigner } from '@enkaku/token';
|
|
2
|
+
import type { ServerConfig } from '@mokei/context-server';
|
|
3
|
+
export type MCPConfig = {
|
|
4
|
+
connect?: string;
|
|
5
|
+
database?: string;
|
|
6
|
+
signer?: TokenSigner;
|
|
7
|
+
};
|
|
8
|
+
export declare function createConfig(config?: MCPConfig): ServerConfig;
|
|
9
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAOzD,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAeD,wBAAgB,YAAY,CAAC,MAAM,GAAE,SAAc,GAAG,YAAY,CAcjE"}
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { createClient } from './client.js';
|
|
2
|
+
import { prompts } from './prompts/index.js';
|
|
3
|
+
import { createClusterTools } from './tools/cluster.js';
|
|
4
|
+
import { createGraphTools } from './tools/graph.js';
|
|
5
|
+
function parseConfig(config) {
|
|
6
|
+
if (config.connect != null) {
|
|
7
|
+
return {
|
|
8
|
+
type: 'http',
|
|
9
|
+
url: config.connect,
|
|
10
|
+
signer: config.signer
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
if (config.database != null) {
|
|
14
|
+
if (config.database.startsWith('postgres://')) {
|
|
15
|
+
return {
|
|
16
|
+
type: 'postgres',
|
|
17
|
+
url: config.database,
|
|
18
|
+
signer: config.signer
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
type: 'sqlite',
|
|
23
|
+
path: config.database,
|
|
24
|
+
signer: config.signer
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
type: 'memory',
|
|
29
|
+
signer: config.signer
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function createConfig(config = {}) {
|
|
33
|
+
const client = createClient(parseConfig(config));
|
|
34
|
+
const clusterTools = createClusterTools(client);
|
|
35
|
+
const graphTools = createGraphTools(client);
|
|
36
|
+
return {
|
|
37
|
+
name: 'kubun',
|
|
38
|
+
version: '0.1.0',
|
|
39
|
+
prompts,
|
|
40
|
+
tools: {
|
|
41
|
+
...clusterTools,
|
|
42
|
+
...graphTools
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC7D,OAAO,EAAE,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAA"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const KUBUN_PROMPT_INSTRUCTIONS = "# Kubun Protocol Data Model Generator\n\nYou are an expert at creating data models following the Kubun protocol specification. Your task is to generate valid JSON schemas for data models based on user requirements.\n\n## Core Principles\n\n**Automatic Server Fields (DO NOT INCLUDE):**\n- `id` - Server generates globally unique DocID automatically\n- `createdAt` - Server generates timestamp automatically\n- `updatedAt` - Server generates timestamp automatically\n- Owner relations - Server handles user/owner associations automatically\n\n**Model Behaviors:**\n- `default` - Standard concrete models for real entities\n- `interface` - Abstract contracts that other models implement\n- `unique` - Models with uniqueness constraints on specific fields\n\n---\n\n## Built-in Interfaces\n\n### Node (Implicit Base Interface)\n\n**All models implicitly implement the `Node` interface.** This is the base interface for all documents in the system.\n\n- **DO NOT** create a `Node` interface model\n- **DO NOT** include `\"Node\"` in any model's `interfaces` array\n- **DO** use `null` as a `relationModel` value when a field can reference any document\n\n**Example - Field that can link to any document:**\n```json\n{\n \"fieldsMeta\": {\n \"linkedItemId\": {\n \"relationModel\": null\n }\n }\n}\n```\n\n---\n\n## Schema Structure\n\nEach model must include:\n```json\n{\n \"name\": \"PascalCaseModelName\",\n \"version\": \"1.0\",\n \"interfaces\": [],\n \"schema\": { /* JSON Schema definition */ },\n \"fieldsMeta\": { /* DocID field metadata */ },\n \"behavior\": \"default|interface|unique\",\n \"uniqueFields\": [\"field1\", \"field2\"]\n}\n```\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `name` | Yes | PascalCase model name |\n| `version` | Yes | Schema version (use `\"1.0\"`) |\n| `interfaces` | Yes | Array of interface references (see Interface References) |\n| `schema` | Yes | JSON Schema definition |\n| `fieldsMeta` | Yes | DocID field relationship metadata (can be empty `{}`) |\n| `behavior` | Yes | One of: `default`, `interface`, `unique` |\n| `uniqueFields` | Only for `unique` behavior | Array of field names that must be unique |\n\n---\n\n## Interface References\n\nThe `interfaces` array specifies which interfaces a model implements. Reference format depends on where the interface is defined:\n\n| Interface Location | Reference Format | Example |\n|--------------------|------------------|---------|\n| Existing in database | Model ID | `\"k1a2b3c4d5e6f7g8h9\"` |\n| In same cluster being generated | Array index | `\"#0\"` |\n\n**Rules:**\n- All models implicitly implement `Node` - never include it in the interfaces array\n- When generating a new cluster, define interface models FIRST (at lower indices) so concrete models can reference them\n- Use `#N` format where N is the zero-based array index of the interface model in the cluster\n\n**Example - Model implementing cluster interfaces:**\n```json\n{\n \"name\": \"Task\",\n \"interfaces\": [\"#0\", \"#2\"],\n ...\n}\n```\n\n---\n\n## Relations Between Models\n\nUse `fieldsMeta` to define DocID relationships:\n\n| Target Location | Reference Format | Description |\n|-----------------|------------------|-------------|\n| Any document (polymorphic to Node) | `null` | Field can link to any item in the system |\n| Existing in database | Model ID | `\"k1a2b3c4d5e6f7g8h9\"` |\n| In same cluster being generated | Array index | `\"#2\"` |\n\n**Example:**\n```json\n{\n \"fieldsMeta\": {\n \"taskListId\": {\n \"relationModel\": \"#5\"\n },\n \"categoryId\": {\n \"relationModel\": \"k1a2b3c4d5e6f7g8h9\"\n },\n \"linkedItemId\": {\n \"relationModel\": null\n }\n }\n}\n```\n\n---\n\n## Naming Conventions\n\n| Element | Convention | Example |\n|---------|------------|---------|\n| Model names | PascalCase starting with uppercase | `UserProfile`, `BlogPost` |\n| Field names | camelCase starting with lowercase | `firstName`, `createdDate` |\n| Type titles | PascalCase | `EmailAddress`, `PhoneNumber` |\n| Enum values | UPPERCASE_UNDERSCORE | `ACTIVE`, `PENDING_APPROVAL` |\n\n---\n\n## Available Data Types\n\n### Predefined Types (Use When Applicable)\n\nWhen a predefined type matches your use case, copy its exact definition into the `definitions` section and reference it. Never create custom types that duplicate predefined functionality.\n\n| Type | Purpose |\n|------|---------|\n| `AttachmentID` | File/media references |\n| `BigInt` | Large integers |\n| `DateTime` | ISO 8601 date-time |\n| `DID` | Decentralized identifiers |\n| `DocID` | Document references |\n| `Duration` | ISO 8601 duration |\n| `JSONObject` | Flexible JSON data |\n| `Latitude` / `Longitude` | Geographic coordinates |\n| `LocalDate` | Date without time (YYYY-MM-DD) |\n| `LocalDateTime` | Local date-time |\n| `LocalTime` | Time without date |\n| `Locale` | Language/region codes |\n| `TimeZone` | Timezone identifiers |\n| `URL` | Web addresses |\n| `UtcOffset` | UTC time offsets |\n\n**Usage Pattern:**\n```json\n{\n \"properties\": {\n \"scheduledAt\": { \"$ref\": \"#/definitions/DateTime\" }\n },\n \"definitions\": {\n \"DateTime\": { \"type\": \"string\", \"format\": \"date-time\", \"title\": \"DateTime\" }\n }\n}\n```\n\n### Primitive Types\n\n| Type | Variants |\n|------|----------|\n| `boolean` | True/false values |\n| `integer` | Whole numbers (with optional min/max) |\n| `number` | Decimal numbers (with optional min/max) |\n| `string` | Plain text, `const`, `pattern`, `enum`, `format` |\n\n### Complex Types\n\n| Type | Description |\n|------|-------------|\n| `array` | Collections of items |\n| `object` | Structured data with properties |\n\n---\n\n## Example Patterns\n\n### Interface Model\n```json\n{\n \"name\": \"Completable\",\n \"version\": \"1.0\",\n \"interfaces\": [],\n \"behavior\": \"interface\",\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"completed\": { \"$ref\": \"#/definitions/Completed\" },\n \"completedAt\": { \"$ref\": \"#/definitions/DateTime\" }\n },\n \"required\": [\"completed\"],\n \"additionalProperties\": true,\n \"definitions\": {\n \"Completed\": { \"type\": \"boolean\", \"title\": \"Completed\", \"default\": false },\n \"DateTime\": { \"type\": \"string\", \"format\": \"date-time\", \"title\": \"DateTime\" }\n }\n },\n \"fieldsMeta\": {}\n}\n```\n\n**Note:** Interface schemas use `\"additionalProperties\": true` to allow implementing models to add fields.\n\n### Concrete Model (Implementing Interfaces)\n```json\n{\n \"name\": \"Task\",\n \"version\": \"1.0\",\n \"interfaces\": [\"#0\", \"#1\"],\n \"behavior\": \"default\",\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"title\": { \"$ref\": \"#/definitions/Title\" },\n \"description\": { \"$ref\": \"#/definitions/Description\" },\n \"completed\": { \"$ref\": \"#/definitions/Completed\" },\n \"completedAt\": { \"$ref\": \"#/definitions/DateTime\" },\n \"priority\": { \"$ref\": \"#/definitions/Priority\" },\n \"taskListId\": { \"$ref\": \"#/definitions/DocID\" }\n },\n \"required\": [\"title\", \"completed\", \"priority\"],\n \"additionalProperties\": false,\n \"definitions\": {\n \"Title\": { \"type\": \"string\", \"title\": \"Title\", \"minLength\": 1, \"maxLength\": 200 },\n \"Description\": { \"type\": \"string\", \"title\": \"Description\", \"maxLength\": 5000 },\n \"Completed\": { \"type\": \"boolean\", \"title\": \"Completed\", \"default\": false },\n \"DateTime\": { \"type\": \"string\", \"format\": \"date-time\", \"title\": \"DateTime\" },\n \"Priority\": {\n \"type\": \"string\",\n \"title\": \"Priority\",\n \"enum\": [\"LOW\", \"MEDIUM\", \"HIGH\", \"URGENT\"],\n \"default\": \"MEDIUM\"\n },\n \"DocID\": { \"type\": \"string\", \"title\": \"DocID\", \"pattern\": \"^k[0-9a-z]{10,120}$\" }\n }\n },\n \"fieldsMeta\": {\n \"taskListId\": { \"relationModel\": \"#5\" }\n }\n}\n```\n\n**Note:** Concrete schemas use `\"additionalProperties\": false` to enforce strict structure.\n\n### Unique Constraint Model\n```json\n{\n \"name\": \"UserProfile\",\n \"version\": \"1.0\",\n \"interfaces\": [],\n \"behavior\": \"unique\",\n \"uniqueFields\": [\"email\"],\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"email\": { \"$ref\": \"#/definitions/Email\" },\n \"displayName\": { \"$ref\": \"#/definitions/DisplayName\" }\n },\n \"required\": [\"email\"],\n \"additionalProperties\": false,\n \"definitions\": {\n \"Email\": { \"type\": \"string\", \"format\": \"email\", \"title\": \"Email\" },\n \"DisplayName\": { \"type\": \"string\", \"title\": \"DisplayName\", \"maxLength\": 100 }\n }\n },\n \"fieldsMeta\": {}\n}\n```\n\n### Model with Any-Document Reference\n```json\n{\n \"name\": \"Reminder\",\n \"version\": \"1.0\",\n \"interfaces\": [\"#0\"],\n \"behavior\": \"default\",\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"title\": { \"$ref\": \"#/definitions/Title\" },\n \"linkedItemId\": { \"$ref\": \"#/definitions/DocID\" },\n \"remindAt\": { \"$ref\": \"#/definitions/DateTime\" }\n },\n \"required\": [\"title\", \"remindAt\"],\n \"additionalProperties\": false,\n \"definitions\": {\n \"Title\": { \"type\": \"string\", \"title\": \"Title\", \"minLength\": 1, \"maxLength\": 200 },\n \"DocID\": { \"type\": \"string\", \"title\": \"DocID\", \"pattern\": \"^k[0-9a-z]{10,120}$\" },\n \"DateTime\": { \"type\": \"string\", \"format\": \"date-time\", \"title\": \"DateTime\" }\n }\n },\n \"fieldsMeta\": {\n \"linkedItemId\": { \"relationModel\": null }\n }\n}\n```\n\n---\n\n## Generation Guidelines\n\n1. **Never create a Node interface** - it's built-in and implicit\n2. **Never include \"Node\" in interfaces array** - all models inherit it automatically\n3. **Use `null` for any-document relations** - this represents the Node interface\n4. **Define interfaces first in clusters** - place them at lower indices (0, 1, 2...) so concrete models can reference them with `#N`\n5. **Ask clarifying questions** about requirements if needed\n6. **Choose appropriate behavior** (`default` / `interface` / `unique`)\n7. **Use predefined types** when they match the use case\n8. **Define clear field relationships** using `fieldsMeta`\n9. **Include reasonable validation** (lengths, patterns, ranges)\n10. **Follow naming conventions** strictly\n11. **Make required fields explicit**\n12. **Concrete models must include all interface fields** - copy the field definitions from implemented interfaces\n\n---\n\n## Cluster Organization\n\nWhen generating a model cluster, organize models in this order:\n\n1. **Interface models** (indices 0, 1, 2, ...) - Define abstract contracts first\n2. **Shared/referenced models** (e.g., Tag) - Models referenced by many others\n3. **Domain models** - Concrete models grouped by domain\n\n**Example cluster structure:**\n```\n#0 Schedulable (interface)\n#1 Completable (interface)\n#2 Prioritizable (interface)\n#3 Taggable (interface)\n#4 Tag (referenced by Taggable)\n#5 Event (implements #0, #3)\n#6 Task (implements #1, #2, #3)\n#7 Project (implements #1)\n```\n\n---\n\n## Response Format\n\nAlways generate models as a JSON array, even when a single model is needed. Validate that your output follows the specification exactly.";
|
|
2
|
+
//# sourceMappingURL=data-model-designer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-model-designer.d.ts","sourceRoot":"","sources":["../../src/prompts/data-model-designer.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,yBAAyB,oyWAiWmG,CAAA"}
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
export const KUBUN_PROMPT_INSTRUCTIONS = `# Kubun Protocol Data Model Generator
|
|
2
|
+
|
|
3
|
+
You are an expert at creating data models following the Kubun protocol specification. Your task is to generate valid JSON schemas for data models based on user requirements.
|
|
4
|
+
|
|
5
|
+
## Core Principles
|
|
6
|
+
|
|
7
|
+
**Automatic Server Fields (DO NOT INCLUDE):**
|
|
8
|
+
- \`id\` - Server generates globally unique DocID automatically
|
|
9
|
+
- \`createdAt\` - Server generates timestamp automatically
|
|
10
|
+
- \`updatedAt\` - Server generates timestamp automatically
|
|
11
|
+
- Owner relations - Server handles user/owner associations automatically
|
|
12
|
+
|
|
13
|
+
**Model Behaviors:**
|
|
14
|
+
- \`default\` - Standard concrete models for real entities
|
|
15
|
+
- \`interface\` - Abstract contracts that other models implement
|
|
16
|
+
- \`unique\` - Models with uniqueness constraints on specific fields
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Built-in Interfaces
|
|
21
|
+
|
|
22
|
+
### Node (Implicit Base Interface)
|
|
23
|
+
|
|
24
|
+
**All models implicitly implement the \`Node\` interface.** This is the base interface for all documents in the system.
|
|
25
|
+
|
|
26
|
+
- **DO NOT** create a \`Node\` interface model
|
|
27
|
+
- **DO NOT** include \`"Node"\` in any model's \`interfaces\` array
|
|
28
|
+
- **DO** use \`null\` as a \`relationModel\` value when a field can reference any document
|
|
29
|
+
|
|
30
|
+
**Example - Field that can link to any document:**
|
|
31
|
+
\`\`\`json
|
|
32
|
+
{
|
|
33
|
+
"fieldsMeta": {
|
|
34
|
+
"linkedItemId": {
|
|
35
|
+
"relationModel": null
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
\`\`\`
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Schema Structure
|
|
44
|
+
|
|
45
|
+
Each model must include:
|
|
46
|
+
\`\`\`json
|
|
47
|
+
{
|
|
48
|
+
"name": "PascalCaseModelName",
|
|
49
|
+
"version": "1.0",
|
|
50
|
+
"interfaces": [],
|
|
51
|
+
"schema": { /* JSON Schema definition */ },
|
|
52
|
+
"fieldsMeta": { /* DocID field metadata */ },
|
|
53
|
+
"behavior": "default|interface|unique",
|
|
54
|
+
"uniqueFields": ["field1", "field2"]
|
|
55
|
+
}
|
|
56
|
+
\`\`\`
|
|
57
|
+
|
|
58
|
+
| Field | Required | Description |
|
|
59
|
+
|-------|----------|-------------|
|
|
60
|
+
| \`name\` | Yes | PascalCase model name |
|
|
61
|
+
| \`version\` | Yes | Schema version (use \`"1.0"\`) |
|
|
62
|
+
| \`interfaces\` | Yes | Array of interface references (see Interface References) |
|
|
63
|
+
| \`schema\` | Yes | JSON Schema definition |
|
|
64
|
+
| \`fieldsMeta\` | Yes | DocID field relationship metadata (can be empty \`{}\`) |
|
|
65
|
+
| \`behavior\` | Yes | One of: \`default\`, \`interface\`, \`unique\` |
|
|
66
|
+
| \`uniqueFields\` | Only for \`unique\` behavior | Array of field names that must be unique |
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Interface References
|
|
71
|
+
|
|
72
|
+
The \`interfaces\` array specifies which interfaces a model implements. Reference format depends on where the interface is defined:
|
|
73
|
+
|
|
74
|
+
| Interface Location | Reference Format | Example |
|
|
75
|
+
|--------------------|------------------|---------|
|
|
76
|
+
| Existing in database | Model ID | \`"k1a2b3c4d5e6f7g8h9"\` |
|
|
77
|
+
| In same cluster being generated | Array index | \`"#0"\` |
|
|
78
|
+
|
|
79
|
+
**Rules:**
|
|
80
|
+
- All models implicitly implement \`Node\` - never include it in the interfaces array
|
|
81
|
+
- When generating a new cluster, define interface models FIRST (at lower indices) so concrete models can reference them
|
|
82
|
+
- Use \`#N\` format where N is the zero-based array index of the interface model in the cluster
|
|
83
|
+
|
|
84
|
+
**Example - Model implementing cluster interfaces:**
|
|
85
|
+
\`\`\`json
|
|
86
|
+
{
|
|
87
|
+
"name": "Task",
|
|
88
|
+
"interfaces": ["#0", "#2"],
|
|
89
|
+
...
|
|
90
|
+
}
|
|
91
|
+
\`\`\`
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Relations Between Models
|
|
96
|
+
|
|
97
|
+
Use \`fieldsMeta\` to define DocID relationships:
|
|
98
|
+
|
|
99
|
+
| Target Location | Reference Format | Description |
|
|
100
|
+
|-----------------|------------------|-------------|
|
|
101
|
+
| Any document (polymorphic to Node) | \`null\` | Field can link to any item in the system |
|
|
102
|
+
| Existing in database | Model ID | \`"k1a2b3c4d5e6f7g8h9"\` |
|
|
103
|
+
| In same cluster being generated | Array index | \`"#2"\` |
|
|
104
|
+
|
|
105
|
+
**Example:**
|
|
106
|
+
\`\`\`json
|
|
107
|
+
{
|
|
108
|
+
"fieldsMeta": {
|
|
109
|
+
"taskListId": {
|
|
110
|
+
"relationModel": "#5"
|
|
111
|
+
},
|
|
112
|
+
"categoryId": {
|
|
113
|
+
"relationModel": "k1a2b3c4d5e6f7g8h9"
|
|
114
|
+
},
|
|
115
|
+
"linkedItemId": {
|
|
116
|
+
"relationModel": null
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
\`\`\`
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Naming Conventions
|
|
125
|
+
|
|
126
|
+
| Element | Convention | Example |
|
|
127
|
+
|---------|------------|---------|
|
|
128
|
+
| Model names | PascalCase starting with uppercase | \`UserProfile\`, \`BlogPost\` |
|
|
129
|
+
| Field names | camelCase starting with lowercase | \`firstName\`, \`createdDate\` |
|
|
130
|
+
| Type titles | PascalCase | \`EmailAddress\`, \`PhoneNumber\` |
|
|
131
|
+
| Enum values | UPPERCASE_UNDERSCORE | \`ACTIVE\`, \`PENDING_APPROVAL\` |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Available Data Types
|
|
136
|
+
|
|
137
|
+
### Predefined Types (Use When Applicable)
|
|
138
|
+
|
|
139
|
+
When a predefined type matches your use case, copy its exact definition into the \`definitions\` section and reference it. Never create custom types that duplicate predefined functionality.
|
|
140
|
+
|
|
141
|
+
| Type | Purpose |
|
|
142
|
+
|------|---------|
|
|
143
|
+
| \`AttachmentID\` | File/media references |
|
|
144
|
+
| \`BigInt\` | Large integers |
|
|
145
|
+
| \`DateTime\` | ISO 8601 date-time |
|
|
146
|
+
| \`DID\` | Decentralized identifiers |
|
|
147
|
+
| \`DocID\` | Document references |
|
|
148
|
+
| \`Duration\` | ISO 8601 duration |
|
|
149
|
+
| \`JSONObject\` | Flexible JSON data |
|
|
150
|
+
| \`Latitude\` / \`Longitude\` | Geographic coordinates |
|
|
151
|
+
| \`LocalDate\` | Date without time (YYYY-MM-DD) |
|
|
152
|
+
| \`LocalDateTime\` | Local date-time |
|
|
153
|
+
| \`LocalTime\` | Time without date |
|
|
154
|
+
| \`Locale\` | Language/region codes |
|
|
155
|
+
| \`TimeZone\` | Timezone identifiers |
|
|
156
|
+
| \`URL\` | Web addresses |
|
|
157
|
+
| \`UtcOffset\` | UTC time offsets |
|
|
158
|
+
|
|
159
|
+
**Usage Pattern:**
|
|
160
|
+
\`\`\`json
|
|
161
|
+
{
|
|
162
|
+
"properties": {
|
|
163
|
+
"scheduledAt": { "$ref": "#/definitions/DateTime" }
|
|
164
|
+
},
|
|
165
|
+
"definitions": {
|
|
166
|
+
"DateTime": { "type": "string", "format": "date-time", "title": "DateTime" }
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
\`\`\`
|
|
170
|
+
|
|
171
|
+
### Primitive Types
|
|
172
|
+
|
|
173
|
+
| Type | Variants |
|
|
174
|
+
|------|----------|
|
|
175
|
+
| \`boolean\` | True/false values |
|
|
176
|
+
| \`integer\` | Whole numbers (with optional min/max) |
|
|
177
|
+
| \`number\` | Decimal numbers (with optional min/max) |
|
|
178
|
+
| \`string\` | Plain text, \`const\`, \`pattern\`, \`enum\`, \`format\` |
|
|
179
|
+
|
|
180
|
+
### Complex Types
|
|
181
|
+
|
|
182
|
+
| Type | Description |
|
|
183
|
+
|------|-------------|
|
|
184
|
+
| \`array\` | Collections of items |
|
|
185
|
+
| \`object\` | Structured data with properties |
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Example Patterns
|
|
190
|
+
|
|
191
|
+
### Interface Model
|
|
192
|
+
\`\`\`json
|
|
193
|
+
{
|
|
194
|
+
"name": "Completable",
|
|
195
|
+
"version": "1.0",
|
|
196
|
+
"interfaces": [],
|
|
197
|
+
"behavior": "interface",
|
|
198
|
+
"schema": {
|
|
199
|
+
"type": "object",
|
|
200
|
+
"properties": {
|
|
201
|
+
"completed": { "$ref": "#/definitions/Completed" },
|
|
202
|
+
"completedAt": { "$ref": "#/definitions/DateTime" }
|
|
203
|
+
},
|
|
204
|
+
"required": ["completed"],
|
|
205
|
+
"additionalProperties": true,
|
|
206
|
+
"definitions": {
|
|
207
|
+
"Completed": { "type": "boolean", "title": "Completed", "default": false },
|
|
208
|
+
"DateTime": { "type": "string", "format": "date-time", "title": "DateTime" }
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
"fieldsMeta": {}
|
|
212
|
+
}
|
|
213
|
+
\`\`\`
|
|
214
|
+
|
|
215
|
+
**Note:** Interface schemas use \`"additionalProperties": true\` to allow implementing models to add fields.
|
|
216
|
+
|
|
217
|
+
### Concrete Model (Implementing Interfaces)
|
|
218
|
+
\`\`\`json
|
|
219
|
+
{
|
|
220
|
+
"name": "Task",
|
|
221
|
+
"version": "1.0",
|
|
222
|
+
"interfaces": ["#0", "#1"],
|
|
223
|
+
"behavior": "default",
|
|
224
|
+
"schema": {
|
|
225
|
+
"type": "object",
|
|
226
|
+
"properties": {
|
|
227
|
+
"title": { "$ref": "#/definitions/Title" },
|
|
228
|
+
"description": { "$ref": "#/definitions/Description" },
|
|
229
|
+
"completed": { "$ref": "#/definitions/Completed" },
|
|
230
|
+
"completedAt": { "$ref": "#/definitions/DateTime" },
|
|
231
|
+
"priority": { "$ref": "#/definitions/Priority" },
|
|
232
|
+
"taskListId": { "$ref": "#/definitions/DocID" }
|
|
233
|
+
},
|
|
234
|
+
"required": ["title", "completed", "priority"],
|
|
235
|
+
"additionalProperties": false,
|
|
236
|
+
"definitions": {
|
|
237
|
+
"Title": { "type": "string", "title": "Title", "minLength": 1, "maxLength": 200 },
|
|
238
|
+
"Description": { "type": "string", "title": "Description", "maxLength": 5000 },
|
|
239
|
+
"Completed": { "type": "boolean", "title": "Completed", "default": false },
|
|
240
|
+
"DateTime": { "type": "string", "format": "date-time", "title": "DateTime" },
|
|
241
|
+
"Priority": {
|
|
242
|
+
"type": "string",
|
|
243
|
+
"title": "Priority",
|
|
244
|
+
"enum": ["LOW", "MEDIUM", "HIGH", "URGENT"],
|
|
245
|
+
"default": "MEDIUM"
|
|
246
|
+
},
|
|
247
|
+
"DocID": { "type": "string", "title": "DocID", "pattern": "^k[0-9a-z]{10,120}$" }
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
"fieldsMeta": {
|
|
251
|
+
"taskListId": { "relationModel": "#5" }
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
\`\`\`
|
|
255
|
+
|
|
256
|
+
**Note:** Concrete schemas use \`"additionalProperties": false\` to enforce strict structure.
|
|
257
|
+
|
|
258
|
+
### Unique Constraint Model
|
|
259
|
+
\`\`\`json
|
|
260
|
+
{
|
|
261
|
+
"name": "UserProfile",
|
|
262
|
+
"version": "1.0",
|
|
263
|
+
"interfaces": [],
|
|
264
|
+
"behavior": "unique",
|
|
265
|
+
"uniqueFields": ["email"],
|
|
266
|
+
"schema": {
|
|
267
|
+
"type": "object",
|
|
268
|
+
"properties": {
|
|
269
|
+
"email": { "$ref": "#/definitions/Email" },
|
|
270
|
+
"displayName": { "$ref": "#/definitions/DisplayName" }
|
|
271
|
+
},
|
|
272
|
+
"required": ["email"],
|
|
273
|
+
"additionalProperties": false,
|
|
274
|
+
"definitions": {
|
|
275
|
+
"Email": { "type": "string", "format": "email", "title": "Email" },
|
|
276
|
+
"DisplayName": { "type": "string", "title": "DisplayName", "maxLength": 100 }
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
"fieldsMeta": {}
|
|
280
|
+
}
|
|
281
|
+
\`\`\`
|
|
282
|
+
|
|
283
|
+
### Model with Any-Document Reference
|
|
284
|
+
\`\`\`json
|
|
285
|
+
{
|
|
286
|
+
"name": "Reminder",
|
|
287
|
+
"version": "1.0",
|
|
288
|
+
"interfaces": ["#0"],
|
|
289
|
+
"behavior": "default",
|
|
290
|
+
"schema": {
|
|
291
|
+
"type": "object",
|
|
292
|
+
"properties": {
|
|
293
|
+
"title": { "$ref": "#/definitions/Title" },
|
|
294
|
+
"linkedItemId": { "$ref": "#/definitions/DocID" },
|
|
295
|
+
"remindAt": { "$ref": "#/definitions/DateTime" }
|
|
296
|
+
},
|
|
297
|
+
"required": ["title", "remindAt"],
|
|
298
|
+
"additionalProperties": false,
|
|
299
|
+
"definitions": {
|
|
300
|
+
"Title": { "type": "string", "title": "Title", "minLength": 1, "maxLength": 200 },
|
|
301
|
+
"DocID": { "type": "string", "title": "DocID", "pattern": "^k[0-9a-z]{10,120}$" },
|
|
302
|
+
"DateTime": { "type": "string", "format": "date-time", "title": "DateTime" }
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
"fieldsMeta": {
|
|
306
|
+
"linkedItemId": { "relationModel": null }
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
\`\`\`
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Generation Guidelines
|
|
314
|
+
|
|
315
|
+
1. **Never create a Node interface** - it's built-in and implicit
|
|
316
|
+
2. **Never include "Node" in interfaces array** - all models inherit it automatically
|
|
317
|
+
3. **Use \`null\` for any-document relations** - this represents the Node interface
|
|
318
|
+
4. **Define interfaces first in clusters** - place them at lower indices (0, 1, 2...) so concrete models can reference them with \`#N\`
|
|
319
|
+
5. **Ask clarifying questions** about requirements if needed
|
|
320
|
+
6. **Choose appropriate behavior** (\`default\` / \`interface\` / \`unique\`)
|
|
321
|
+
7. **Use predefined types** when they match the use case
|
|
322
|
+
8. **Define clear field relationships** using \`fieldsMeta\`
|
|
323
|
+
9. **Include reasonable validation** (lengths, patterns, ranges)
|
|
324
|
+
10. **Follow naming conventions** strictly
|
|
325
|
+
11. **Make required fields explicit**
|
|
326
|
+
12. **Concrete models must include all interface fields** - copy the field definitions from implemented interfaces
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Cluster Organization
|
|
331
|
+
|
|
332
|
+
When generating a model cluster, organize models in this order:
|
|
333
|
+
|
|
334
|
+
1. **Interface models** (indices 0, 1, 2, ...) - Define abstract contracts first
|
|
335
|
+
2. **Shared/referenced models** (e.g., Tag) - Models referenced by many others
|
|
336
|
+
3. **Domain models** - Concrete models grouped by domain
|
|
337
|
+
|
|
338
|
+
**Example cluster structure:**
|
|
339
|
+
\`\`\`
|
|
340
|
+
#0 Schedulable (interface)
|
|
341
|
+
#1 Completable (interface)
|
|
342
|
+
#2 Prioritizable (interface)
|
|
343
|
+
#3 Taggable (interface)
|
|
344
|
+
#4 Tag (referenced by Taggable)
|
|
345
|
+
#5 Event (implements #0, #3)
|
|
346
|
+
#6 Task (implements #1, #2, #3)
|
|
347
|
+
#7 Project (implements #1)
|
|
348
|
+
\`\`\`
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Response Format
|
|
353
|
+
|
|
354
|
+
Always generate models as a JSON array, even when a single model is needed. Validate that your output follows the specification exactly.`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO;;;;;;;;;;;;;CAenB,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { KUBUN_PROMPT_INSTRUCTIONS } from './data-model-designer.js';
|
|
2
|
+
export const prompts = {
|
|
3
|
+
'data-model-designer': {
|
|
4
|
+
description: 'Instructions to help design a data model following the Kubun protocol specification',
|
|
5
|
+
handler: ()=>{
|
|
6
|
+
return {
|
|
7
|
+
messages: [
|
|
8
|
+
{
|
|
9
|
+
role: 'user',
|
|
10
|
+
content: {
|
|
11
|
+
type: 'text',
|
|
12
|
+
text: KUBUN_PROMPT_INSTRUCTIONS
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
};
|
package/lib/run.d.ts
ADDED
package/lib/run.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":""}
|
package/lib/run.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from 'node:util';
|
|
3
|
+
import { serveProcess } from '@mokei/context-server';
|
|
4
|
+
import { createConfig } from './config.js';
|
|
5
|
+
const args = parseArgs({
|
|
6
|
+
options: {
|
|
7
|
+
connect: {
|
|
8
|
+
type: 'string'
|
|
9
|
+
},
|
|
10
|
+
db: {
|
|
11
|
+
type: 'string'
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
const config = createConfig({
|
|
16
|
+
connect: args.values.connect,
|
|
17
|
+
database: args.values.db
|
|
18
|
+
});
|
|
19
|
+
serveProcess(config);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { KubunClient } from '@kubun/client';
|
|
2
|
+
import { createTool } from '@mokei/context-server';
|
|
3
|
+
type ToolDefinition = ReturnType<typeof createTool>;
|
|
4
|
+
export declare function createClusterTools(client: KubunClient): Record<string, ToolDefinition>;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=cluster.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster.d.ts","sourceRoot":"","sources":["../../src/tools/cluster.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAEhD,OAAO,EAAE,UAAU,EAAe,MAAM,uBAAuB,CAAA;AAE/D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAA;AAEnD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA8CtF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ClusterBuilder, clusterModel } from '@kubun/protocol';
|
|
2
|
+
import { createTool } from '@mokei/context-server';
|
|
3
|
+
export function createClusterTools(client) {
|
|
4
|
+
const create_cluster = createTool('Create a new cluster from model definitions', {
|
|
5
|
+
type: 'object',
|
|
6
|
+
properties: {
|
|
7
|
+
models: {
|
|
8
|
+
type: 'array',
|
|
9
|
+
items: {
|
|
10
|
+
type: 'object'
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
required: [
|
|
15
|
+
'models'
|
|
16
|
+
],
|
|
17
|
+
additionalProperties: false
|
|
18
|
+
}, async (ctx)=>{
|
|
19
|
+
const builder = new ClusterBuilder();
|
|
20
|
+
builder.addAll(ctx.arguments.models);
|
|
21
|
+
const cluster = builder.build();
|
|
22
|
+
return {
|
|
23
|
+
content: [
|
|
24
|
+
{
|
|
25
|
+
type: 'text',
|
|
26
|
+
text: 'Cluster created'
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
structuredContent: {
|
|
30
|
+
cluster
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
const deploy_clusters = createTool('Deploy clusters to the Kubun backend', {
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
clusters: {
|
|
38
|
+
type: 'array',
|
|
39
|
+
items: clusterModel
|
|
40
|
+
},
|
|
41
|
+
id: {
|
|
42
|
+
type: 'string'
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
required: [
|
|
46
|
+
'clusters'
|
|
47
|
+
],
|
|
48
|
+
additionalProperties: false
|
|
49
|
+
}, async (ctx)=>{
|
|
50
|
+
const result = await client.deployGraph({
|
|
51
|
+
id: ctx.arguments.id,
|
|
52
|
+
clusters: ctx.arguments.clusters
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
content: [
|
|
56
|
+
{
|
|
57
|
+
type: 'text',
|
|
58
|
+
text: `Clusters deployed to graph "${result.id}"`
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
structuredContent: {
|
|
62
|
+
id: result.id,
|
|
63
|
+
models: result.models
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
create_cluster,
|
|
69
|
+
deploy_clusters
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { KubunClient } from '@kubun/client';
|
|
2
|
+
import { createTool } from '@mokei/context-server';
|
|
3
|
+
type ToolDefinition = ReturnType<typeof createTool>;
|
|
4
|
+
export declare function createGraphTools(client: KubunClient): Record<string, ToolDefinition>;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/tools/graph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAKhD,OAAO,EAAE,UAAU,EAAe,MAAM,uBAAuB,CAAA;AAG/D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAA;AA2BnD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAuKpF"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { createSchema } from '@kubun/graphql';
|
|
2
|
+
import { createTool } from '@mokei/context-server';
|
|
3
|
+
import { printSchema } from 'graphql';
|
|
4
|
+
function getModelsInfo(result) {
|
|
5
|
+
if (result.models == null) {
|
|
6
|
+
return {};
|
|
7
|
+
}
|
|
8
|
+
const aliases = result.aliases ?? {};
|
|
9
|
+
return Object.entries(result.models).reduce((acc, [id, model])=>{
|
|
10
|
+
const alias = aliases[id] ?? model.name;
|
|
11
|
+
acc[alias] = {
|
|
12
|
+
id,
|
|
13
|
+
behavior: model.behavior,
|
|
14
|
+
interfaces: model.interfaces,
|
|
15
|
+
fields: Object.keys(model.schema.properties)
|
|
16
|
+
};
|
|
17
|
+
return acc;
|
|
18
|
+
}, {});
|
|
19
|
+
}
|
|
20
|
+
export function createGraphTools(client) {
|
|
21
|
+
const graph_list = createTool('List all available graphs', {}, async ()=>{
|
|
22
|
+
const result = await client.listGraphs();
|
|
23
|
+
const graphs = result.graphs.map((graph)=>`${graph.name} (${graph.id})`).join(', ');
|
|
24
|
+
return {
|
|
25
|
+
content: [
|
|
26
|
+
{
|
|
27
|
+
type: 'text',
|
|
28
|
+
text: graphs === '' ? 'No graphs available' : `Available graphs: ${graphs}`
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
structuredContent: {
|
|
32
|
+
graphs: result.graphs
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
const graph_info = createTool('Get information about a specific graph', {
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {
|
|
39
|
+
id: {
|
|
40
|
+
type: 'string'
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
required: [
|
|
44
|
+
'id'
|
|
45
|
+
],
|
|
46
|
+
additionalProperties: false
|
|
47
|
+
}, async (ctx)=>{
|
|
48
|
+
try {
|
|
49
|
+
const result = await client.loadGraph({
|
|
50
|
+
id: ctx.arguments.id
|
|
51
|
+
});
|
|
52
|
+
if (result.models == null) {
|
|
53
|
+
throw new Error(`Models not found for graph: ${ctx.arguments.id}`);
|
|
54
|
+
}
|
|
55
|
+
const info = getModelsInfo(result);
|
|
56
|
+
return {
|
|
57
|
+
content: [
|
|
58
|
+
{
|
|
59
|
+
type: 'text',
|
|
60
|
+
text: JSON.stringify(info)
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
structuredContent: info
|
|
64
|
+
};
|
|
65
|
+
} catch (error) {
|
|
66
|
+
return {
|
|
67
|
+
isError: true,
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: 'text',
|
|
71
|
+
text: `Failed to get GraphQL schema: ${error instanceof Error ? error.message : String(error)}`
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
const graph_schema = createTool('Get the GraphQL schema for the given graph ID', {
|
|
78
|
+
type: 'object',
|
|
79
|
+
properties: {
|
|
80
|
+
id: {
|
|
81
|
+
type: 'string'
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
required: [
|
|
85
|
+
'id'
|
|
86
|
+
],
|
|
87
|
+
additionalProperties: false
|
|
88
|
+
}, async (ctx)=>{
|
|
89
|
+
try {
|
|
90
|
+
const result = await client.loadGraph({
|
|
91
|
+
id: ctx.arguments.id
|
|
92
|
+
});
|
|
93
|
+
if (result.models == null) {
|
|
94
|
+
throw new Error(`Models not found for graph: ${ctx.arguments.id}`);
|
|
95
|
+
}
|
|
96
|
+
const schema = createSchema(result.models, result.aliases);
|
|
97
|
+
return {
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: 'text',
|
|
101
|
+
text: printSchema(schema)
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
};
|
|
105
|
+
} catch (error) {
|
|
106
|
+
return {
|
|
107
|
+
isError: true,
|
|
108
|
+
content: [
|
|
109
|
+
{
|
|
110
|
+
type: 'text',
|
|
111
|
+
text: `Failed to get GraphQL schema: ${error instanceof Error ? error.message : String(error)}`
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
const graph_query = createTool('Execute a GraphQL query on the given graph ID', {
|
|
118
|
+
type: 'object',
|
|
119
|
+
properties: {
|
|
120
|
+
id: {
|
|
121
|
+
type: 'string'
|
|
122
|
+
},
|
|
123
|
+
query: {
|
|
124
|
+
type: 'string'
|
|
125
|
+
},
|
|
126
|
+
variables: {
|
|
127
|
+
type: 'object'
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
required: [
|
|
131
|
+
'id',
|
|
132
|
+
'query'
|
|
133
|
+
],
|
|
134
|
+
additionalProperties: false
|
|
135
|
+
}, async (ctx)=>{
|
|
136
|
+
try {
|
|
137
|
+
const result = await client.queryGraph({
|
|
138
|
+
id: ctx.arguments.id,
|
|
139
|
+
text: ctx.arguments.query,
|
|
140
|
+
variables: ctx.arguments.variables ?? {}
|
|
141
|
+
});
|
|
142
|
+
if (result.errors != null && result.errors.length > 0) {
|
|
143
|
+
return {
|
|
144
|
+
isError: true,
|
|
145
|
+
content: [
|
|
146
|
+
{
|
|
147
|
+
type: 'text',
|
|
148
|
+
text: result.errors.map((e)=>e.toString()).join(', ')
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
structuredContent: {
|
|
152
|
+
errors: result.errors
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
content: [
|
|
158
|
+
{
|
|
159
|
+
type: 'text',
|
|
160
|
+
text: JSON.stringify(result.data)
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
structuredContent: {
|
|
164
|
+
data: result.data
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
} catch (error) {
|
|
168
|
+
return {
|
|
169
|
+
isError: true,
|
|
170
|
+
content: [
|
|
171
|
+
{
|
|
172
|
+
type: 'text',
|
|
173
|
+
text: `Failed to execute GraphQL query: ${error instanceof Error ? error.message : String(error)}`
|
|
174
|
+
}
|
|
175
|
+
]
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
const graph_mutate = createTool('Execute a GraphQL mutation on the given graph ID', {
|
|
180
|
+
type: 'object',
|
|
181
|
+
properties: {
|
|
182
|
+
id: {
|
|
183
|
+
type: 'string'
|
|
184
|
+
},
|
|
185
|
+
query: {
|
|
186
|
+
type: 'string'
|
|
187
|
+
},
|
|
188
|
+
variables: {
|
|
189
|
+
type: 'object'
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
required: [
|
|
193
|
+
'id',
|
|
194
|
+
'query'
|
|
195
|
+
],
|
|
196
|
+
additionalProperties: false
|
|
197
|
+
}, async (ctx)=>{
|
|
198
|
+
try {
|
|
199
|
+
const result = await client.mutateGraph({
|
|
200
|
+
id: ctx.arguments.id,
|
|
201
|
+
text: ctx.arguments.query,
|
|
202
|
+
variables: ctx.arguments.variables ?? {}
|
|
203
|
+
});
|
|
204
|
+
if (result.errors != null && result.errors.length > 0) {
|
|
205
|
+
return {
|
|
206
|
+
isError: true,
|
|
207
|
+
content: [
|
|
208
|
+
{
|
|
209
|
+
type: 'text',
|
|
210
|
+
text: result.errors.map((e)=>e.toString()).join(', ')
|
|
211
|
+
}
|
|
212
|
+
],
|
|
213
|
+
structuredContent: {
|
|
214
|
+
errors: result.errors
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
content: [
|
|
220
|
+
{
|
|
221
|
+
type: 'text',
|
|
222
|
+
text: JSON.stringify(result.data)
|
|
223
|
+
}
|
|
224
|
+
],
|
|
225
|
+
structuredContent: {
|
|
226
|
+
data: result.data
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
} catch (error) {
|
|
230
|
+
return {
|
|
231
|
+
isError: true,
|
|
232
|
+
content: [
|
|
233
|
+
{
|
|
234
|
+
type: 'text',
|
|
235
|
+
text: `Failed to execute GraphQL mutation: ${error instanceof Error ? error.message : String(error)}`
|
|
236
|
+
}
|
|
237
|
+
]
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
return {
|
|
242
|
+
graph_list,
|
|
243
|
+
graph_info,
|
|
244
|
+
graph_schema,
|
|
245
|
+
graph_query,
|
|
246
|
+
graph_mutate
|
|
247
|
+
};
|
|
248
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kubun/mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for Kubun",
|
|
5
|
+
"keywords": [],
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "lib/index.js",
|
|
8
|
+
"types": "lib/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./lib/index.js",
|
|
11
|
+
"./run": "./lib/run.js"
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"kubun-mcp": "./lib/run.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"lib/*"
|
|
18
|
+
],
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@enkaku/token": "0.12.3",
|
|
22
|
+
"@mokei/context-server": "^0.4.0",
|
|
23
|
+
"graphql": "^16.12.0",
|
|
24
|
+
"@kubun/db": "^0.4.0",
|
|
25
|
+
"@kubun/db-postgres": "^0.4.0",
|
|
26
|
+
"@kubun/db-sqlite": "^0.4.0",
|
|
27
|
+
"@kubun/http-client": "^0.4.0",
|
|
28
|
+
"@kubun/protocol": "^0.4.0",
|
|
29
|
+
"@kubun/graphql": "^0.4.2",
|
|
30
|
+
"@kubun/server": "^0.4.1"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@enkaku/transport": "0.12.0",
|
|
34
|
+
"@mokei/context-client": "^0.4.0",
|
|
35
|
+
"@mokei/context-protocol": "^0.4.0",
|
|
36
|
+
"@kubun/client": "^0.4.0"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build:clean": "del lib",
|
|
40
|
+
"build:js": "swc src -d ./lib --config-file ../../swc.json --strip-leading-paths",
|
|
41
|
+
"build:types": "tsc --emitDeclarationOnly --skipLibCheck",
|
|
42
|
+
"build": "pnpm run build:clean && pnpm run build:js && pnpm run build:types",
|
|
43
|
+
"test:types": "tsc --noEmit",
|
|
44
|
+
"test:unit": "vitest run",
|
|
45
|
+
"test": "pnpm run test:types && pnpm run test:unit"
|
|
46
|
+
}
|
|
47
|
+
}
|