@powerhousedao/reactor-mcp 6.0.0-staging.3 → 6.0.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.
Files changed (71) hide show
  1. package/dist/cli.d.mts +1 -0
  2. package/dist/cli.mjs +143 -0
  3. package/dist/cli.mjs.map +1 -0
  4. package/dist/index.d.mts +637 -0
  5. package/dist/index.d.mts.map +1 -0
  6. package/dist/index.mjs +46 -0
  7. package/dist/index.mjs.map +1 -0
  8. package/dist/server-B68G2N1-.mjs +391 -0
  9. package/dist/server-B68G2N1-.mjs.map +1 -0
  10. package/package.json +22 -18
  11. package/dist/src/cli.d.ts +0 -2
  12. package/dist/src/cli.d.ts.map +0 -1
  13. package/dist/src/cli.js +0 -10
  14. package/dist/src/cli.js.map +0 -1
  15. package/dist/src/express.d.ts +0 -5
  16. package/dist/src/express.d.ts.map +0 -1
  17. package/dist/src/express.js +0 -59
  18. package/dist/src/express.js.map +0 -1
  19. package/dist/src/feature-flags.d.ts +0 -2
  20. package/dist/src/feature-flags.d.ts.map +0 -1
  21. package/dist/src/feature-flags.js +0 -9
  22. package/dist/src/feature-flags.js.map +0 -1
  23. package/dist/src/index.d.ts +0 -5
  24. package/dist/src/index.d.ts.map +0 -1
  25. package/dist/src/index.js +0 -5
  26. package/dist/src/index.js.map +0 -1
  27. package/dist/src/logger.d.ts +0 -3
  28. package/dist/src/logger.d.ts.map +0 -1
  29. package/dist/src/logger.js +0 -3
  30. package/dist/src/logger.js.map +0 -1
  31. package/dist/src/sdk/chat.d.ts +0 -19
  32. package/dist/src/sdk/chat.d.ts.map +0 -1
  33. package/dist/src/sdk/chat.js +0 -60
  34. package/dist/src/sdk/chat.js.map +0 -1
  35. package/dist/src/server.d.ts +0 -5
  36. package/dist/src/server.d.ts.map +0 -1
  37. package/dist/src/server.js +0 -56
  38. package/dist/src/server.js.map +0 -1
  39. package/dist/src/stdio/index.d.ts +0 -7
  40. package/dist/src/stdio/index.d.ts.map +0 -1
  41. package/dist/src/stdio/index.js +0 -93
  42. package/dist/src/stdio/index.js.map +0 -1
  43. package/dist/src/stdio/loader.d.ts +0 -18
  44. package/dist/src/stdio/loader.d.ts.map +0 -1
  45. package/dist/src/stdio/loader.js +0 -89
  46. package/dist/src/stdio/loader.js.map +0 -1
  47. package/dist/src/tools/index.d.ts +0 -3
  48. package/dist/src/tools/index.d.ts.map +0 -1
  49. package/dist/src/tools/index.js +0 -3
  50. package/dist/src/tools/index.js.map +0 -1
  51. package/dist/src/tools/reactor.d.ts +0 -847
  52. package/dist/src/tools/reactor.d.ts.map +0 -1
  53. package/dist/src/tools/reactor.js +0 -461
  54. package/dist/src/tools/reactor.js.map +0 -1
  55. package/dist/src/tools/types.d.ts +0 -24
  56. package/dist/src/tools/types.d.ts.map +0 -1
  57. package/dist/src/tools/types.js +0 -2
  58. package/dist/src/tools/types.js.map +0 -1
  59. package/dist/src/tools/utils.d.ts +0 -23
  60. package/dist/src/tools/utils.d.ts.map +0 -1
  61. package/dist/src/tools/utils.js +0 -99
  62. package/dist/src/tools/utils.js.map +0 -1
  63. package/dist/test/reactor.test.d.ts +0 -2
  64. package/dist/test/reactor.test.d.ts.map +0 -1
  65. package/dist/test/reactor.test.js +0 -501
  66. package/dist/test/reactor.test.js.map +0 -1
  67. package/dist/tsconfig.tsbuildinfo +0 -1
  68. package/dist/vitest.config.d.ts +0 -3
  69. package/dist/vitest.config.d.ts.map +0 -1
  70. package/dist/vitest.config.js +0 -9
  71. package/dist/vitest.config.js.map +0 -1
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/dist/cli.mjs ADDED
@@ -0,0 +1,143 @@
1
+ import { t as createServer$1, v as logger } from "./server-B68G2N1-.mjs";
2
+ import { childLogger, documentModelDocumentModelModule } from "document-model";
3
+ import { ReactorBuilder, ReactorClientBuilder } from "@powerhousedao/reactor";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { reactorDriveDocumentModelModule } from "@powerhousedao/reactor-drive";
6
+ import { driveDocumentModelModule } from "@powerhousedao/shared/document-drive";
7
+ import { EnvVarProvider } from "@openfeature/env-var-provider";
8
+ import { OpenFeature } from "@openfeature/server-sdk";
9
+ import { access } from "node:fs/promises";
10
+ import path from "node:path";
11
+ import { createServer } from "vite";
12
+ //#region src/feature-flags.ts
13
+ async function initFeatureFlags() {
14
+ const provider = new EnvVarProvider();
15
+ await OpenFeature.setProviderAndWait(provider);
16
+ return OpenFeature.getClient();
17
+ }
18
+ //#endregion
19
+ //#region src/stdio/loader.ts
20
+ function debounce(func, delay = 100) {
21
+ let timeoutId;
22
+ return (...args) => {
23
+ clearTimeout(timeoutId);
24
+ timeoutId = setTimeout(() => func(...args), delay);
25
+ };
26
+ }
27
+ function isSubpath(parent, dir) {
28
+ const relative = path.relative(parent, dir);
29
+ return relative && !relative.startsWith("..") && !path.isAbsolute(relative);
30
+ }
31
+ var VitePackageLoader = class {
32
+ logger = childLogger(["reactor-mcp", "vite-loader"]);
33
+ root;
34
+ documentModelsDir;
35
+ vite;
36
+ name = "VitePackageLoader";
37
+ constructor(root, documentModelsDir) {
38
+ this.root = root;
39
+ this.documentModelsDir = documentModelsDir;
40
+ }
41
+ get fullPath() {
42
+ return path.join(this.root, this.documentModelsDir);
43
+ }
44
+ async initVite() {
45
+ if (this.vite) return this.vite;
46
+ this.vite = await createServer({
47
+ root: this.root,
48
+ logLevel: "info",
49
+ server: {
50
+ hmr: false,
51
+ middlewareMode: true,
52
+ warmup: { ssrFiles: [this.fullPath] },
53
+ fs: { allow: [this.fullPath] }
54
+ },
55
+ optimizeDeps: {
56
+ noDiscovery: true,
57
+ include: []
58
+ }
59
+ });
60
+ return this.vite;
61
+ }
62
+ async load() {
63
+ const vite = await this.initVite();
64
+ await access(this.fullPath);
65
+ this.logger.verbose("Loading document models from @path", this.fullPath);
66
+ try {
67
+ const localDMs = await vite.ssrLoadModule(this.fullPath);
68
+ const exports = Object.values(localDMs);
69
+ const documentModels = [];
70
+ for (const dm of exports) if (dm.documentModel) documentModels.push(dm);
71
+ this.logger.verbose(` ➜ Loaded ${documentModels.length} Document Models from: ${this.fullPath}`);
72
+ return documentModels;
73
+ } catch (e) {
74
+ this.logger.verbose(` ➜ No Document Models found for: ${this.fullPath}${e ? `\n${JSON.stringify(e)}` : ""}`);
75
+ }
76
+ return [];
77
+ }
78
+ async onDocumentModelsChange(callback) {
79
+ const vite = await this.initVite();
80
+ const listener = debounce(async (changedPath) => {
81
+ if (isSubpath(this.fullPath, changedPath)) callback(await this.load());
82
+ }, 100);
83
+ vite.watcher.on("change", listener);
84
+ return () => {
85
+ vite.watcher.off("change", listener);
86
+ };
87
+ }
88
+ };
89
+ //#endregion
90
+ //#region src/stdio/index.ts
91
+ const baseDocumentModels = [
92
+ documentModelDocumentModelModule,
93
+ driveDocumentModelModule,
94
+ reactorDriveDocumentModelModule
95
+ ];
96
+ async function createReactorClient(documentModels) {
97
+ const reactorBuilder = new ReactorBuilder().withDocumentModels(baseDocumentModels.concat(documentModels));
98
+ return await new ReactorClientBuilder().withReactorBuilder(reactorBuilder).buildModule();
99
+ }
100
+ async function initStdioMcpServer(options) {
101
+ const { remoteDrive, root, documentModelsDir = "./document-models" } = options ?? {};
102
+ await initFeatureFlags();
103
+ let documentModelsLoader;
104
+ const documentModels = [];
105
+ if (root) {
106
+ documentModelsLoader = new VitePackageLoader(root, documentModelsDir);
107
+ try {
108
+ const loadedModels = await documentModelsLoader.load();
109
+ documentModels.push(...loadedModels);
110
+ logger.info("Loaded document models: @models", loadedModels.map((m) => m.documentModel.global.name).join(", "));
111
+ } catch (e) {
112
+ logger.error("@error", e);
113
+ }
114
+ }
115
+ const { client, reactor, reactorModule: rModule } = await createReactorClient(documentModels);
116
+ if (documentModelsLoader && rModule?.documentModelRegistry) {
117
+ const unsubscribe = await documentModelsLoader.onDocumentModelsChange((models) => {
118
+ const results = rModule.documentModelRegistry.registerModules(...baseDocumentModels.concat(models));
119
+ for (const result of results) if (result.status === "error") logger.error("Failed to register document model: @error", result.error);
120
+ });
121
+ process.on("exit", () => {
122
+ unsubscribe();
123
+ reactor.kill();
124
+ });
125
+ }
126
+ if (remoteDrive) logger.warn("Remote drive configuration via MCP is not supported in the new reactor. Remote drives should be configured at the server level.");
127
+ const server = await createServer$1({ client });
128
+ const transport = new StdioServerTransport();
129
+ await server.connect(transport);
130
+ }
131
+ //#endregion
132
+ //#region src/cli.ts
133
+ initStdioMcpServer({
134
+ remoteDrive: process.argv.at(2),
135
+ root: process.cwd()
136
+ }).catch((error) => {
137
+ logger.error("@error", error);
138
+ process.exit(1);
139
+ });
140
+ //#endregion
141
+ export {};
142
+
143
+ //# sourceMappingURL=cli.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.mjs","names":["createServer"],"sources":["../src/feature-flags.ts","../src/stdio/loader.ts","../src/stdio/index.ts","../src/cli.ts"],"sourcesContent":["import { EnvVarProvider } from \"@openfeature/env-var-provider\";\nimport { OpenFeature } from \"@openfeature/server-sdk\";\n\nexport async function initFeatureFlags() {\n // for now, we're only using env vars for feature flags\n const provider = new EnvVarProvider();\n\n await OpenFeature.setProviderAndWait(provider);\n\n return OpenFeature.getClient();\n}\n","import type { DocumentModelModule } from \"@powerhousedao/shared/document-model\";\nimport { childLogger } from \"document-model\";\nimport { access } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ViteDevServer } from \"vite\";\nimport { createServer } from \"vite\";\n\ninterface IPackageLoader {\n load(): Promise<DocumentModelModule[]>;\n onDocumentModelsChange(\n callback: (models: DocumentModelModule[]) => void,\n ): Promise<() => void>;\n}\n\nfunction debounce<T extends (...args: any[]) => void>(\n func: T,\n delay = 100,\n): (...args: Parameters<T>) => void {\n let timeoutId: ReturnType<typeof setTimeout>;\n return (...args: Parameters<T>): void => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => func(...args), delay);\n };\n}\n\nfunction isSubpath(parent: string, dir: string) {\n const relative = path.relative(parent, dir);\n return relative && !relative.startsWith(\"..\") && !path.isAbsolute(relative);\n}\n\nexport class VitePackageLoader implements IPackageLoader {\n private readonly logger = childLogger([\"reactor-mcp\", \"vite-loader\"]);\n\n private readonly root: string;\n private readonly documentModelsDir: string;\n\n private vite: ViteDevServer | undefined;\n\n readonly name = \"VitePackageLoader\";\n\n constructor(root: string, documentModelsDir: string) {\n this.root = root;\n this.documentModelsDir = documentModelsDir;\n }\n\n private get fullPath(): string {\n return path.join(this.root, this.documentModelsDir);\n }\n\n private async initVite() {\n if (this.vite) {\n return this.vite;\n }\n\n this.vite = await createServer({\n root: this.root,\n logLevel: \"info\",\n server: {\n hmr: false,\n middlewareMode: true,\n warmup: {\n ssrFiles: [this.fullPath],\n },\n fs: {\n allow: [this.fullPath],\n },\n },\n optimizeDeps: {\n // It's recommended to disable deps optimization\n noDiscovery: true,\n include: [],\n },\n });\n\n return this.vite;\n }\n\n async load(): Promise<DocumentModelModule[]> {\n const vite = await this.initVite();\n\n await access(this.fullPath);\n this.logger.verbose(\"Loading document models from @path\", this.fullPath);\n\n try {\n const localDMs = (await vite.ssrLoadModule(this.fullPath)) as Record<\n string,\n DocumentModelModule\n >;\n\n const exports = Object.values(localDMs);\n\n // duck type\n const documentModels: DocumentModelModule[] = [];\n for (const dm of exports) {\n if (dm.documentModel) {\n documentModels.push(dm);\n }\n }\n\n this.logger.verbose(\n ` ➜ Loaded ${documentModels.length} Document Models from: ${this.fullPath}`,\n );\n\n return documentModels;\n } catch (e) {\n this.logger.verbose(\n ` ➜ No Document Models found for: ${this.fullPath}${e ? `\\n${JSON.stringify(e)}` : \"\"}`,\n );\n }\n\n return [];\n }\n\n async onDocumentModelsChange(\n callback: (models: DocumentModelModule[]) => void,\n ) {\n const vite = await this.initVite();\n const listener = debounce(async (changedPath: string) => {\n if (isSubpath(this.fullPath, changedPath)) {\n const documentModels = await this.load();\n callback(documentModels);\n }\n }, 100);\n vite.watcher.on(\"change\", listener);\n\n return () => {\n vite.watcher.off(\"change\", listener);\n };\n }\n}\n","import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { ReactorBuilder, ReactorClientBuilder } from \"@powerhousedao/reactor\";\nimport { reactorDriveDocumentModelModule } from \"@powerhousedao/reactor-drive\";\nimport { driveDocumentModelModule } from \"@powerhousedao/shared/document-drive\";\nimport type { DocumentModelModule } from \"@powerhousedao/shared/document-model\";\nimport { documentModelDocumentModelModule } from \"document-model\";\nimport { initFeatureFlags } from \"../feature-flags.js\";\nimport { logger } from \"../logger.js\";\nimport { createServer } from \"../server.js\";\nimport { VitePackageLoader } from \"./loader.js\";\n\nexport interface IMcpOptions {\n remoteDrive?: string;\n root?: string;\n documentModelsDir?: string;\n}\n\nconst baseDocumentModels: DocumentModelModule<any>[] = [\n documentModelDocumentModelModule,\n driveDocumentModelModule,\n reactorDriveDocumentModelModule,\n];\n\nasync function createReactorClient(documentModels: DocumentModelModule[]) {\n const reactorBuilder = new ReactorBuilder().withDocumentModels(\n baseDocumentModels.concat(documentModels),\n );\n\n const module = await new ReactorClientBuilder()\n .withReactorBuilder(reactorBuilder)\n .buildModule();\n\n return module;\n}\n\nexport async function initStdioMcpServer(options?: IMcpOptions) {\n const {\n remoteDrive,\n root,\n documentModelsDir = \"./document-models\",\n } = options ?? {};\n\n // initialize feature flags\n await initFeatureFlags();\n\n // if root of project is passed then loads local document models\n let documentModelsLoader: VitePackageLoader | undefined;\n const documentModels: DocumentModelModule[] = [];\n\n if (root) {\n documentModelsLoader = new VitePackageLoader(root, documentModelsDir);\n try {\n const loadedModels = await documentModelsLoader.load();\n documentModels.push(...loadedModels);\n logger.info(\n \"Loaded document models: @models\",\n loadedModels.map((m) => m.documentModel.global.name).join(\", \"),\n );\n } catch (e) {\n logger.error(\"@error\", e);\n }\n }\n\n // initializes reactor client with loaded document models\n const reactorModule = await createReactorClient(documentModels);\n const { client, reactor, reactorModule: rModule } = reactorModule;\n\n // listens for changes in the local document models to update the reactor\n if (documentModelsLoader && rModule?.documentModelRegistry) {\n const unsubscribe = await documentModelsLoader.onDocumentModelsChange(\n (models) => {\n const results = rModule.documentModelRegistry.registerModules(\n ...baseDocumentModels.concat(models),\n );\n for (const result of results) {\n if (result.status === \"error\") {\n logger.error(\n \"Failed to register document model: @error\",\n result.error,\n );\n }\n }\n },\n );\n\n process.on(\"exit\", () => {\n unsubscribe();\n reactor.kill();\n });\n }\n\n // if a remote drive is passed, log a warning since remote drives\n // are now handled at a different level (SyncManager)\n if (remoteDrive) {\n logger.warn(\n \"Remote drive configuration via MCP is not supported in the new reactor. \" +\n \"Remote drives should be configured at the server level.\",\n );\n }\n\n // starts the server\n // Note: syncManager is not available in stdio mode currently\n const server = await createServer({ client });\n\n // starts Stdio transport\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n","import { logger } from \"./logger.js\";\nimport { initStdioMcpServer } from \"./stdio/index.js\";\n\ninitStdioMcpServer({\n remoteDrive: process.argv.at(2),\n root: process.cwd(),\n}).catch((error: unknown) => {\n logger.error(\"@error\", error);\n process.exit(1);\n});\n"],"mappings":"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"}