@powerhousedao/reactor-mcp 6.0.0-dev.13 → 6.0.0-dev.130

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.
Files changed (46) hide show
  1. package/dist/src/cli.js +1 -1
  2. package/dist/src/cli.js.map +1 -1
  3. package/dist/src/index.d.ts +2 -2
  4. package/dist/src/index.d.ts.map +1 -1
  5. package/dist/src/index.js +1 -1
  6. package/dist/src/index.js.map +1 -1
  7. package/dist/src/logger.d.ts +1 -1
  8. package/dist/src/logger.d.ts.map +1 -1
  9. package/dist/src/logger.js +1 -1
  10. package/dist/src/logger.js.map +1 -1
  11. package/dist/src/mcp-routes.d.ts +19 -0
  12. package/dist/src/mcp-routes.d.ts.map +1 -0
  13. package/dist/src/mcp-routes.js +50 -0
  14. package/dist/src/mcp-routes.js.map +1 -0
  15. package/dist/src/server.d.ts +7 -3
  16. package/dist/src/server.d.ts.map +1 -1
  17. package/dist/src/server.js +8 -5
  18. package/dist/src/server.js.map +1 -1
  19. package/dist/src/stdio/index.d.ts.map +1 -1
  20. package/dist/src/stdio/index.js +22 -51
  21. package/dist/src/stdio/index.js.map +1 -1
  22. package/dist/src/stdio/loader.d.ts +1 -1
  23. package/dist/src/stdio/loader.d.ts.map +1 -1
  24. package/dist/src/stdio/loader.js +1 -1
  25. package/dist/src/stdio/loader.js.map +1 -1
  26. package/dist/src/tools/reactor.d.ts +83 -363
  27. package/dist/src/tools/reactor.d.ts.map +1 -1
  28. package/dist/src/tools/reactor.js +98 -101
  29. package/dist/src/tools/reactor.js.map +1 -1
  30. package/dist/src/tools/types.d.ts +1 -1
  31. package/dist/src/tools/types.d.ts.map +1 -1
  32. package/dist/src/tools/utils.d.ts +1 -1
  33. package/dist/src/tools/utils.d.ts.map +1 -1
  34. package/dist/src/tools/utils.js.map +1 -1
  35. package/dist/test/reactor.test.js +205 -248
  36. package/dist/test/reactor.test.js.map +1 -1
  37. package/dist/test/setup-mcp-server.test.d.ts +10 -0
  38. package/dist/test/setup-mcp-server.test.d.ts.map +1 -0
  39. package/dist/test/setup-mcp-server.test.js +172 -0
  40. package/dist/test/setup-mcp-server.test.js.map +1 -0
  41. package/dist/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +19 -20
  43. package/dist/src/express.d.ts +0 -5
  44. package/dist/src/express.d.ts.map +0 -1
  45. package/dist/src/express.js +0 -59
  46. package/dist/src/express.js.map +0 -1
@@ -1,76 +1,92 @@
1
+ import { ReactorBuilder, ReactorClientBuilder } from "@powerhousedao/reactor";
1
2
  import { createReactorMcpProvider } from "@powerhousedao/reactor-mcp";
