@nimblebrain/synapse 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 +21 -0
- package/README.md +248 -0
- package/dist/chunk-AW3YIXLE.cjs +248 -0
- package/dist/chunk-AW3YIXLE.cjs.map +1 -0
- package/dist/chunk-JZC3VC2C.js +349 -0
- package/dist/chunk-JZC3VC2C.js.map +1 -0
- package/dist/chunk-M4I222LB.js +243 -0
- package/dist/chunk-M4I222LB.js.map +1 -0
- package/dist/chunk-Q7OSHSGZ.cjs +351 -0
- package/dist/chunk-Q7OSHSGZ.cjs.map +1 -0
- package/dist/codegen/cli.cjs +85 -0
- package/dist/codegen/cli.cjs.map +1 -0
- package/dist/codegen/cli.d.cts +1 -0
- package/dist/codegen/cli.d.ts +1 -0
- package/dist/codegen/cli.js +83 -0
- package/dist/codegen/cli.js.map +1 -0
- package/dist/codegen/index.cjs +24 -0
- package/dist/codegen/index.cjs.map +1 -0
- package/dist/codegen/index.d.cts +24 -0
- package/dist/codegen/index.d.ts +24 -0
- package/dist/codegen/index.js +3 -0
- package/dist/codegen/index.js.map +1 -0
- package/dist/index.cjs +87 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +26 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.cjs +123 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +30 -0
- package/dist/react/index.d.ts +30 -0
- package/dist/react/index.js +113 -0
- package/dist/react/index.js.map +1 -0
- package/dist/synapse-runtime.iife.global.js +1 -0
- package/dist/types-BP0SNrpo.d.cts +96 -0
- package/dist/types-BP0SNrpo.d.ts +96 -0
- package/dist/vite/index.cjs +49 -0
- package/dist/vite/index.cjs.map +1 -0
- package/dist/vite/index.d.cts +21 -0
- package/dist/vite/index.d.ts +21 -0
- package/dist/vite/index.js +47 -0
- package/dist/vite/index.js.map +1 -0
- package/package.json +89 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NimbleBrain, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# @nimblebrain/synapse
|
|
2
|
+
|
|
3
|
+
[](https://github.com/NimbleBrainInc/synapse/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@nimblebrain/synapse)
|
|
5
|
+
[](https://www.npmjs.com/package/@nimblebrain/synapse)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://nodejs.org/)
|
|
9
|
+
|
|
10
|
+
Agent-aware app SDK for the [NimbleBrain](https://nimblebrain.ai) platform. Typed tool calls, reactive state, and React hooks over the [MCP ext-apps](https://modelcontextprotocol.io/specification/2025-06-18/user-interaction/ext-apps) protocol.
|
|
11
|
+
|
|
12
|
+
## What is Synapse?
|
|
13
|
+
|
|
14
|
+
Synapse is an optional enhancement layer over `@modelcontextprotocol/ext-apps`. It wraps the ext-apps protocol handshake and adds:
|
|
15
|
+
|
|
16
|
+
- **Typed tool calls** — call MCP tools with full TypeScript input/output types
|
|
17
|
+
- **Reactive data sync** — subscribe to data change events from the agent
|
|
18
|
+
- **Theme tracking** — automatic light/dark mode and custom design tokens
|
|
19
|
+
- **State store** — Redux-like store with optional persistence and LLM visibility
|
|
20
|
+
- **Keyboard forwarding** — forward shortcuts from sandboxed iframes to the host
|
|
21
|
+
- **Code generation** — generate TypeScript types from manifests, running servers, or JSON schemas
|
|
22
|
+
|
|
23
|
+
In non-NimbleBrain hosts (Claude Desktop, VS Code, ChatGPT), NB-specific features degrade gracefully to no-ops while ext-apps baseline behavior is preserved.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @nimblebrain/synapse
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Peer dependency:** `@modelcontextprotocol/ext-apps@^1.3.1`
|
|
32
|
+
|
|
33
|
+
## Package Exports
|
|
34
|
+
|
|
35
|
+
| Entry Point | Description |
|
|
36
|
+
|-------------|-------------|
|
|
37
|
+
| `@nimblebrain/synapse` | Vanilla JS core (no framework dependency) |
|
|
38
|
+
| `@nimblebrain/synapse/react` | React hooks and provider |
|
|
39
|
+
| `@nimblebrain/synapse/vite` | Vite plugin for dev mode |
|
|
40
|
+
| `@nimblebrain/synapse/codegen` | CLI + programmatic code generation |
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
### Vanilla JS
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { createSynapse } from "@nimblebrain/synapse";
|
|
48
|
+
|
|
49
|
+
const synapse = createSynapse({
|
|
50
|
+
name: "my-app",
|
|
51
|
+
version: "1.0.0",
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
await synapse.ready;
|
|
55
|
+
|
|
56
|
+
// Call an MCP tool
|
|
57
|
+
const result = await synapse.callTool("get_items", { limit: 10 });
|
|
58
|
+
console.log(result.data);
|
|
59
|
+
|
|
60
|
+
// React to data changes from the agent
|
|
61
|
+
synapse.onDataChanged((event) => {
|
|
62
|
+
console.log(`${event.tool} was called on ${event.server}`);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Push state visible to the LLM
|
|
66
|
+
synapse.setVisibleState(
|
|
67
|
+
{ selectedItem: "item-42" },
|
|
68
|
+
"User is viewing item 42",
|
|
69
|
+
);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### React
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { SynapseProvider, useCallTool, useTheme } from "@nimblebrain/synapse/react";
|
|
76
|
+
|
|
77
|
+
function App() {
|
|
78
|
+
return (
|
|
79
|
+
<SynapseProvider name="my-app" version="1.0.0">
|
|
80
|
+
<ItemList />
|
|
81
|
+
</SynapseProvider>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function ItemList() {
|
|
86
|
+
const { call, data, isPending } = useCallTool<Item[]>("list_items");
|
|
87
|
+
const theme = useTheme();
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<div style={{ colorScheme: theme.mode }}>
|
|
91
|
+
<button onClick={() => call()} disabled={isPending}>
|
|
92
|
+
Load Items
|
|
93
|
+
</button>
|
|
94
|
+
{data?.map((item) => <div key={item.id}>{item.name}</div>)}
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Vite Plugin
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
// vite.config.ts
|
|
104
|
+
import { synapseVite } from "@nimblebrain/synapse/vite";
|
|
105
|
+
|
|
106
|
+
export default {
|
|
107
|
+
plugins: [
|
|
108
|
+
synapseVite({
|
|
109
|
+
appName: "my-app",
|
|
110
|
+
}),
|
|
111
|
+
],
|
|
112
|
+
};
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Code Generation
|
|
116
|
+
|
|
117
|
+
Generate TypeScript types from an app manifest:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npx synapse --from-manifest ./manifest.json --out src/generated/types.ts
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Or from a running MCP server:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npx synapse --from-server http://localhost:3000 --out src/generated/types.ts
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Or from a directory of `.schema.json` files (generates CRUD tool types):
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npx synapse --from-schema ./schemas --out src/generated/types.ts
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## State Store
|
|
136
|
+
|
|
137
|
+
Create a typed, reactive store with optional persistence and agent visibility:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { createSynapse, createStore } from "@nimblebrain/synapse";
|
|
141
|
+
|
|
142
|
+
const synapse = createSynapse({ name: "my-app", version: "1.0.0" });
|
|
143
|
+
|
|
144
|
+
const store = createStore(synapse, {
|
|
145
|
+
initialState: { count: 0, items: [] },
|
|
146
|
+
actions: {
|
|
147
|
+
increment: (state) => ({ ...state, count: state.count + 1 }),
|
|
148
|
+
addItem: (state, item: string) => ({
|
|
149
|
+
...state,
|
|
150
|
+
items: [...state.items, item],
|
|
151
|
+
}),
|
|
152
|
+
},
|
|
153
|
+
persist: true,
|
|
154
|
+
visibleToAgent: true,
|
|
155
|
+
summarize: (state) => `${state.items.length} items, count=${state.count}`,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
store.dispatch.increment();
|
|
159
|
+
store.dispatch.addItem("hello");
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Use `useStore` in React:
|
|
163
|
+
|
|
164
|
+
```tsx
|
|
165
|
+
import { useStore } from "@nimblebrain/synapse/react";
|
|
166
|
+
|
|
167
|
+
function Counter() {
|
|
168
|
+
const { state, dispatch } = useStore(store);
|
|
169
|
+
return <button onClick={() => dispatch.increment()}>{state.count}</button>;
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## API Reference
|
|
174
|
+
|
|
175
|
+
### `createSynapse(options)`
|
|
176
|
+
|
|
177
|
+
Creates a Synapse instance. Returns a `Synapse` object.
|
|
178
|
+
|
|
179
|
+
| Option | Type | Description |
|
|
180
|
+
|--------|------|-------------|
|
|
181
|
+
| `name` | `string` | App name (must match registered bundle name) |
|
|
182
|
+
| `version` | `string` | Semver version |
|
|
183
|
+
| `internal` | `boolean?` | Enable cross-server tool calls (NB internal only) |
|
|
184
|
+
| `forwardKeys` | `KeyForwardConfig[]?` | Custom keyboard forwarding rules |
|
|
185
|
+
|
|
186
|
+
### `Synapse` Methods
|
|
187
|
+
|
|
188
|
+
| Method | Description |
|
|
189
|
+
|--------|-------------|
|
|
190
|
+
| `ready` | Promise that resolves after the ext-apps handshake |
|
|
191
|
+
| `isNimbleBrainHost` | Whether the host is a NimbleBrain platform |
|
|
192
|
+
| `callTool(name, args?)` | Call an MCP tool and get typed result |
|
|
193
|
+
| `onDataChanged(cb)` | Subscribe to data change events |
|
|
194
|
+
| `getTheme()` | Get current theme |
|
|
195
|
+
| `onThemeChanged(cb)` | Subscribe to theme changes |
|
|
196
|
+
| `action(name, params?)` | Dispatch a NB platform action |
|
|
197
|
+
| `chat(message, context?)` | Send a chat message to the agent |
|
|
198
|
+
| `setVisibleState(state, summary?)` | Push LLM-visible state (debounced 250ms) |
|
|
199
|
+
| `downloadFile(name, content, mime?)` | Trigger a file download |
|
|
200
|
+
| `openLink(url)` | Open a URL (host-aware) |
|
|
201
|
+
| `destroy()` | Clean up all listeners and timers |
|
|
202
|
+
|
|
203
|
+
### React Hooks
|
|
204
|
+
|
|
205
|
+
| Hook | Description |
|
|
206
|
+
|------|-------------|
|
|
207
|
+
| `useSynapse()` | Access the Synapse instance |
|
|
208
|
+
| `useCallTool(name)` | `{ call, data, isPending, error }` for a tool |
|
|
209
|
+
| `useDataSync(cb)` | Subscribe to data change events |
|
|
210
|
+
| `useTheme()` | Reactive theme object |
|
|
211
|
+
| `useAction()` | Dispatch platform actions |
|
|
212
|
+
| `useChat()` | Send chat messages |
|
|
213
|
+
| `useVisibleState()` | Push LLM-visible state |
|
|
214
|
+
| `useStore(store)` | `{ state, dispatch }` for a store |
|
|
215
|
+
|
|
216
|
+
## Development
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
npm install
|
|
220
|
+
npm run build # Build ESM + CJS + IIFE
|
|
221
|
+
npm test # Run tests
|
|
222
|
+
npm run typecheck # Type-check
|
|
223
|
+
npm run lint # Lint with Biome
|
|
224
|
+
npm run lint:fix # Auto-fix lint issues
|
|
225
|
+
npm run ci # Run full CI pipeline locally (lint → typecheck → build → test)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Publishing
|
|
229
|
+
|
|
230
|
+
Requires npm login with access to the `@nimblebrain` org.
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
# First time: log in to npm
|
|
234
|
+
npm login
|
|
235
|
+
|
|
236
|
+
# Bump version (updates package.json and creates a git tag)
|
|
237
|
+
npm version patch # or minor / major
|
|
238
|
+
|
|
239
|
+
# Publish (build runs automatically via prepublishOnly)
|
|
240
|
+
npm publish --access public
|
|
241
|
+
|
|
242
|
+
# Push the version tag
|
|
243
|
+
git push origin main --tags
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
|
|
6
|
+
// src/codegen/schema-reader.ts
|
|
7
|
+
function readFromManifest(manifestPath) {
|
|
8
|
+
if (!fs.existsSync(manifestPath)) {
|
|
9
|
+
throw new Error(`Manifest not found: ${manifestPath}`);
|
|
10
|
+
}
|
|
11
|
+
const raw = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
12
|
+
const tools = raw.tools ?? [];
|
|
13
|
+
if (!Array.isArray(tools)) {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
return tools.map((t) => ({
|
|
17
|
+
name: t.name,
|
|
18
|
+
description: t.description,
|
|
19
|
+
inputSchema: t.inputSchema ?? {},
|
|
20
|
+
outputSchema: t.outputSchema
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
async function readFromServer(url) {
|
|
24
|
+
const response = await fetch(url, {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: { "Content-Type": "application/json" },
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
jsonrpc: "2.0",
|
|
29
|
+
method: "tools/list",
|
|
30
|
+
id: "codegen-1",
|
|
31
|
+
params: {}
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`Server responded with ${response.status}: ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
const result = await response.json();
|
|
38
|
+
if (result.error) {
|
|
39
|
+
throw new Error(`Server error: ${result.error.message}`);
|
|
40
|
+
}
|
|
41
|
+
const tools = result.result?.tools ?? [];
|
|
42
|
+
return tools.map((t) => ({
|
|
43
|
+
name: t.name,
|
|
44
|
+
description: t.description,
|
|
45
|
+
inputSchema: t.inputSchema ?? {},
|
|
46
|
+
outputSchema: t.outputSchema
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
function readFromSchemaDir(dirPath) {
|
|
50
|
+
if (!fs.existsSync(dirPath)) {
|
|
51
|
+
throw new Error(`Schema directory not found: ${dirPath}`);
|
|
52
|
+
}
|
|
53
|
+
const files = fs.readdirSync(dirPath).filter((f) => f.endsWith(".schema.json"));
|
|
54
|
+
const tools = [];
|
|
55
|
+
for (const file of files) {
|
|
56
|
+
const schema = JSON.parse(fs.readFileSync(path.join(dirPath, file), "utf-8"));
|
|
57
|
+
const entityName = path.basename(file, ".schema.json");
|
|
58
|
+
tools.push(
|
|
59
|
+
{
|
|
60
|
+
name: `create_${entityName}`,
|
|
61
|
+
description: `Create a new ${entityName}`,
|
|
62
|
+
inputSchema: schema,
|
|
63
|
+
outputSchema: schema
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: `read_${entityName}`,
|
|
67
|
+
description: `Read a ${entityName} by ID`,
|
|
68
|
+
inputSchema: {
|
|
69
|
+
type: "object",
|
|
70
|
+
properties: { id: { type: "string" } },
|
|
71
|
+
required: ["id"]
|
|
72
|
+
},
|
|
73
|
+
outputSchema: schema
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: `update_${entityName}`,
|
|
77
|
+
description: `Update an existing ${entityName}`,
|
|
78
|
+
inputSchema: schema,
|
|
79
|
+
outputSchema: schema
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: `delete_${entityName}`,
|
|
83
|
+
description: `Delete a ${entityName} by ID`,
|
|
84
|
+
inputSchema: {
|
|
85
|
+
type: "object",
|
|
86
|
+
properties: { id: { type: "string" } },
|
|
87
|
+
required: ["id"]
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: `list_${entityName}s`,
|
|
92
|
+
description: `List all ${entityName}s`,
|
|
93
|
+
inputSchema: {
|
|
94
|
+
type: "object",
|
|
95
|
+
properties: {
|
|
96
|
+
filter: { type: "string" },
|
|
97
|
+
limit: { type: "number" }
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
outputSchema: {
|
|
101
|
+
type: "object",
|
|
102
|
+
properties: {
|
|
103
|
+
items: { type: "array", items: schema },
|
|
104
|
+
total: { type: "number" }
|
|
105
|
+
},
|
|
106
|
+
required: ["items", "total"]
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
return tools;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/codegen/type-generator.ts
|
|
115
|
+
function generateTypes(tools, appName) {
|
|
116
|
+
const lines = [];
|
|
117
|
+
const mapName = `${toPascalCase(appName)}ToolMap`;
|
|
118
|
+
lines.push("/**");
|
|
119
|
+
lines.push(` * Auto-generated by @nimblebrain/synapse codegen`);
|
|
120
|
+
lines.push(` * Source: ${appName}`);
|
|
121
|
+
lines.push(` *`);
|
|
122
|
+
lines.push(
|
|
123
|
+
` * DO NOT EDIT \u2014 regenerate with: npx synapse codegen --from-manifest ./manifest.json`
|
|
124
|
+
);
|
|
125
|
+
lines.push(` */`);
|
|
126
|
+
lines.push("");
|
|
127
|
+
const mapEntries = [];
|
|
128
|
+
for (const tool of tools) {
|
|
129
|
+
const baseName = toPascalCase(tool.name);
|
|
130
|
+
const inputName = `${baseName}Input`;
|
|
131
|
+
lines.push(schemaToInterface(inputName, tool.inputSchema));
|
|
132
|
+
lines.push("");
|
|
133
|
+
let outputName = "unknown";
|
|
134
|
+
if (tool.outputSchema) {
|
|
135
|
+
outputName = `${baseName}Output`;
|
|
136
|
+
lines.push(schemaToInterface(outputName, tool.outputSchema));
|
|
137
|
+
lines.push("");
|
|
138
|
+
}
|
|
139
|
+
mapEntries.push(` ${tool.name}: { input: ${inputName}; output: ${outputName} };`);
|
|
140
|
+
}
|
|
141
|
+
lines.push(`/** Tool type map for typed useCallTool */`);
|
|
142
|
+
lines.push(`export interface ${mapName} {`);
|
|
143
|
+
for (const entry of mapEntries) {
|
|
144
|
+
lines.push(entry);
|
|
145
|
+
}
|
|
146
|
+
lines.push(`}`);
|
|
147
|
+
lines.push("");
|
|
148
|
+
return lines.join("\n");
|
|
149
|
+
}
|
|
150
|
+
function schemaToInterface(name, schema) {
|
|
151
|
+
const type = schemaToType(schema, name);
|
|
152
|
+
if (schema.type === "object" || schema.properties) {
|
|
153
|
+
return generateInterface(name, schema);
|
|
154
|
+
}
|
|
155
|
+
return `export type ${name} = ${type};`;
|
|
156
|
+
}
|
|
157
|
+
function generateInterface(name, schema) {
|
|
158
|
+
const lines = [];
|
|
159
|
+
lines.push(`export interface ${name} {`);
|
|
160
|
+
const props = schema.properties ?? {};
|
|
161
|
+
const required = new Set(schema.required ?? []);
|
|
162
|
+
for (const [key, propSchema] of Object.entries(props)) {
|
|
163
|
+
const isRequired = required.has(key);
|
|
164
|
+
const type = schemaToType(propSchema, name + toPascalCase(key));
|
|
165
|
+
const desc = propSchema.description;
|
|
166
|
+
if (desc) {
|
|
167
|
+
lines.push(` /** ${desc} */`);
|
|
168
|
+
}
|
|
169
|
+
lines.push(` ${key}${isRequired ? "" : "?"}: ${type};`);
|
|
170
|
+
}
|
|
171
|
+
lines.push(`}`);
|
|
172
|
+
return lines.join("\n");
|
|
173
|
+
}
|
|
174
|
+
function schemaToType(schema, context) {
|
|
175
|
+
if (schema.enum && Array.isArray(schema.enum)) {
|
|
176
|
+
return schema.enum.map((v) => typeof v === "string" ? `"${v}"` : String(v)).join(" | ");
|
|
177
|
+
}
|
|
178
|
+
if (schema.oneOf && Array.isArray(schema.oneOf)) {
|
|
179
|
+
return schema.oneOf.map((s, i) => schemaToType(s, `${context}Option${i}`)).join(" | ");
|
|
180
|
+
}
|
|
181
|
+
if (schema.anyOf && Array.isArray(schema.anyOf)) {
|
|
182
|
+
return schema.anyOf.map((s, i) => schemaToType(s, `${context}Option${i}`)).join(" | ");
|
|
183
|
+
}
|
|
184
|
+
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
185
|
+
return schema.allOf.map((s, i) => schemaToType(s, `${context}Part${i}`)).join(" & ");
|
|
186
|
+
}
|
|
187
|
+
const type = schema.type;
|
|
188
|
+
if (Array.isArray(type)) {
|
|
189
|
+
return type.map((t) => primitiveType(t)).join(" | ");
|
|
190
|
+
}
|
|
191
|
+
switch (type) {
|
|
192
|
+
case "string":
|
|
193
|
+
return "string";
|
|
194
|
+
case "number":
|
|
195
|
+
case "integer":
|
|
196
|
+
return "number";
|
|
197
|
+
case "boolean":
|
|
198
|
+
return "boolean";
|
|
199
|
+
case "null":
|
|
200
|
+
return "null";
|
|
201
|
+
case "array": {
|
|
202
|
+
const items = schema.items;
|
|
203
|
+
if (items) {
|
|
204
|
+
return `${schemaToType(items, `${context}Item`)}[]`;
|
|
205
|
+
}
|
|
206
|
+
return "unknown[]";
|
|
207
|
+
}
|
|
208
|
+
case "object": {
|
|
209
|
+
if (schema.properties) {
|
|
210
|
+
const props = schema.properties;
|
|
211
|
+
const required = new Set(schema.required ?? []);
|
|
212
|
+
const fields = Object.entries(props).map(([key, propSchema]) => {
|
|
213
|
+
const t = schemaToType(propSchema, context + toPascalCase(key));
|
|
214
|
+
return `${key}${required.has(key) ? "" : "?"}: ${t}`;
|
|
215
|
+
}).join("; ");
|
|
216
|
+
return `{ ${fields} }`;
|
|
217
|
+
}
|
|
218
|
+
return "Record<string, unknown>";
|
|
219
|
+
}
|
|
220
|
+
default:
|
|
221
|
+
return "unknown";
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function primitiveType(t) {
|
|
225
|
+
switch (t) {
|
|
226
|
+
case "string":
|
|
227
|
+
return "string";
|
|
228
|
+
case "number":
|
|
229
|
+
case "integer":
|
|
230
|
+
return "number";
|
|
231
|
+
case "boolean":
|
|
232
|
+
return "boolean";
|
|
233
|
+
case "null":
|
|
234
|
+
return "null";
|
|
235
|
+
default:
|
|
236
|
+
return "unknown";
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function toPascalCase(str) {
|
|
240
|
+
return str.split(/[-_@/]/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
exports.generateTypes = generateTypes;
|
|
244
|
+
exports.readFromManifest = readFromManifest;
|
|
245
|
+
exports.readFromSchemaDir = readFromSchemaDir;
|
|
246
|
+
exports.readFromServer = readFromServer;
|
|
247
|
+
//# sourceMappingURL=chunk-AW3YIXLE.cjs.map
|
|
248
|
+
//# sourceMappingURL=chunk-AW3YIXLE.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/codegen/schema-reader.ts","../src/codegen/type-generator.ts"],"names":["existsSync","readFileSync","readdirSync","join","basename"],"mappings":"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","file":"chunk-AW3YIXLE.cjs","sourcesContent":["import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport type { ToolDefinition } from \"../types.js\";\n\n/**\n * Read tool definitions from a manifest.json file.\n * Extracts tools from the MCP standard `tools` array.\n */\nexport function readFromManifest(manifestPath: string): ToolDefinition[] {\n if (!existsSync(manifestPath)) {\n throw new Error(`Manifest not found: ${manifestPath}`);\n }\n\n const raw = JSON.parse(readFileSync(manifestPath, \"utf-8\"));\n const tools = raw.tools ?? [];\n\n if (!Array.isArray(tools)) {\n return [];\n }\n\n return tools.map((t: any) => ({\n name: t.name as string,\n description: t.description as string | undefined,\n inputSchema: (t.inputSchema ?? {}) as Record<string, unknown>,\n outputSchema: t.outputSchema as Record<string, unknown> | undefined,\n }));\n}\n\n/**\n * Read tool definitions from a running MCP server via tools/list.\n * Connects to the server's HTTP endpoint and calls the JSON-RPC method.\n */\nexport async function readFromServer(url: string): Promise<ToolDefinition[]> {\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n method: \"tools/list\",\n id: \"codegen-1\",\n params: {},\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Server responded with ${response.status}: ${response.statusText}`);\n }\n\n const result = await response.json();\n if (result.error) {\n throw new Error(`Server error: ${result.error.message}`);\n }\n\n const tools = result.result?.tools ?? [];\n return tools.map((t: any) => ({\n name: t.name as string,\n description: t.description as string | undefined,\n inputSchema: (t.inputSchema ?? {}) as Record<string, unknown>,\n outputSchema: t.outputSchema as Record<string, unknown> | undefined,\n }));\n}\n\n/**\n * Read entity schemas from a directory and generate CRUD tool definitions.\n * Each .schema.json file becomes create/read/update/delete/list tools.\n */\nexport function readFromSchemaDir(dirPath: string): ToolDefinition[] {\n if (!existsSync(dirPath)) {\n throw new Error(`Schema directory not found: ${dirPath}`);\n }\n\n const files = readdirSync(dirPath).filter((f: string) => f.endsWith(\".schema.json\"));\n const tools: ToolDefinition[] = [];\n\n for (const file of files) {\n const schema = JSON.parse(readFileSync(join(dirPath, file), \"utf-8\"));\n const entityName = basename(file, \".schema.json\");\n\n tools.push(\n {\n name: `create_${entityName}`,\n description: `Create a new ${entityName}`,\n inputSchema: schema,\n outputSchema: schema,\n },\n {\n name: `read_${entityName}`,\n description: `Read a ${entityName} by ID`,\n inputSchema: {\n type: \"object\",\n properties: { id: { type: \"string\" } },\n required: [\"id\"],\n },\n outputSchema: schema,\n },\n {\n name: `update_${entityName}`,\n description: `Update an existing ${entityName}`,\n inputSchema: schema,\n outputSchema: schema,\n },\n {\n name: `delete_${entityName}`,\n description: `Delete a ${entityName} by ID`,\n inputSchema: {\n type: \"object\",\n properties: { id: { type: \"string\" } },\n required: [\"id\"],\n },\n },\n {\n name: `list_${entityName}s`,\n description: `List all ${entityName}s`,\n inputSchema: {\n type: \"object\",\n properties: {\n filter: { type: \"string\" },\n limit: { type: \"number\" },\n },\n },\n outputSchema: {\n type: \"object\",\n properties: {\n items: { type: \"array\", items: schema },\n total: { type: \"number\" },\n },\n required: [\"items\", \"total\"],\n },\n },\n );\n }\n\n return tools;\n}\n","import type { ToolDefinition } from \"../types.js\";\n\n/**\n * Generate TypeScript interfaces from tool definitions.\n */\nexport function generateTypes(tools: ToolDefinition[], appName: string): string {\n const lines: string[] = [];\n const mapName = `${toPascalCase(appName)}ToolMap`;\n\n lines.push(\"/**\");\n lines.push(` * Auto-generated by @nimblebrain/synapse codegen`);\n lines.push(` * Source: ${appName}`);\n lines.push(` *`);\n lines.push(\n ` * DO NOT EDIT — regenerate with: npx synapse codegen --from-manifest ./manifest.json`,\n );\n lines.push(` */`);\n lines.push(\"\");\n\n const mapEntries: string[] = [];\n\n for (const tool of tools) {\n const baseName = toPascalCase(tool.name);\n\n // Input type\n const inputName = `${baseName}Input`;\n lines.push(schemaToInterface(inputName, tool.inputSchema));\n lines.push(\"\");\n\n // Output type\n let outputName = \"unknown\";\n if (tool.outputSchema) {\n outputName = `${baseName}Output`;\n lines.push(schemaToInterface(outputName, tool.outputSchema));\n lines.push(\"\");\n }\n\n mapEntries.push(` ${tool.name}: { input: ${inputName}; output: ${outputName} };`);\n }\n\n // Tool map\n lines.push(`/** Tool type map for typed useCallTool */`);\n lines.push(`export interface ${mapName} {`);\n for (const entry of mapEntries) {\n lines.push(entry);\n }\n lines.push(`}`);\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// JSON Schema -> TypeScript conversion\n// ---------------------------------------------------------------------------\n\nfunction schemaToInterface(name: string, schema: Record<string, unknown>): string {\n const type = schemaToType(schema, name);\n\n // If the schema is an object, generate a named interface\n if (schema.type === \"object\" || schema.properties) {\n return generateInterface(name, schema);\n }\n\n // Otherwise, generate a type alias\n return `export type ${name} = ${type};`;\n}\n\nfunction generateInterface(name: string, schema: Record<string, unknown>): string {\n const lines: string[] = [];\n lines.push(`export interface ${name} {`);\n\n const props = (schema.properties ?? {}) as Record<string, Record<string, unknown>>;\n const required = new Set((schema.required ?? []) as string[]);\n\n for (const [key, propSchema] of Object.entries(props)) {\n const isRequired = required.has(key);\n const type = schemaToType(propSchema, name + toPascalCase(key));\n const desc = propSchema.description;\n if (desc) {\n lines.push(` /** ${desc} */`);\n }\n lines.push(` ${key}${isRequired ? \"\" : \"?\"}: ${type};`);\n }\n\n lines.push(`}`);\n return lines.join(\"\\n\");\n}\n\nfunction schemaToType(schema: Record<string, unknown>, context: string): string {\n // Handle enum\n if (schema.enum && Array.isArray(schema.enum)) {\n return (schema.enum as unknown[])\n .map((v) => (typeof v === \"string\" ? `\"${v}\"` : String(v)))\n .join(\" | \");\n }\n\n // Handle oneOf / anyOf\n if (schema.oneOf && Array.isArray(schema.oneOf)) {\n return (schema.oneOf as Record<string, unknown>[])\n .map((s, i) => schemaToType(s, `${context}Option${i}`))\n .join(\" | \");\n }\n if (schema.anyOf && Array.isArray(schema.anyOf)) {\n return (schema.anyOf as Record<string, unknown>[])\n .map((s, i) => schemaToType(s, `${context}Option${i}`))\n .join(\" | \");\n }\n\n // Handle allOf (intersection)\n if (schema.allOf && Array.isArray(schema.allOf)) {\n return (schema.allOf as Record<string, unknown>[])\n .map((s, i) => schemaToType(s, `${context}Part${i}`))\n .join(\" & \");\n }\n\n // Handle type-based conversion\n const type = schema.type as string | string[] | undefined;\n\n if (Array.isArray(type)) {\n // Multi-type (e.g., [\"string\", \"null\"])\n return type.map((t) => primitiveType(t)).join(\" | \");\n }\n\n switch (type) {\n case \"string\":\n return \"string\";\n case \"number\":\n case \"integer\":\n return \"number\";\n case \"boolean\":\n return \"boolean\";\n case \"null\":\n return \"null\";\n case \"array\": {\n const items = schema.items as Record<string, unknown> | undefined;\n if (items) {\n return `${schemaToType(items, `${context}Item`)}[]`;\n }\n return \"unknown[]\";\n }\n case \"object\": {\n if (schema.properties) {\n // Inline object — generate property types\n const props = schema.properties as Record<string, Record<string, unknown>>;\n const required = new Set((schema.required ?? []) as string[]);\n const fields = Object.entries(props)\n .map(([key, propSchema]) => {\n const t = schemaToType(propSchema, context + toPascalCase(key));\n return `${key}${required.has(key) ? \"\" : \"?\"}: ${t}`;\n })\n .join(\"; \");\n return `{ ${fields} }`;\n }\n return \"Record<string, unknown>\";\n }\n default:\n return \"unknown\";\n }\n}\n\nfunction primitiveType(t: string): string {\n switch (t) {\n case \"string\":\n return \"string\";\n case \"number\":\n case \"integer\":\n return \"number\";\n case \"boolean\":\n return \"boolean\";\n case \"null\":\n return \"null\";\n default:\n return \"unknown\";\n }\n}\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_@/]/)\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\"\");\n}\n"]}
|