@lhi/n8m 0.1.2 → 0.2.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 +84 -21
- package/bin/dev.js +8 -0
- package/bin/run.js +7 -1
- package/dist/agentic/graph.d.ts +116 -8
- package/dist/agentic/graph.js +1 -1
- package/dist/agentic/nodes/architect.d.ts +15 -3
- package/dist/agentic/nodes/architect.js +11 -2
- package/dist/agentic/nodes/engineer.d.ts +1 -1
- package/dist/agentic/nodes/engineer.js +19 -91
- package/dist/agentic/nodes/qa.js +66 -55
- package/dist/agentic/nodes/reviewer.js +5 -3
- package/dist/agentic/state.d.ts +10 -0
- package/dist/agentic/state.js +2 -0
- package/dist/commands/create.js +115 -48
- package/dist/commands/doc.d.ts +11 -0
- package/dist/commands/doc.js +136 -0
- package/dist/commands/mcp.d.ts +6 -0
- package/dist/commands/mcp.js +25 -0
- package/dist/commands/modify.js +1 -1
- package/dist/commands/resume.js +40 -1
- package/dist/commands/test.d.ts +1 -0
- package/dist/commands/test.js +36 -4
- package/dist/resources/node-definitions-fallback.json +213 -0
- package/dist/services/ai.service.d.ts +38 -47
- package/dist/services/ai.service.js +302 -350
- package/dist/services/doc.service.d.ts +26 -0
- package/dist/services/doc.service.js +92 -0
- package/dist/services/mcp.service.d.ts +9 -0
- package/dist/services/mcp.service.js +110 -0
- package/dist/services/node-definitions.service.d.ts +5 -0
- package/dist/services/node-definitions.service.js +65 -9
- package/dist/utils/n8nClient.d.ts +10 -10
- package/dist/utils/n8nClient.js +80 -145
- package/oclif.manifest.json +67 -3
- package/package.json +7 -4
package/dist/utils/n8nClient.js
CHANGED
|
@@ -12,13 +12,35 @@ export class N8nClient {
|
|
|
12
12
|
// Priority: Explicit Config > Environment > Defaults
|
|
13
13
|
this.apiUrl = config?.apiUrl ?? process.env.N8N_API_URL ?? 'http://localhost:5678/api/v1';
|
|
14
14
|
this.apiKey = config?.apiKey ?? process.env.N8N_API_KEY ?? '';
|
|
15
|
+
// Normalize: ensure the URL ends with /api/v1 (config may store bare base URL)
|
|
16
|
+
if (!this.apiUrl.includes('/api/v1')) {
|
|
17
|
+
this.apiUrl = this.apiUrl.replace(/\/?$/, '') + '/api/v1';
|
|
18
|
+
}
|
|
15
19
|
// Constructor validation moved to method call time to allow lazy loading
|
|
16
|
-
// from config file if not provided here.
|
|
20
|
+
// from config file if not provided here.
|
|
17
21
|
this.headers = {
|
|
18
22
|
'Content-Type': 'application/json',
|
|
19
23
|
'X-N8N-API-KEY': this.apiKey,
|
|
20
24
|
};
|
|
21
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Assert that an API response is OK, throwing an actionable error for 401/403.
|
|
28
|
+
*/
|
|
29
|
+
async assertOk(response, operation) {
|
|
30
|
+
if (response.ok)
|
|
31
|
+
return;
|
|
32
|
+
const errorText = await response.text();
|
|
33
|
+
if (response.status === 403) {
|
|
34
|
+
throw new Error(`${operation} failed (403 Forbidden). Your n8n API key does not have permission to access this resource. ` +
|
|
35
|
+
`In n8n, go to Settings → n8n API and ensure the key belongs to the same owner/project as the workflow. ` +
|
|
36
|
+
`n8n says: ${errorText}`);
|
|
37
|
+
}
|
|
38
|
+
if (response.status === 401) {
|
|
39
|
+
throw new Error(`${operation} failed (401 Unauthorized). Your n8n API key is missing or invalid. ` +
|
|
40
|
+
`Run: n8m config --n8n-key <your-key>`);
|
|
41
|
+
}
|
|
42
|
+
throw new Error(`${operation} failed: ${response.status} - ${errorText}`);
|
|
43
|
+
}
|
|
22
44
|
/**
|
|
23
45
|
* Activate a workflow
|
|
24
46
|
*/
|
|
@@ -27,10 +49,7 @@ export class N8nClient {
|
|
|
27
49
|
headers: this.headers,
|
|
28
50
|
method: 'POST',
|
|
29
51
|
});
|
|
30
|
-
|
|
31
|
-
const errorText = await response.text();
|
|
32
|
-
throw new Error(`Failed to activate workflow: ${response.status} - ${errorText}`);
|
|
33
|
-
}
|
|
52
|
+
await this.assertOk(response, 'activate workflow');
|
|
34
53
|
}
|
|
35
54
|
/**
|
|
36
55
|
* Deactivate a workflow
|
|
@@ -40,10 +59,7 @@ export class N8nClient {
|
|
|
40
59
|
headers: this.headers,
|
|
41
60
|
method: 'POST',
|
|
42
61
|
});
|
|
43
|
-
|
|
44
|
-
const errorText = await response.text();
|
|
45
|
-
throw new Error(`Failed to deactivate workflow: ${response.status} - ${errorText}`);
|
|
46
|
-
}
|
|
62
|
+
await this.assertOk(response, 'deactivate workflow');
|
|
47
63
|
}
|
|
48
64
|
/**
|
|
49
65
|
* Execute a workflow and return the result
|
|
@@ -56,10 +72,7 @@ export class N8nClient {
|
|
|
56
72
|
headers: this.headers,
|
|
57
73
|
method: 'POST',
|
|
58
74
|
});
|
|
59
|
-
|
|
60
|
-
const errorText = await response.text();
|
|
61
|
-
throw new Error(`n8n Validation Error: ${response.status} - ${errorText}`);
|
|
62
|
-
}
|
|
75
|
+
await this.assertOk(response, 'execute workflow');
|
|
63
76
|
// If activation succeeds, we assume basic validation passed.
|
|
64
77
|
const result = await response.json();
|
|
65
78
|
return {
|
|
@@ -83,9 +96,7 @@ export class N8nClient {
|
|
|
83
96
|
headers: this.headers,
|
|
84
97
|
method: 'GET',
|
|
85
98
|
});
|
|
86
|
-
|
|
87
|
-
throw new Error(`Failed to get execution: ${response.status}`);
|
|
88
|
-
}
|
|
99
|
+
await this.assertOk(response, 'get execution');
|
|
89
100
|
return response.json();
|
|
90
101
|
}
|
|
91
102
|
catch (error) {
|
|
@@ -104,9 +115,7 @@ export class N8nClient {
|
|
|
104
115
|
headers: this.headers,
|
|
105
116
|
method: 'GET',
|
|
106
117
|
});
|
|
107
|
-
|
|
108
|
-
throw new Error(`Failed to get executions: ${response.status}`);
|
|
109
|
-
}
|
|
118
|
+
await this.assertOk(response, 'get workflow executions');
|
|
110
119
|
const result = await response.json();
|
|
111
120
|
return result.data;
|
|
112
121
|
}
|
|
@@ -119,15 +128,13 @@ export class N8nClient {
|
|
|
119
128
|
*/
|
|
120
129
|
async updateWorkflow(workflowId, workflowData) {
|
|
121
130
|
try {
|
|
131
|
+
const sanitized = this.sanitizeSettings(workflowData);
|
|
122
132
|
const response = await fetch(`${this.apiUrl}/workflows/${workflowId}`, {
|
|
123
|
-
body: JSON.stringify(
|
|
133
|
+
body: JSON.stringify(sanitized),
|
|
124
134
|
headers: this.headers,
|
|
125
135
|
method: 'PUT',
|
|
126
136
|
});
|
|
127
|
-
|
|
128
|
-
const errorText = await response.text();
|
|
129
|
-
throw new Error(`Failed to update workflow: ${response.status} - ${errorText}`);
|
|
130
|
-
}
|
|
137
|
+
await this.assertOk(response, 'update workflow');
|
|
131
138
|
}
|
|
132
139
|
catch (error) {
|
|
133
140
|
throw new Error(`Failed to update workflow: ${error.message}`);
|
|
@@ -142,24 +149,35 @@ export class N8nClient {
|
|
|
142
149
|
headers: this.headers,
|
|
143
150
|
method: 'GET',
|
|
144
151
|
});
|
|
145
|
-
|
|
146
|
-
throw new Error(`Failed to get workflow: ${response.status}`);
|
|
147
|
-
}
|
|
152
|
+
await this.assertOk(response, 'get workflow');
|
|
148
153
|
return response.json();
|
|
149
154
|
}
|
|
150
155
|
catch (error) {
|
|
151
156
|
throw new Error(`Failed to fetch workflow: ${error.message}`);
|
|
152
157
|
}
|
|
153
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Strip invalid timezone from workflow settings so n8n activation never 400s.
|
|
161
|
+
*/
|
|
162
|
+
sanitizeSettings(data) {
|
|
163
|
+
if (!data.settings || typeof data.settings !== 'object')
|
|
164
|
+
return data;
|
|
165
|
+
const settings = { ...data.settings };
|
|
166
|
+
// Always remove timezone — n8n validates against its own list and AI-generated
|
|
167
|
+
// values (including seemingly valid ones like "UTC") cause activation 400s.
|
|
168
|
+
// n8n will use the instance-level default timezone instead.
|
|
169
|
+
delete settings.timezone;
|
|
170
|
+
return { ...data, settings };
|
|
171
|
+
}
|
|
154
172
|
/**
|
|
155
173
|
* Create a new workflow
|
|
156
174
|
*/
|
|
157
175
|
async createWorkflow(name, workflowData) {
|
|
158
176
|
try {
|
|
159
|
-
const payload = {
|
|
177
|
+
const payload = this.sanitizeSettings({
|
|
160
178
|
name,
|
|
161
179
|
...workflowData,
|
|
162
|
-
};
|
|
180
|
+
});
|
|
163
181
|
// Debug logging for payload validation errors
|
|
164
182
|
// console.log('DEBUG: createWorkflow payload keys:', Object.keys(payload));
|
|
165
183
|
const response = await fetch(`${this.apiUrl}/workflows`, {
|
|
@@ -167,10 +185,7 @@ export class N8nClient {
|
|
|
167
185
|
headers: this.headers,
|
|
168
186
|
method: 'POST',
|
|
169
187
|
});
|
|
170
|
-
|
|
171
|
-
const errorText = await response.text();
|
|
172
|
-
throw new Error(`Failed to create workflow: ${response.status} - ${errorText}`);
|
|
173
|
-
}
|
|
188
|
+
await this.assertOk(response, 'create workflow');
|
|
174
189
|
const result = await response.json();
|
|
175
190
|
return { id: result.id };
|
|
176
191
|
}
|
|
@@ -179,121 +194,45 @@ export class N8nClient {
|
|
|
179
194
|
}
|
|
180
195
|
}
|
|
181
196
|
/**
|
|
182
|
-
* Get all installed node types
|
|
183
|
-
*
|
|
184
|
-
* Strategy:
|
|
185
|
-
* 1. Create a workflow with Webhook -> HTTP Request (Internal API)
|
|
186
|
-
* 2. Activate it
|
|
187
|
-
* 3. Call the webhook -> Returns the node types
|
|
188
|
-
*/
|
|
189
|
-
/**
|
|
190
|
-
* Get all installed node types via Probe Workflow (Webhook)
|
|
191
|
-
* Returns full node type objects including parameters, not just names.
|
|
197
|
+
* Get all installed node types directly from the n8n REST API.
|
|
198
|
+
* Handles paginated responses and returns the full node type objects.
|
|
192
199
|
*/
|
|
193
200
|
async getNodeTypes() {
|
|
194
|
-
const probeId = `probe-${Math.random().toString(36).substring(7)}`;
|
|
195
|
-
const probePath = `n8m-probe-${Math.random().toString(36).substring(7)}`;
|
|
196
|
-
let workflowId = null;
|
|
197
201
|
try {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
type: "n8n-nodes-base.webhook",
|
|
212
|
-
typeVersion: 1,
|
|
213
|
-
position: [400, 300],
|
|
214
|
-
webhookId: probePath
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
parameters: {
|
|
218
|
-
url: internalApiUrl,
|
|
219
|
-
method: "GET",
|
|
220
|
-
authentication: "none",
|
|
221
|
-
sendHeaders: true,
|
|
222
|
-
headerParameters: {
|
|
223
|
-
parameters: [
|
|
224
|
-
{
|
|
225
|
-
name: "X-N8N-API-KEY",
|
|
226
|
-
value: this.apiKey
|
|
227
|
-
}
|
|
228
|
-
]
|
|
229
|
-
},
|
|
230
|
-
options: {}
|
|
231
|
-
},
|
|
232
|
-
id: "http-request",
|
|
233
|
-
name: "FetchNodes",
|
|
234
|
-
type: "n8n-nodes-base.httpRequest",
|
|
235
|
-
typeVersion: 4.1,
|
|
236
|
-
position: [600, 300]
|
|
237
|
-
}
|
|
238
|
-
],
|
|
239
|
-
connections: {
|
|
240
|
-
"ProbeWebhook": {
|
|
241
|
-
main: [[{ node: "FetchNodes", type: "main", index: 0 }]]
|
|
242
|
-
}
|
|
243
|
-
},
|
|
244
|
-
settings: {
|
|
245
|
-
saveManualExecutions: false,
|
|
246
|
-
callerPolicy: 'workflowsFromSameOwner'
|
|
202
|
+
let all = [];
|
|
203
|
+
let cursor = undefined;
|
|
204
|
+
do {
|
|
205
|
+
const url = new URL(`${this.apiUrl}/node-types`);
|
|
206
|
+
if (cursor)
|
|
207
|
+
url.searchParams.set('cursor', cursor);
|
|
208
|
+
const response = await fetch(url.toString(), {
|
|
209
|
+
headers: this.headers,
|
|
210
|
+
method: 'GET',
|
|
211
|
+
});
|
|
212
|
+
if (!response.ok) {
|
|
213
|
+
console.warn(`[N8nClient] node-types request failed (${response.status}) — validation/shimming disabled`);
|
|
214
|
+
return [];
|
|
247
215
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
parameters: [
|
|
253
|
-
{ name: 'X-N8N-API-KEY', value: this.apiKey }
|
|
254
|
-
]
|
|
255
|
-
};
|
|
256
|
-
// 1. Create
|
|
257
|
-
const { id } = await this.createWorkflow(probeWorkflow.name, probeWorkflow);
|
|
258
|
-
workflowId = id;
|
|
259
|
-
// 2. Activate
|
|
260
|
-
await this.activateWorkflow(id);
|
|
261
|
-
// 3. Trigger
|
|
262
|
-
const baseUrl = this.apiUrl.replace('/api/v1', '');
|
|
263
|
-
const webhookUrl = `${baseUrl}/webhook/${probePath}`;
|
|
264
|
-
console.log(`[N8nClient] Triggering probe at ${webhookUrl}...`);
|
|
265
|
-
const response = await fetch(webhookUrl);
|
|
266
|
-
if (!response.ok) {
|
|
267
|
-
const errorText = await response.text();
|
|
268
|
-
if (process.env.DEBUG) {
|
|
269
|
-
console.warn(`[N8nClient] Probe webhook failed (Status ${response.status}): ${errorText}`);
|
|
216
|
+
const result = await response.json();
|
|
217
|
+
if (Array.isArray(result)) {
|
|
218
|
+
all = [...all, ...result];
|
|
219
|
+
cursor = undefined;
|
|
270
220
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
return [];
|
|
221
|
+
else if (result.data && Array.isArray(result.data)) {
|
|
222
|
+
all = [...all, ...result.data];
|
|
223
|
+
cursor = result.nextCursor ?? undefined;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
// Unknown format — stop paging
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
} while (cursor);
|
|
230
|
+
return all;
|
|
282
231
|
}
|
|
283
232
|
catch (error) {
|
|
284
|
-
|
|
285
|
-
console.warn(`[N8nClient] Probe failed: ${error.message}`);
|
|
286
|
-
}
|
|
233
|
+
console.warn(`[N8nClient] Failed to fetch node types: ${error.message}`);
|
|
287
234
|
return [];
|
|
288
235
|
}
|
|
289
|
-
finally {
|
|
290
|
-
if (workflowId) {
|
|
291
|
-
try {
|
|
292
|
-
await this.deleteWorkflow(workflowId);
|
|
293
|
-
}
|
|
294
|
-
catch { /* intentionally empty */ }
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
236
|
}
|
|
298
237
|
/**
|
|
299
238
|
* Get all workflows
|
|
@@ -312,9 +251,7 @@ export class N8nClient {
|
|
|
312
251
|
headers: this.headers,
|
|
313
252
|
method: 'GET',
|
|
314
253
|
});
|
|
315
|
-
|
|
316
|
-
throw new Error(`Failed to get workflows: ${response.status}`);
|
|
317
|
-
}
|
|
254
|
+
await this.assertOk(response, 'get workflows');
|
|
318
255
|
const result = await response.json();
|
|
319
256
|
allWorkflows = [...allWorkflows, ...result.data];
|
|
320
257
|
cursor = result.nextCursor;
|
|
@@ -334,9 +271,7 @@ export class N8nClient {
|
|
|
334
271
|
headers: this.headers,
|
|
335
272
|
method: 'DELETE',
|
|
336
273
|
});
|
|
337
|
-
|
|
338
|
-
throw new Error(`Failed to delete workflow: ${response.status}`);
|
|
339
|
-
}
|
|
274
|
+
await this.assertOk(response, 'delete workflow');
|
|
340
275
|
}
|
|
341
276
|
catch (error) {
|
|
342
277
|
throw new Error(`Failed to delete workflow: ${error.message}`);
|
package/oclif.manifest.json
CHANGED
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"required": false
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
|
-
"description": "Generate n8n workflows from natural language using
|
|
75
|
+
"description": "Generate n8n workflows from natural language using an AI Agent",
|
|
76
76
|
"examples": [
|
|
77
77
|
"<%= config.bin %> <%= command.id %> \"Send a telegram alert when I receive an email\"",
|
|
78
78
|
"echo \"Slack to Discord sync\" | <%= config.bin %> <%= command.id %>",
|
|
@@ -164,6 +164,64 @@
|
|
|
164
164
|
"deploy.js"
|
|
165
165
|
]
|
|
166
166
|
},
|
|
167
|
+
"doc": {
|
|
168
|
+
"aliases": [],
|
|
169
|
+
"args": {
|
|
170
|
+
"workflow": {
|
|
171
|
+
"description": "Path or Name of the workflow to document",
|
|
172
|
+
"name": "workflow",
|
|
173
|
+
"required": false
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
"description": "Generate visual and text documentation for n8n workflows",
|
|
177
|
+
"flags": {
|
|
178
|
+
"output": {
|
|
179
|
+
"char": "o",
|
|
180
|
+
"description": "Output directory for documentation (defaults to ./docs)",
|
|
181
|
+
"name": "output",
|
|
182
|
+
"hasDynamicHelp": false,
|
|
183
|
+
"multiple": false,
|
|
184
|
+
"type": "option"
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
"hasDynamicHelp": false,
|
|
188
|
+
"hiddenAliases": [],
|
|
189
|
+
"id": "doc",
|
|
190
|
+
"pluginAlias": "@lhi/n8m",
|
|
191
|
+
"pluginName": "@lhi/n8m",
|
|
192
|
+
"pluginType": "core",
|
|
193
|
+
"strict": true,
|
|
194
|
+
"enableJsonFlag": false,
|
|
195
|
+
"isESM": true,
|
|
196
|
+
"relativePath": [
|
|
197
|
+
"dist",
|
|
198
|
+
"commands",
|
|
199
|
+
"doc.js"
|
|
200
|
+
]
|
|
201
|
+
},
|
|
202
|
+
"mcp": {
|
|
203
|
+
"aliases": [],
|
|
204
|
+
"args": {},
|
|
205
|
+
"description": "Launch the n8m MCP (Model Context Protocol) server",
|
|
206
|
+
"examples": [
|
|
207
|
+
"<%= config.bin %> <%= command.id %>"
|
|
208
|
+
],
|
|
209
|
+
"flags": {},
|
|
210
|
+
"hasDynamicHelp": false,
|
|
211
|
+
"hiddenAliases": [],
|
|
212
|
+
"id": "mcp",
|
|
213
|
+
"pluginAlias": "@lhi/n8m",
|
|
214
|
+
"pluginName": "@lhi/n8m",
|
|
215
|
+
"pluginType": "core",
|
|
216
|
+
"strict": true,
|
|
217
|
+
"enableJsonFlag": false,
|
|
218
|
+
"isESM": true,
|
|
219
|
+
"relativePath": [
|
|
220
|
+
"dist",
|
|
221
|
+
"commands",
|
|
222
|
+
"mcp.js"
|
|
223
|
+
]
|
|
224
|
+
},
|
|
167
225
|
"modify": {
|
|
168
226
|
"aliases": [],
|
|
169
227
|
"args": {
|
|
@@ -178,7 +236,7 @@
|
|
|
178
236
|
"required": false
|
|
179
237
|
}
|
|
180
238
|
},
|
|
181
|
-
"description": "Modify existing n8n workflows using
|
|
239
|
+
"description": "Modify existing n8n workflows using an AI Agent",
|
|
182
240
|
"flags": {
|
|
183
241
|
"multiline": {
|
|
184
242
|
"char": "m",
|
|
@@ -309,6 +367,12 @@
|
|
|
309
367
|
"name": "validate-only",
|
|
310
368
|
"allowNo": false,
|
|
311
369
|
"type": "boolean"
|
|
370
|
+
},
|
|
371
|
+
"ai-scenarios": {
|
|
372
|
+
"description": "Generate 3 diverse AI test scenarios (happy path, edge case, error)",
|
|
373
|
+
"name": "ai-scenarios",
|
|
374
|
+
"allowNo": false,
|
|
375
|
+
"type": "boolean"
|
|
312
376
|
}
|
|
313
377
|
},
|
|
314
378
|
"hasDynamicHelp": false,
|
|
@@ -327,5 +391,5 @@
|
|
|
327
391
|
]
|
|
328
392
|
}
|
|
329
393
|
},
|
|
330
|
-
"version": "0.
|
|
394
|
+
"version": "0.2.0"
|
|
331
395
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lhi/n8m",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Agentic n8n CLI wrapper - A Skill Bridge for n8n workflow automation",
|
|
5
5
|
"author": "Lem Canady",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"oclif.manifest.json"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"openai": "^4.0.0",
|
|
22
21
|
"@langchain/core": "^1.1.18",
|
|
23
22
|
"@langchain/langgraph": "^1.1.2",
|
|
24
23
|
"@langchain/langgraph-checkpoint-sqlite": "^1.0.0",
|
|
24
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
25
25
|
"@oclif/core": "^4",
|
|
26
26
|
"@oclif/plugin-help": "^6",
|
|
27
27
|
"@oclif/plugin-plugins": "^5",
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
"ink-spinner": "^5.0.0",
|
|
38
38
|
"ink-text-input": "^6.0.0",
|
|
39
39
|
"inquirer": "^13.2.2",
|
|
40
|
+
"jsonrepair": "^3.13.2",
|
|
41
|
+
"openai": "^4.0.0",
|
|
40
42
|
"react": "^19.2.4"
|
|
41
43
|
},
|
|
42
44
|
"devDependencies": {
|
|
@@ -83,13 +85,14 @@
|
|
|
83
85
|
}
|
|
84
86
|
},
|
|
85
87
|
"scripts": {
|
|
86
|
-
"build": "shx rm -rf dist && tsc -b",
|
|
88
|
+
"build": "shx rm -rf dist && tsc -b && shx mkdir -p dist/resources && shx cp src/resources/*.json dist/resources/",
|
|
87
89
|
"lint": "eslint .",
|
|
88
90
|
"postpack": "shx rm -f oclif.manifest.json",
|
|
89
91
|
"posttest": "npm run lint",
|
|
90
92
|
"prepack": "oclif manifest && oclif readme",
|
|
91
|
-
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
|
|
93
|
+
"test": "NODE_ENV=test mocha --forbid-only \"test/**/*.test.ts\"",
|
|
92
94
|
"n8m": "./bin/run.js",
|
|
95
|
+
"start": "npm run build && ./bin/run.js",
|
|
93
96
|
"dev": "tsc -b -w",
|
|
94
97
|
"version": "oclif readme && git add README.md"
|
|
95
98
|
}
|