@hamak/smart-data-dico 1.1.1 → 1.6.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/bin/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { fileURLToPath } from 'url';
4
4
  import { dirname, join, resolve } from 'node:path';
5
- import { existsSync, mkdirSync, cpSync } from 'fs';
5
+ import { existsSync, mkdirSync, cpSync, writeFileSync } from 'fs';
6
6
  import { spawn } from 'child_process';
7
7
 
8
8
  const __filename = fileURLToPath(import.meta.url);
@@ -44,19 +44,30 @@ if (flags.help) {
44
44
  const port = flags.port || process.env.PORT || '3001';
45
45
  const dataDir = resolve(flags.dataDir || process.env.DATA_DIR || './data-dictionaries');
46
46
 
47
- // Ensure data directory exists
47
+ // Bootstrap the project on first run. The layout matches the current
48
+ // conventions:
49
+ // - `dico.config.json` — project marker (#104)
50
+ // - `.dico/stereotypes.yaml` — project-level stereotypes (#104)
51
+ // Packages and perspectives are created on demand — no empty subfolders.
48
52
  if (!existsSync(dataDir)) {
49
53
  mkdirSync(dataDir, { recursive: true });
50
54
  console.log(`Created data directory: ${dataDir}`);
51
55
 
52
- const defaultStereotypes = join(PKG_ROOT, 'data-dictionaries', 'stereotypes.yaml');
53
- if (existsSync(defaultStereotypes)) {
54
- cpSync(defaultStereotypes, join(dataDir, 'stereotypes.yaml'));
55
- console.log('Copied default stereotypes');
56
+ const dicoDir = join(dataDir, '.dico');
57
+ mkdirSync(dicoDir, { recursive: true });
58
+
59
+ const configPath = join(dataDir, 'dico.config.json');
60
+ if (!existsSync(configPath)) {
61
+ writeFileSync(configPath, JSON.stringify({ version: 1 }, null, 2) + '\n', 'utf-8');
56
62
  }
57
63
 
58
- mkdirSync(join(dataDir, 'microservices'), { recursive: true });
59
- mkdirSync(join(dataDir, 'perspectives'), { recursive: true });
64
+ // Default stereotypes are shipped under the bundled sample.
65
+ const defaultStereotypes = join(PKG_ROOT, 'samples', 'eshop', '.dico', 'stereotypes.yaml');
66
+ const targetStereotypes = join(dicoDir, 'stereotypes.yaml');
67
+ if (existsSync(defaultStereotypes) && !existsSync(targetStereotypes)) {
68
+ cpSync(defaultStereotypes, targetStereotypes);
69
+ console.log('Copied default stereotypes to .dico/stereotypes.yaml');
70
+ }
60
71
  }
61
72
 
62
73
  // Determine how to run the server:
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Smart Data Dictionary MCP launcher (#62).
4
+ *
5
+ * Boots the MCP server defined under `backend/src/mcp/server.ts` over stdio.
6
+ * Mirrors `bin/cli.js`:
7
+ * - Resolves `--data-dir <path>` (falling back to env `DATA_DIR`).
8
+ * - Prefers the bundled JS build if present; falls back to `tsx` over the
9
+ * TypeScript source when running from a checkout.
10
+ *
11
+ * Critically: this script must NOT write to stdout. The MCP stdio transport
12
+ * uses stdout for JSON-RPC framing — any extra bytes will corrupt the stream.
13
+ * All chatter goes to stderr.
14
+ */
15
+
16
+ import { fileURLToPath } from 'url';
17
+ import { dirname, join, resolve } from 'node:path';
18
+ import { existsSync } from 'fs';
19
+ import { spawn } from 'child_process';
20
+
21
+ const __filename = fileURLToPath(import.meta.url);
22
+ const __dirname = dirname(__filename);
23
+ const PKG_ROOT = join(__dirname, '..');
24
+
25
+ const args = process.argv.slice(2);
26
+ const flags = {};
27
+ for (let i = 0; i < args.length; i++) {
28
+ if (args[i] === '--data-dir' && args[i + 1]) {
29
+ flags.dataDir = args[++i];
30
+ } else if (args[i] === '--help' || args[i] === '-h') {
31
+ flags.help = true;
32
+ }
33
+ }
34
+
35
+ if (flags.help) {
36
+ process.stderr.write(`
37
+ dico-mcp - Smart Data Dictionary MCP server (stdio)
38
+
39
+ Usage:
40
+ dico-mcp [options]
41
+
42
+ Options:
43
+ --data-dir <path> Project directory (overrides DATA_DIR env)
44
+ -h, --help Show this help
45
+
46
+ Register with Claude Desktop / Cursor / Roo Code:
47
+ See backend/src/mcp/README.md for the JSON config snippets.
48
+
49
+ `);
50
+ process.exit(0);
51
+ }
52
+
53
+ const dataDir = resolve(flags.dataDir || process.env.DATA_DIR || './data-dictionaries');
54
+
55
+ const bundledServer = join(PKG_ROOT, 'backend', 'dist', 'mcp', 'cli.js');
56
+ const sourceServer = join(PKG_ROOT, 'backend', 'src', 'mcp', 'cli.ts');
57
+
58
+ let bin, binArgs;
59
+
60
+ if (existsSync(bundledServer)) {
61
+ bin = process.execPath; // node
62
+ binArgs = [bundledServer];
63
+ } else if (existsSync(sourceServer)) {
64
+ const tsxPaths = [
65
+ join(PKG_ROOT, 'node_modules', '.bin', 'tsx'),
66
+ join(PKG_ROOT, 'backend', 'node_modules', '.bin', 'tsx'),
67
+ ];
68
+ bin = tsxPaths.find(p => existsSync(p));
69
+ if (!bin) {
70
+ process.stderr.write('Error: tsx not found. Run `cd backend && npm install` first.\n');
71
+ process.exit(1);
72
+ }
73
+ binArgs = [sourceServer];
74
+ } else {
75
+ process.stderr.write('Error: MCP server not found (neither bundled nor source).\n');
76
+ process.exit(1);
77
+ }
78
+
79
+ // Spawn the server, wiring its stdio straight through to ours so the parent
80
+ // MCP client (Claude Desktop, Cursor, ...) talks to it directly.
81
+ const child = spawn(bin, binArgs, {
82
+ cwd: PKG_ROOT,
83
+ env: {
84
+ ...process.env,
85
+ DATA_DIR: dataDir,
86
+ },
87
+ stdio: 'inherit',
88
+ });
89
+
90
+ child.on('error', (err) => {
91
+ process.stderr.write(`Failed to start MCP server: ${err.message}\n`);
92
+ process.exit(1);
93
+ });
94
+
95
+ child.on('exit', (code) => process.exit(code || 0));
96
+
97
+ process.on('SIGINT', () => child.kill('SIGINT'));
98
+ process.on('SIGTERM', () => child.kill('SIGTERM'));