@majkapp/plugin-kit 1.3.1 → 1.3.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-kit.d.ts","sourceRoot":"","sources":["../src/plugin-kit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin-kit.d.ts","sourceRoot":"","sources":["../src/plugin-kit.ts"],"names":[],"mappings":"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"}
@@ -389,20 +389,44 @@ function serveSpa(ui, req, res, ctx) {
389
389
  return;
390
390
  }
391
391
  let content = fs_1.default.readFileSync(targetFile);
392
- // Inject base URL for React apps
392
+ // Inject base URL for React apps and MCP DOM Agent
393
393
  if (path_1.default.basename(targetFile) === 'index.html') {
394
394
  const html = content.toString('utf-8');
395
- const inject = `<script>` +
395
+ // Inject configuration
396
+ const configInject = `<script>` +
396
397
  `window.__MAJK_BASE_URL__=${JSON.stringify(ctx.http.baseUrl)};` +
397
398
  `window.__MAJK_IFRAME_BASE__=${JSON.stringify(ui.base)};` +
398
399
  `window.__MAJK_PLUGIN_ID__=${JSON.stringify(ctx.pluginId)};` +
399
400
  `</script>`;
400
- const injected = html.replace('</head>', `${inject}</head>`);
401
+ // Inject MCP DOM Agent script
402
+ const mcpScript = BuiltPlugin.mcpDomAgentScript
403
+ ? `<script>${BuiltPlugin.mcpDomAgentScript}</script>`
404
+ : '';
405
+ const allInjections = configInject + mcpScript;
406
+ const injected = html.replace('</head>', `${allInjections}</head>`);
401
407
  content = Buffer.from(injected, 'utf-8');
402
408
  }
403
409
  res.writeHead(200, corsHeaders({ 'Content-Type': getContentType(targetFile) }));
404
410
  res.end(content);
405
411
  }
412
+ /**
413
+ * Load MCP DOM Agent script
414
+ */
415
+ function loadMcpDomAgentScript() {
416
+ try {
417
+ const scriptPath = path_1.default.join(__dirname, 'mcp-dom-agent.js');
418
+ if (fs_1.default.existsSync(scriptPath)) {
419
+ return fs_1.default.readFileSync(scriptPath, 'utf-8');
420
+ }
421
+ // Fallback: return minimal inline version if file not found
422
+ log('[MCP DOM Agent] Script file not found, using minimal fallback');
423
+ return `(function(){if(window.__mcpDomAgent)return;window.__mcpDomAgent=true;console.log('[MCP DOM Agent] Minimal fallback loaded');})();`;
424
+ }
425
+ catch (error) {
426
+ log(`[MCP DOM Agent] Failed to load script: ${error.message}`);
427
+ return '';
428
+ }
429
+ }
406
430
  /**
407
431
  * Main plugin class built by the fluent API
408
432
  */