2
- import { DocumentNotFoundError, driveDocumentModelModule, ReactorBuilder, } from "document-drive";
3
- import { documentModelCreateDocument, documentModelDocumentModelModule, documentModelReducer, } from "document-model";
4
- import { generateId } from "document-model/core";
5
- import { beforeEach, describe, expect, it, vi } from "vitest";
6
- // Mock reactor
7
- const createMockReactor = () => {
8
- const mockReactor = {
9
- initialize: vi.fn().mockResolvedValue(undefined),
10
- getDocument: vi.fn(),
3
+ import { driveDocumentModelModule } from "@powerhousedao/shared/document-drive";
4
+ import { documentModelCreateDocument, documentModelDocumentModelModule, } from "document-model";
5
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
6
+ function getTextContent(result, index = 0) {
7
+ const content = result.content[index];
8
+ return content.type === "text" ? content.text : "";
9
+ }
10
+ // Mock reactor client for unit tests
11
+ const createMockReactorClient = () => {
12
+ const mockClient = {
13
+ get: vi.fn(),
14
+ getDocumentModelModule: vi.fn(),
15
+ getDocumentModelModules: vi.fn().mockResolvedValue({
16
+ results: [],
17
+ options: { cursor: "", limit: 10 },
18
+ }),
19
+ createEmpty: vi.fn(),
20
+ getChildren: vi.fn().mockResolvedValue({
21
+ results: [],
22
+ options: { cursor: "", limit: 10 },
23
+ }),
24
+ deleteDocument: vi.fn(),
25
+ execute: vi.fn(),
26
+ createDocumentInDrive: vi.fn(),
27
+ find: vi.fn().mockResolvedValue({
28
+ results: [],
29
+ options: { cursor: "", limit: 10 },
30
+ }),
31
+ rename: vi.fn(),
11
32
  };
12
- return mockReactor;
33
+ return mockClient;
13
34
  };
14
- async function createReactor() {
15
- const builder = new ReactorBuilder([
35
+ // Create a real reactor client for integration tests
36
+ async function createReactorClientModule() {
37
+ const reactorBuilder = new ReactorBuilder().withDocumentModels([
16
38
  documentModelDocumentModelModule,
17
39
  driveDocumentModelModule,
18
40
  ]);
19
- const reactor = builder.build();
20
- await reactor.initialize();
21
- return reactor;
41
+ const module = await new ReactorClientBuilder()
42
+ .withReactorBuilder(reactorBuilder)
43
+ .buildModule();
44
+ return module;
22
45
  }
23
- describe.skip("ReactorMcpProvider", () => {
24
- let mockReactor;
25
- let reactor;
46
+ describe("ReactorMcpProvider", () => {
47
+ let mockClient;
48
+ let reactorModule;
49
+ let client;
26
50
  beforeEach(async () => {
27
- reactor = await createReactor();
28
- mockReactor = createMockReactor();
51
+ reactorModule = await createReactorClientModule();
52
+ client = reactorModule.client;
53
+ mockClient = createMockReactorClient();
29
54
  vi.clearAllMocks();
30
55
  });
31
- it("should initialize reactor on creation", async () => {
32
- await createReactorMcpProvider(mockReactor);
33
- expect(mockReactor.initialize).toHaveBeenCalledOnce();
56
+ afterEach(() => {
57
+ reactorModule.reactor.kill();
34
58
  });
35
- describe("createDocument tool", () => {
59
+ describe("getDocument tool", () => {
36
60
  it("should retrieve a document successfully", async () => {
61
+ // Create a document using the client
37
62
  const document = documentModelCreateDocument();
38
- const resultDocument = await reactor.addDocument(document);
39
- const provider = await createReactorMcpProvider(reactor);
63
+ await client.create(document);
64
+ const provider = await createReactorMcpProvider({ client });
40
65
  const result = await provider.tools.getDocument.callback({
41
66
  id: document.header.id,
42
67
  });
43
- expect(JSON.parse(result.content[0].text)).toMatchObject({
44
- document: {
45
- header: resultDocument.header,
46
- state: resultDocument.state,
47
- },
48
- });
68
+ expect(result.isError).toBeUndefined();
49
69
  expect(result.structuredContent).toMatchObject({
50
70
  document: {
51
- header: resultDocument.header,
52
- state: resultDocument.state,
71
+ header: expect.objectContaining({
72
+ id: document.header.id,
73
+ documentType: document.header.documentType,
74
+ }),
53
75
  },
54
76
  });
55
- expect(result.isError).toBeUndefined();
56
77
  });
57
78
  it("should handle errors gracefully", async () => {
58
- const provider = await createReactorMcpProvider(reactor);
79
+ const provider = await createReactorMcpProvider({ client });
59
80
  const result = await provider.tools.getDocument.callback({
60
81
  id: "non-existent-id",
61
82
  });
62
83
  expect(result.isError).toBe(true);
63
- expect(result.content).toEqual([
64
- {
65
- type: "text",
66
- text: "Error: Document with id non-existent-id not found",
67
- },
68
- ]);
84
+ expect(getTextContent(result)).toContain("non-existent-id");
69
85
  });
70
86
  it("should handle non-Error exceptions", async () => {
71
87
  const errorMessage = "String error message";
72
- mockReactor.getDocument = vi.fn().mockRejectedValue(errorMessage);
73
- const provider = await createReactorMcpProvider(mockReactor);
88
+ vi.mocked(mockClient.get).mockRejectedValue(errorMessage);
89
+ const provider = await createReactorMcpProvider({ client: mockClient });
74
90
  const result = await provider.tools.getDocument.callback({
75
91
  id: "test-id",
76
92
  });
@@ -82,40 +98,83 @@ describe.skip("ReactorMcpProvider", () => {
82
98
  },
83
99
  ]);
84
100
  });
85
- it("should handle empty string ID", async () => {
86
- mockReactor.getDocument = vi
87
- .fn()
88
- .mockRejectedValue(new DocumentNotFoundError(""));
89
- const provider = await createReactorMcpProvider(reactor);
90
- const result = await provider.tools.getDocument.callback({ id: "" });
91
- expect(result.isError).toBe(true);
92
- expect(result.content).toEqual([
93
- {
94
- type: "text",
95
- text: "Error: Document with id not found",
96
- },
97
- ]);
98
- });
99
101
  });
100
102
  describe("createDocument tool", () => {
101
103
  it("should create a document successfully", async () => {
102
- const provider = await createReactorMcpProvider(reactor);
104
+ const provider = await createReactorMcpProvider({ client });
103
105
  const result = await provider.tools.createDocument.callback({
104
106
  documentType: "powerhouse/document-model",
105
- documentId: "test-doc-id",
106
107
  });
107
108
  expect(result.isError).toBeUndefined();
108
- expect(result.structuredContent).toStrictEqual({
109
- documentId: "test-doc-id",
109
+ expect(result.structuredContent).toMatchObject({
110
+ documentId: expect.any(String),
111
+ });
112
+ });
113
+ it("should create a document in a drive when driveId is provided", async () => {
114
+ const drive = await client.createEmpty("powerhouse/document-drive");
115
+ const provider = await createReactorMcpProvider({ client });
116
+ const result = await provider.tools.createDocument.callback({
117
+ documentType: "powerhouse/document-model",
118
+ driveId: drive.header.id,
110
119
  });
120
+ expect(result.isError).toBeUndefined();
121
+ expect(result.structuredContent).toMatchObject({
122
+ documentId: expect.any(String),
123
+ });
124
+ // Verify the document was created and can be retrieved
125
+ const documentId = result.structuredContent
126
+ .documentId;
127
+ const doc = await client.get(documentId);
128
+ expect(doc).toBeDefined();
129
+ expect(doc.header.documentType).toBe("powerhouse/document-model");
130
+ });
131
+ it("should create a document in a drive with parentFolder", async () => {
132
+ const drive = await client.createEmpty("powerhouse/document-drive");
133
+ // Add a folder to the drive using addActions tool (properly formats actions)
134
+ const folderId = "test-folder-id";
135
+ const provider = await createReactorMcpProvider({ client });
136
+ await provider.tools.addActions.callback({
137
+ documentId: drive.header.id,
138
+ actions: [
139
+ {
140
+ type: "ADD_FOLDER",
141
+ input: { id: folderId, name: "Test Folder" },
142
+ scope: "global",
143
+ },
144
+ ],
145
+ });
146
+ const result = await provider.tools.createDocument.callback({
147
+ documentType: "powerhouse/document-model",
148
+ driveId: drive.header.id,
149
+ parentFolder: folderId,
150
+ });
151
+ expect(result.isError).toBeUndefined();
152
+ expect(result.structuredContent).toMatchObject({
153
+ documentId: expect.any(String),
154
+ });
155
+ // Verify the document exists
156
+ const documentId = result.structuredContent
157
+ .documentId;
158
+ const doc = await client.get(documentId);
159
+ expect(doc).toBeDefined();
160
+ expect(doc.header.documentType).toBe("powerhouse/document-model");
161
+ });
162
+ it("should return error for unknown document type with driveId", async () => {
163
+ const drive = await client.createEmpty("powerhouse/document-drive");
164
+ const provider = await createReactorMcpProvider({ client });
165
+ const result = await provider.tools.createDocument.callback({
166
+ documentType: "non-existent/type",
167
+ driveId: drive.header.id,
168
+ });
169
+ expect(result.isError).toBe(true);
170
+ expect(getTextContent(result)).toContain("non-existent/type");
111
171
  });
112
172
  });
113
173
  describe("getDocuments tool", () => {
114
174
  it("should get documents from a drive", async () => {
115
- const drive = await reactor.addDrive({
116
- global: { name: "Test Drive" },
117
- });
118
- const provider = await createReactorMcpProvider(reactor);
175
+ // Create a drive first
176
+ const drive = await client.createEmpty("powerhouse/document-drive");
177
+ const provider = await createReactorMcpProvider({ client });
119
178
  const result = await provider.tools.getDocuments.callback({
120
179
  parentId: drive.header.id,
121
180
  });
@@ -123,31 +182,15 @@ describe.skip("ReactorMcpProvider", () => {
123
182
  expect(result.structuredContent).toMatchObject({
124
183
  documentIds: [],
125
184
  });
126
- const { document } = await reactor.queueDocument({
127
- documentType: "powerhouse/document-model",
128
- id: generateId(),
129
- });
130
- const addResult = await reactor.addAction(drive.header.id, driveDocumentModelModule.actions.addFile({
131
- id: document?.header.id,
132
- documentType: "powerhouse/document-model",
133
- name: "test-doc",
134
- }));
135
- expect(addResult.error).toBeUndefined();
136
- const result2 = await provider.tools.getDocuments.callback({
137
- parentId: drive.header.id,
138
- });
139
- expect(result2.structuredContent).toMatchObject({
140
- documentIds: [document?.header.id],
141
- });
142
185
  });
143
186
  });
144
187
  describe("deleteDocument tool", () => {
145
188
  it("should delete a document successfully", async () => {
146
189
  const document = documentModelCreateDocument();
147
- await reactor.addDocument(document);
148
- const provider = await createReactorMcpProvider(reactor);
190
+ await client.create(document);
191
+ const provider = await createReactorMcpProvider({ client });
149
192
  const result = await provider.tools.deleteDocument.callback({
150
- documentId: document?.header.id,
193
+ documentId: document.header.id,
151
194
  });
152
195
  expect(result.isError).toBeUndefined();
153
196
  expect(result.structuredContent).toMatchObject({
@@ -155,22 +198,21 @@ describe.skip("ReactorMcpProvider", () => {
155
198
  });
156
199
  });
157
200
  it("should handle deletion of non-existent document", async () => {
158
- const provider = await createReactorMcpProvider(reactor);
201
+ const provider = await createReactorMcpProvider({ client });
159
202
  const result = await provider.tools.deleteDocument.callback({
160
203
  documentId: "non-existent-id",
161
204
  });
162
- expect(result.isError).toBeUndefined();
163
- // The reactor implementation returns true even for non-existent documents
205
+ // The new reactor throws for non-existent documents
164
206
  expect(result.structuredContent).toMatchObject({
165
- success: true,
207
+ success: false,
166
208
  });
167
209
  });
168
210
  });
169
211
  describe("addActions tool", () => {
170
212
  it("should add an action to a document", async () => {
171
213
  const document = documentModelCreateDocument();
172
- await reactor.addDocument(document);
173
- const provider = await createReactorMcpProvider(reactor);
214
+ await client.create(document);
215
+ const provider = await createReactorMcpProvider({ client });
174
216
  const action = documentModelDocumentModelModule.actions.setModelName({
175
217
  name: "test-doc",
176
218
  });
@@ -178,7 +220,6 @@ describe.skip("ReactorMcpProvider", () => {
178
220
  documentId: document.header.id,
179
221
  actions: [action],
180
222
  });
181
- const expectedResult = documentModelReducer(document, action);
182
223
  expect(result.isError).toBeUndefined();
183
224
  expect(result.structuredContent).toStrictEqual({
184
225
  success: true,
@@ -186,11 +227,11 @@ describe.skip("ReactorMcpProvider", () => {
186
227
  });
187
228
  it("should add multiple actions to a document", async () => {
188
229
  const document = documentModelCreateDocument();
189
- await reactor.addDocument(document);
190
- const provider = await createReactorMcpProvider(reactor);
230
+ await client.create(document);
231
+ const provider = await createReactorMcpProvider({ client });
191
232
  const actions = [
192
233
  documentModelDocumentModelModule.actions.setModelName({
193
- name: "Test Name 1 ",
234
+ name: "Test Name 1",
194
235
  }),
195
236
  documentModelDocumentModelModule.actions.setModelName({
196
237
  name: "Test Name 2",
@@ -200,8 +241,6 @@ describe.skip("ReactorMcpProvider", () => {
200
241
  documentId: document.header.id,
201
242
  actions,
202
243
  });
203
- const intermediateResult = documentModelReducer(document, actions[0]);
204
- const expectedResult = documentModelReducer(intermediateResult, actions[1]);
205
244
  expect(result.isError).toBeUndefined();
206
245
  expect(result.structuredContent).toStrictEqual({
207
246
  success: true,
@@ -209,8 +248,8 @@ describe.skip("ReactorMcpProvider", () => {
209
248
  });
210
249
  it("should throw error on invalid action type", async () => {
211
250
  const document = documentModelCreateDocument();
212
- await reactor.addDocument(document);
213
- const provider = await createReactorMcpProvider(reactor);
251
+ await client.create(document);
252
+ const provider = await createReactorMcpProvider({ client });
214
253
  const result = await provider.tools.addActions.callback({
215
254
  documentId: document.header.id,
216
255
  actions: [
@@ -222,14 +261,14 @@ describe.skip("ReactorMcpProvider", () => {
222
261
  ],
223
262
  });
224
263
  expect(result.isError).toBe(true);
225
- expect(result.content[0].text).toContain(`Operation "INVALID_ACTION" is not defined in any module of the document model`);
264
+ expect(getTextContent(result)).toContain(`Operation "INVALID_ACTION" is not defined in any module of the document model`);
226
265
  });
227
266
  it("should throw error on invalid action input", async () => {
228
267
  const document = documentModelCreateDocument();
229
- await reactor.addDocument(document);
230
- const provider = await createReactorMcpProvider(reactor);
268
+ await client.create(document);
269
+ const provider = await createReactorMcpProvider({ client });
231
270
  const result = await provider.tools.addActions.callback({
232
- documentId: document?.header.id,
271
+ documentId: document.header.id,
233
272
  actions: [
234
273
  {
235
274
  type: "SET_MODEL_NAME",
@@ -241,21 +280,10 @@ describe.skip("ReactorMcpProvider", () => {
241
280
  ],
242
281
  });
243
282
  expect(result.isError).toBe(true);
244
- expect(result.content[0].text)
245
- .toContain(`Input validation error: Invalid action input: [
246
- {
247
- "code": "invalid_type",
248
- "expected": "string",
249
- "received": "undefined",
250
- "path": [
251
- "name"
252
- ],
253
- "message": "Required"
254
- }
255
- ]`);
283
+ expect(getTextContent(result)).toContain("Input validation error");
256
284
  });
257
285
  it("should throw error on action on non-existent document", async () => {
258
- const provider = await createReactorMcpProvider(reactor);
286
+ const provider = await createReactorMcpProvider({ client });
259
287
  const result = await provider.tools.addActions.callback({
260
288
  documentId: "non-existent-id",
261
289
  actions: [
@@ -268,92 +296,46 @@ describe.skip("ReactorMcpProvider", () => {
268
296
  });
269
297
  // Action on non-existent document returns an error
270
298
  expect(result.isError).toBe(true);
271
- expect(result.content).toStrictEqual([
272
- {
273
- text: "Error: Document with id non-existent-id not found",
274
- type: "text",
275
- },
276
- ]);
277
- expect(result.structuredContent).toBeUndefined();
299
+ expect(getTextContent(result)).toContain("non-existent-id");
278
300
  });
279
301
  });
280
- // describe("addOperation tool", () => {
281
- // it("should add an operation to a document", async () => {
282
- // const document = documentModelCreateDocument();
283
- // await reactor.addDocument(document);
284
- // const provider = await createReactorMcpProvider(reactor);
285
- // const result = await provider.tools.addOperation.callback({
286
- // documentId: document.header.id,
287
- // operation: {
288
- // type: "SET_NAME",
289
- // input: "Operation Name",
290
- // scope: "global",
291
- // index: 1,
292
- // timestampUtcMs: new Date().toISOString(),
293
- // hash: "test-hash",
294
- // skip: 0,
295
- // },
296
- // });
297
- // expect(result.isError).toBeUndefined();
298
- // expect(result.structuredContent).toMatchObject({
299
- // result: {
300
- // status: "ERROR",
301
- //
302
- // error: expect.any(String),
303
- // operations: [],
304
- // signals: [],
305
- // },
306
- // });
307
- // });
308
- // });
309
302
  describe("getDrives tool", () => {
310
303
  it("should list all drives", async () => {
311
- await reactor.addDrive({ global: { name: "Test Drive 1" } });
312
- await reactor.addDrive({ global: { name: "Test Drive 2" } });
313
- const provider = await createReactorMcpProvider(reactor);
304
+ await client.createEmpty("powerhouse/document-drive");
305
+ await client.createEmpty("powerhouse/document-drive");
306
+ const provider = await createReactorMcpProvider({ client });
314
307
  const result = await provider.tools.getDrives.callback({});
315
308
  expect(result.isError).toBeUndefined();
316
309
  expect(result.structuredContent).toMatchObject({
317
- driveIds: expect.arrayContaining([]),
310
+ driveIds: expect.any(Array),
318
311
  });
312
+ expect(result.structuredContent.driveIds.length).toBeGreaterThanOrEqual(2);
319
313
  });
320
314
  });
321
315
  describe("addDrive tool", () => {
322
316
  it("should add a new drive", async () => {
323
- const provider = await createReactorMcpProvider(reactor);
317
+ const provider = await createReactorMcpProvider({ client });
324
318
  const result = await provider.tools.addDrive.callback({
325
319
  driveInput: {
326
320
  global: {
327
321
  name: "New Test Drive",
328
322
  icon: "test-icon",
329
323
  },
330
- id: "test-drive-id",
331
- slug: "test-drive-slug",
332
- preferredEditor: "test-editor",
333
- local: {
334
- availableOffline: true,
335
- sharingType: "private",
336
- },
337
324
  },
338
325
  });
339
326
  expect(result.isError).toBeUndefined();
340
- expect(result.structuredContent).toStrictEqual({
341
- driveId: "test-drive-id",
327
+ expect(result.structuredContent).toMatchObject({
328
+ driveId: expect.any(String),
342
329
  });
343
- const drive = await reactor.getDrive("test-drive-id");
330
+ const drive = await client.get(result.structuredContent.driveId);
344
331
  expect(drive).toMatchObject({
345
332
  header: expect.objectContaining({
346
333
  documentType: "powerhouse/document-drive",
347
334
  }),
348
- state: expect.objectContaining({
349
- global: expect.objectContaining({
350
- name: expect.any(String),
351
- }),
352
- }),
353
335
  });
354
336
  });
355
337
  it("should add a drive with minimal input", async () => {
356
- const provider = await createReactorMcpProvider(reactor);
338
+ const provider = await createReactorMcpProvider({ client });
357
339
  const result = await provider.tools.addDrive.callback({
358
340
  driveInput: {
359
341
  global: {
@@ -362,51 +344,23 @@ describe.skip("ReactorMcpProvider", () => {
362
344
  },
363
345
  });
364
346
  expect(result.isError).toBeUndefined();
365
- expect(result.structuredContent).toStrictEqual({
347
+ expect(result.structuredContent).toMatchObject({
366
348
  driveId: expect.any(String),
367
349
  });
368
- const drive = await reactor.getDrive(result.structuredContent.driveId);
350
+ const drive = await client.get(result.structuredContent.driveId);
369
351
  expect(drive).toMatchObject({
370
352
  header: expect.objectContaining({
371
353
  documentType: "powerhouse/document-drive",
372
354
  }),
373
- state: expect.objectContaining({
374
- global: expect.objectContaining({
375
- name: expect.any(String),
376
- }),
377
- }),
378
355
  });
379
356
  });
380
357
  });
381
358
  describe("getDrive tool", () => {
382
359
  it("should get a specific drive", async () => {
383
- const drive = await reactor.addDrive({ global: { name: "Test Drive" } });
384
- const provider = await createReactorMcpProvider(reactor);
360
+ const drive = await client.createEmpty("powerhouse/document-drive");
361
+ const provider = await createReactorMcpProvider({ client });
385
362
  const result = await provider.tools.getDrive.callback({
386
- driveId: drive?.header.id,
387
- });
388
- expect(result.isError).toBeUndefined();
389
- expect(result.structuredContent).toMatchObject({
390
- drive: expect.objectContaining({
391
- header: expect.objectContaining({
392
- documentType: "powerhouse/document-drive",
393
- }),
394
- state: expect.objectContaining({
395
- global: expect.objectContaining({
396
- name: expect.any(String),
397
- }),
398
- }),
399
- }),
400
- });
401
- });
402
- it("should get a drive with options", async () => {
403
- const drive = await reactor.addDrive({ global: { name: "Test Drive" } });
404
- const provider = await createReactorMcpProvider(reactor);
405
- const result = await provider.tools.getDrive.callback({
406
- driveId: drive?.header.id,
407
- options: {
408
- checkHashes: true,
409
- },
363
+ driveId: drive.header.id,
410
364
  });
411
365
  expect(result.isError).toBeUndefined();
412
366
  expect(result.structuredContent).toMatchObject({
@@ -414,19 +368,14 @@ describe.skip("ReactorMcpProvider", () => {
414
368
  header: expect.objectContaining({
415
369
  documentType: "powerhouse/document-drive",
416
370
  }),
417
- state: expect.objectContaining({
418
- global: expect.objectContaining({
419
- name: expect.any(String),
420
- }),
421
- }),
422
371
  }),
423
372
  });
424
373
  });
425
374
  });
426
375
  describe("deleteDrive tool", () => {
427
376
  it("should delete a drive successfully", async () => {
428
- const drive = await reactor.addDrive({ global: { name: "Test Drive" } });
429
- const provider = await createReactorMcpProvider(reactor);
377
+ const drive = await client.createEmpty("powerhouse/document-drive");
378
+ const provider = await createReactorMcpProvider({ client });
430
379
  const result = await provider.tools.deleteDrive.callback({
431
380
  driveId: drive.header.id,
432
381
  });
@@ -436,29 +385,20 @@ describe.skip("ReactorMcpProvider", () => {
436
385
  });
437
386
  });
438
387
  it("should handle deletion of non-existent drive", async () => {
439
- const provider = await createReactorMcpProvider(reactor);
388
+ const provider = await createReactorMcpProvider({ client });
440
389
  const result = await provider.tools.deleteDrive.callback({
441
390
  driveId: "non-existent-drive-id",
442
391
  });
443
- expect(result.isError).toBeUndefined();
444
- // The reactor implementation returns true even for non-existent drives
392
+ // The new reactor throws for non-existent documents
445
393
  expect(result.structuredContent).toMatchObject({
446
- success: true,
394
+ success: false,
447
395
  });
448
396
  });
449
397
  });
450
398
  describe("addRemoteDrive tool", () => {
451
- it("should handle remote drive connection with mock", async () => {
452
- // Mock the addRemoteDrive method since we can't test actual remote connections
453
- mockReactor.addRemoteDrive = vi.fn().mockResolvedValue({
454
- header: { id: "remote-drive-id" },
455
- state: { global: { name: "Remote Drive" } },
456
- });
457
- mockReactor.getDrive = vi.fn().mockResolvedValue({
458
- header: { id: "remote-drive-id" },
459
- state: { global: { name: "Remote Drive" } },
460
- });
461
- const provider = await createReactorMcpProvider(mockReactor);
399
+ it("should return an error when syncManager is not configured", async () => {
400
+ // No syncManager provided
401
+ const provider = await createReactorMcpProvider({ client });
462
402
  const result = await provider.tools.addRemoteDrive.callback({
463
403
  url: "https://example.com/remote-drive",
464
404
  options: {
@@ -473,28 +413,45 @@ describe.skip("ReactorMcpProvider", () => {
473
413
  pullInterval: 30000,
474
414
  },
475
415
  });
416
+ expect(result.isError).toBe(true);
417
+ expect(getTextContent(result)).toContain("Remote drive management is not available");
418
+ expect(getTextContent(result)).toContain("SyncManager was not configured");
419
+ });
420
+ });
421
+ describe("getDocumentModels tool", () => {
422
+ it("should list available document models", async () => {
423
+ const provider = await createReactorMcpProvider({ client });
424
+ const result = await provider.tools.getDocumentModels.callback({});
476
425
  expect(result.isError).toBeUndefined();
477
- expect(result.structuredContent).toStrictEqual({
478
- driveId: "remote-drive-id",
426
+ expect(result.structuredContent).toMatchObject({
427
+ documentModels: expect.any(Array),
479
428
  });
480
- const drive = await mockReactor.getDrive("remote-drive-id");
481
- expect(drive).toMatchObject({
482
- header: { id: "remote-drive-id" },
483
- state: { global: { name: "Remote Drive" } },
484
- });
485
- expect(mockReactor.addRemoteDrive).toHaveBeenCalledWith("https://example.com/remote-drive", expect.objectContaining({
486
- availableOffline: true,
487
- listeners: [],
488
- triggers: [],
489
- sharingType: "public",
490
- pullFilter: {
491
- branch: ["main"],
492
- documentId: ["doc1", "doc2"],
493
- documentType: ["powerhouse/document-model"],
494
- scope: ["global"],
495
- },
496
- pullInterval: 30000,
497
- }));
429
+ // Should include at least the document model and drive document model
430
+ const models = result.structuredContent.documentModels;
431
+ expect(models.length).toBeGreaterThanOrEqual(2);
432
+ });
433
+ });
434
+ describe("getDocumentModelSchema tool", () => {
435
+ it("should get schema for a document model", async () => {
436
+ const provider = await createReactorMcpProvider({ client });
437
+ const result = await provider.tools.getDocumentModelSchema.callback({
438
+ type: "powerhouse/document-model",
439
+ });
440
+ expect(result.isError).toBeUndefined();
441
+ expect(result.structuredContent).toMatchObject({
442
+ schema: expect.objectContaining({
443
+ name: expect.any(String),
444
+ id: "powerhouse/document-model",
445
+ }),
446
+ });
447
+ });
448
+ it("should return error for non-existent document model", async () => {
449
+ const provider = await createReactorMcpProvider({ client });
450
+ const result = await provider.tools.getDocumentModelSchema.callback({
451
+ type: "non-existent/model",
452
+ });
453
+ expect(result.isError).toBe(true);
454
+ expect(getTextContent(result)).toContain("non-existent/model");
498
455
  });
499
456
  });
500
457
  });