@@ -560,6 +584,13 @@ class BuiltPlugin {
560
584
  context.logger.info(`🌐 HTTP Port: ${context.http.port}`);
561
585
  context.logger.info(`🔗 Base URL: ${context.http.baseUrl}`);
562
586
  context.logger.info('═══════════════════════════════════════════════════════');
587
+ // Load MCP DOM Agent script once for all plugins
588
+ if (!BuiltPlugin.mcpDomAgentScript) {
589
+ BuiltPlugin.mcpDomAgentScript = loadMcpDomAgentScript();
590
+ if (BuiltPlugin.mcpDomAgentScript) {
591
+ context.logger.info('✅ MCP DOM Agent script loaded - will be injected into all screens');
592
+ }
593
+ }
563
594
  // Validate file paths now that we have pluginRoot context
564
595
  if (this.reactScreens.length > 0 && this.uiConfig) {
565
596
  const indexPath = path_1.default.join(this.context.pluginRoot, this.uiConfig.appDir || '', 'index.html');
@@ -814,6 +845,63 @@ class BuiltPlugin {
814
845
  this.context.logger.debug(`← ${method} ${url} 200 (${duration}ms)`);
815
846
  return;
816
847
  }
848
+ // MCP Screenshot endpoint
849
+ if (req.method === 'POST' && req.url === '/api/mcp/screenshot') {
850
+ try {
851
+ const body = await readBody(req);
852
+ if (!body || !body.data) {
853
+ res.writeHead(400, corsHeaders({ 'Content-Type': 'application/json' }));
854
+ res.end(JSON.stringify({ error: 'Missing screenshot data' }));
855
+ return;
856
+ }
857
+ // Create screenshots directory if it doesn't exist
858
+ const screenshotsDir = path_1.default.join(this.context.pluginRoot, 'screenshots');
859
+ if (!fs_1.default.existsSync(screenshotsDir)) {
860
+ fs_1.default.mkdirSync(screenshotsDir, { recursive: true });
861
+ }
862
+ // Generate filename
863
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
864
+ const metadata = body.metadata || {};
865
+ const customName = metadata.filename || `screenshot-${timestamp}`;
866
+ const filename = `${customName}.png`;
867
+ const filepath = path_1.default.join(screenshotsDir, filename);
868
+ // Extract base64 data (remove data:image/png;base64, prefix if present)
869
+ const base64Data = body.data.replace(/^data:image\/\w+;base64,/, '');
870
+ const buffer = Buffer.from(base64Data, 'base64');
871
+ // Write file
872
+ fs_1.default.writeFileSync(filepath, buffer);
873
+ // Also save metadata
874
+ const metadataPath = path_1.default.join(screenshotsDir, `${customName}.json`);
875
+ fs_1.default.writeFileSync(metadataPath, JSON.stringify({
876
+ ...metadata,
877
+ filename,
878
+ filepath,
879
+ timestamp: new Date().toISOString(),
880
+ size: buffer.length
881
+ }, null, 2));
882
+ this.context.logger.info(`📸 Screenshot saved: ${filepath}`);
883
+ res.writeHead(200, corsHeaders({ 'Content-Type': 'application/json' }));
884
+ res.end(JSON.stringify({
885
+ success: true,
886
+ filename,
887
+ filepath,
888
+ size: buffer.length,
889
+ message: 'Screenshot saved successfully'
890
+ }));
891
+ const duration = Date.now() - startTime;
892
+ this.context.logger.debug(`← ${method} ${url} 200 (${duration}ms)`);
893
+ return;
894
+ }
895
+ catch (error) {
896
+ this.context.logger.error(`Failed to save screenshot: ${error.message}`);
897
+ res.writeHead(500, corsHeaders({ 'Content-Type': 'application/json' }));
898
+ res.end(JSON.stringify({
899
+ success: false,
900
+ error: error.message || 'Failed to save screenshot'
901
+ }));
902
+ return;
903
+ }
904
+ }
817
905
  // HTML screens virtual route
818
906
  if (req.method === 'GET' && req.url?.startsWith('/__html/')) {
819
907
  const id = decodeURIComponent(req.url.substring('/__html/'.length)).split('?')[0];
@@ -826,8 +914,9 @@ class BuiltPlugin {
826
914
  return;
827
915
  }
828
916
  res.writeHead(200, corsHeaders({ 'Content-Type': 'text/html; charset=utf-8' }));
917
+ let htmlContent;
829
918
  if ('html' in screen) {
830
- res.end(screen.html);
919
+ htmlContent = screen.html;
831
920
  }
832
921
  else {
833
922
  const filePath = path_1.default.join(this.context.pluginRoot, screen.htmlFile);
@@ -843,7 +932,7 @@ class BuiltPlugin {
843
932
  return;
844
933
  }
845
934
  try {
846
- res.end(fs_1.default.readFileSync(filePath));
935
+ htmlContent = fs_1.default.readFileSync(filePath, 'utf-8');
847
936
  }
848
937
  catch (error) {
849
938
  this.context.logger.error(`Failed to read HTML file: ${error.message}`);
@@ -854,6 +943,21 @@ class BuiltPlugin {
854
943
  return;
855
944
  }
856
945
  }
946
+ // Inject MCP DOM Agent script into HTML screens
947
+ if (BuiltPlugin.mcpDomAgentScript) {
948
+ const mcpScript = `<script>${BuiltPlugin.mcpDomAgentScript}</script>`;
949
+ // Try to inject before </body>, fallback to </head>, fallback to end of HTML
950
+ if (htmlContent.includes('</body>')) {
951
+ htmlContent = htmlContent.replace('</body>', `${mcpScript}</body>`);
952
+ }
953
+ else if (htmlContent.includes('</head>')) {
954
+ htmlContent = htmlContent.replace('</head>', `${mcpScript}</head>`);
955
+ }
956
+ else {
957
+ htmlContent += mcpScript;
958
+ }
959
+ }
960
+ res.end(htmlContent);
857
961
  const duration = Date.now() - startTime;
858
962
  this.context.logger.debug(`← ${method} ${url} 200 (${duration}ms)`);
859
963
  return;
@@ -1002,6 +1106,8 @@ class BuiltPlugin {
1002
1106
  });
1003
1107
  }
1004
1108
  }
1109
+ // MCP DOM Agent script (loaded once at startup, accessible to serveSpa function)
1110
+ BuiltPlugin.mcpDomAgentScript = null;
1005
1111
  /**
1006
1112
  * Group tools by scope
1007
1113
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@majkapp/plugin-kit",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "Fluent builder framework for creating robust MAJK plugins",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",