crushdataai 1.0.0 → 1.2.1

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.
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PostgreSQLConnector = void 0;
4
+ class PostgreSQLConnector {
5
+ constructor() {
6
+ this.type = 'postgresql';
7
+ }
8
+ async test(connection) {
9
+ if (!connection.host || !connection.user || !connection.database) {
10
+ throw new Error('Host, user, and database are required');
11
+ }
12
+ return true;
13
+ }
14
+ async getTables(connection) {
15
+ return [];
16
+ }
17
+ async getData(connection, tableName, page, limit) {
18
+ return {
19
+ columns: [],
20
+ rows: [],
21
+ pagination: { page, limit, totalRows: 0, totalPages: 0, startIdx: 0, endIdx: 0 }
22
+ };
23
+ }
24
+ getSnippet(connection, lang) {
25
+ return `# PostgreSQL snippet generation not implemented yet`;
26
+ }
27
+ }
28
+ exports.PostgreSQLConnector = PostgreSQLConnector;
@@ -0,0 +1,9 @@
1
+ import { Connector, Table, TableData } from '../index';
2
+ import { Connection } from '../../connections';
3
+ export declare class ShopifyConnector implements Connector {
4
+ type: string;
5
+ test(connection: Connection): Promise<boolean>;
6
+ getTables(connection: Connection): Promise<Table[]>;
7
+ getData(connection: Connection, tableName: string, page: number, limit: number): Promise<TableData>;
8
+ getSnippet(connection: Connection, lang: string): string;
9
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ShopifyConnector = void 0;
4
+ class ShopifyConnector {
5
+ constructor() {
6
+ this.type = 'shopify';
7
+ }
8
+ async test(connection) {
9
+ if (!connection.store || !connection.apiKey) {
10
+ throw new Error('Store URL and API Key are required');
11
+ }
12
+ return true;
13
+ }
14
+ async getTables(connection) {
15
+ return [];
16
+ }
17
+ async getData(connection, tableName, page, limit) {
18
+ return {
19
+ columns: [],
20
+ rows: [],
21
+ pagination: { page, limit, totalRows: 0, totalPages: 0, startIdx: 0, endIdx: 0 }
22
+ };
23
+ }
24
+ getSnippet(connection, lang) {
25
+ return `# Shopify snippet generation not implemented yet`;
26
+ }
27
+ }
28
+ exports.ShopifyConnector = ShopifyConnector;
package/dist/index.js CHANGED
@@ -1,13 +1,48 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
3
36
  Object.defineProperty(exports, "__esModule", { value: true });
4
37
  const commander_1 = require("commander");
5
38
  const commands_1 = require("./commands");
39
+ const server_1 = require("./server");
40
+ const connections_1 = require("./connections");
6
41
  const program = new commander_1.Command();
7
42
  program
8
43
  .name('crushdataai')
9
44
  .description('CLI to install CrushData AI data analyst skill for AI coding assistants')
10
- .version('1.0.0');
45
+ .version('1.2.1');
11
46
  program
12
47
  .command('init')
13
48
  .description('Initialize CrushData AI skill in current project')
@@ -28,4 +63,59 @@ program
28
63
  .action(() => {
29
64
  (0, commands_1.versions)();
30
65
  });
66
+ program
67
+ .command('connect')
68
+ .description('Open connection manager UI to add/manage data sources')
69
+ .option('-p, --port <port>', 'Server port', '4321')
70
+ .action(async (options) => {
71
+ const port = parseInt(options.port);
72
+ console.log('\nšŸ”Œ Starting CrushData AI Connection Manager...\n');
73
+ try {
74
+ await (0, server_1.startServer)(port);
75
+ // Open browser
76
+ const open = (await Promise.resolve().then(() => __importStar(require('open')))).default;
77
+ await open(`http://localhost:${port}`);
78
+ }
79
+ catch (error) {
80
+ console.error(`āŒ Error: ${error.message}`);
81
+ process.exit(1);
82
+ }
83
+ });
84
+ program
85
+ .command('connections')
86
+ .description('List saved data source connections')
87
+ .action(() => {
88
+ const connections = (0, connections_1.listConnections)();
89
+ if (connections.length === 0) {
90
+ console.log('\nšŸ“ No saved connections.');
91
+ console.log(' Run `crushdataai connect` to add one.\n');
92
+ return;
93
+ }
94
+ console.log('\nšŸ“ Saved Connections:\n');
95
+ connections.forEach(conn => {
96
+ console.log(` ${conn.name}`);
97
+ console.log(` └─ Type: ${conn.type} | Host: ${conn.host || 'local'}`);
98
+ console.log(` └─ Created: ${conn.createdAt}\n`);
99
+ });
100
+ });
101
+ program
102
+ .command('connections:delete <name>')
103
+ .description('Delete a saved connection')
104
+ .action((name) => {
105
+ const deleted = (0, connections_1.deleteConnection)(name);
106
+ if (deleted) {
107
+ console.log(`\nāœ“ Connection "${name}" deleted.\n`);
108
+ }
109
+ else {
110
+ console.log(`\nāœ— Connection "${name}" not found.\n`);
111
+ }
112
+ });
113
+ program
114
+ .command('snippet <name>')
115
+ .description('Get connection code snippet for AI to use')
116
+ .option('-l, --lang <lang>', 'Target language (currently python)', 'python')
117
+ .action(async (name, options) => {
118
+ const { snippet } = await Promise.resolve().then(() => __importStar(require('./commands/snippet')));
119
+ await snippet(name, options.lang);
120
+ });
31
121
  program.parse();
@@ -0,0 +1,2 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = __importDefault(require("express"));
7
+ const connections_1 = require("../connections");
8
+ const connectors_1 = require("../connectors");
9
+ const router = express_1.default.Router();
10
+ // List connections
11
+ router.get('/', (_req, res) => {
12
+ try {
13
+ const connections = (0, connections_1.listConnections)();
14
+ res.json({ success: true, connections });
15
+ }
16
+ catch (error) {
17
+ res.status(500).json({ success: false, error: 'Failed to load connections' });
18
+ }
19
+ });
20
+ // Get connection details
21
+ router.get('/:name', (req, res) => {
22
+ try {
23
+ const connection = (0, connections_1.getConnection)(req.params.name);
24
+ if (!connection) {
25
+ res.status(404).json({ success: false, error: 'Connection not found' });
26
+ return;
27
+ }
28
+ // Remove sensitive fields
29
+ const safe = { ...connection, password: undefined, apiKey: undefined, apiSecret: undefined };
30
+ res.json({ success: true, connection: safe });
31
+ }
32
+ catch (error) {
33
+ res.status(500).json({ success: false, error: 'Failed to get connection' });
34
+ }
35
+ });
36
+ // Save connection
37
+ router.post('/', (req, res) => {
38
+ try {
39
+ const connection = {
40
+ ...req.body,
41
+ createdAt: req.body.createdAt || new Date().toISOString(),
42
+ updatedAt: new Date().toISOString()
43
+ };
44
+ if (!connection.name || !connection.type) {
45
+ res.status(400).json({ success: false, error: 'Name and type are required' });
46
+ return;
47
+ }
48
+ (0, connections_1.saveConnection)(connection);
49
+ res.json({ success: true, message: 'Connection saved' });
50
+ }
51
+ catch (error) {
52
+ res.status(500).json({ success: false, error: 'Failed to save connection' });
53
+ }
54
+ });
55
+ // Delete connection
56
+ router.delete('/:name', (req, res) => {
57
+ try {
58
+ const deleted = (0, connections_1.deleteConnection)(req.params.name);
59
+ if (deleted) {
60
+ res.json({ success: true, message: 'Connection deleted' });
61
+ }
62
+ else {
63
+ res.status(404).json({ success: false, error: 'Connection not found' });
64
+ }
65
+ }
66
+ catch (error) {
67
+ res.status(500).json({ success: false, error: 'Failed to delete connection' });
68
+ }
69
+ });
70
+ // Test connection
71
+ router.post('/test', async (req, res) => {
72
+ try {
73
+ const connection = req.body;
74
+ // Use registry to test
75
+ try {
76
+ const connector = connectors_1.ConnectorRegistry.get(connection.type);
77
+ await connector.test(connection);
78
+ res.json({ success: true, message: 'Connection valid' });
79
+ }
80
+ catch (err) {
81
+ res.json({ success: false, error: err.message || 'Unknown connector type' });
82
+ }
83
+ }
84
+ catch (error) {
85
+ res.status(500).json({ success: false, error: 'Connection test failed: ' + error.message });
86
+ }
87
+ });
88
+ // Get tables
89
+ router.get('/:name/tables', async (req, res) => {
90
+ try {
91
+ const connection = (0, connections_1.getConnection)(req.params.name);
92
+ if (!connection) {
93
+ res.status(404).json({ success: false, error: 'Connection not found' });
94
+ return;
95
+ }
96
+ const connector = connectors_1.ConnectorRegistry.get(connection.type);
97
+ const tables = await connector.getTables(connection);
98
+ res.json({ success: true, tables });
99
+ }
100
+ catch (error) {
101
+ res.status(500).json({ success: false, error: 'Failed to get tables: ' + error.message });
102
+ }
103
+ });
104
+ // Get table data
105
+ router.get('/:name/tables/:table/data', async (req, res) => {
106
+ try {
107
+ const connection = (0, connections_1.getConnection)(req.params.name);
108
+ if (!connection) {
109
+ res.status(404).json({ success: false, error: 'Connection not found' });
110
+ return;
111
+ }
112
+ const page = parseInt(req.query.page) || 1;
113
+ const limit = parseInt(req.query.limit) || 25;
114
+ const tableName = req.params.table;
115
+ const connector = connectors_1.ConnectorRegistry.get(connection.type);
116
+ const result = await connector.getData(connection, tableName, page, limit);
117
+ res.json({ success: true, ...result });
118
+ }
119
+ catch (error) {
120
+ console.error('Error in getData:', error);
121
+ res.status(500).json({ success: false, error: 'Failed to get table data: ' + error.message });
122
+ }
123
+ });
124
+ exports.default = router;
@@ -0,0 +1 @@
1
+ export declare function startServer(port?: number): Promise<void>;
package/dist/server.js ADDED
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.startServer = startServer;
40
+ const express_1 = __importDefault(require("express"));
41
+ const path = __importStar(require("path"));
42
+ const connectors_1 = require("./connectors");
43
+ const csv_1 = require("./connectors/csv");
44
+ const mysql_1 = require("./connectors/mysql");
45
+ const postgresql_1 = require("./connectors/postgresql");
46
+ const shopify_1 = require("./connectors/shopify");
47
+ const cloud_1 = require("./connectors/cloud");
48
+ const connections_1 = __importDefault(require("./routes/connections"));
49
+ const app = (0, express_1.default)();
50
+ app.use(express_1.default.json());
51
+ // Request logger
52
+ app.use((req, res, next) => {
53
+ console.log(`${req.method} ${req.url}`);
54
+ next();
55
+ });
56
+ // Initialize Connectors
57
+ connectors_1.ConnectorRegistry.register(new csv_1.CSVConnector());
58
+ connectors_1.ConnectorRegistry.register(new mysql_1.MySQLConnector());
59
+ connectors_1.ConnectorRegistry.register(new postgresql_1.PostgreSQLConnector());
60
+ connectors_1.ConnectorRegistry.register(new shopify_1.ShopifyConnector());
61
+ connectors_1.ConnectorRegistry.register(new cloud_1.BigQueryConnector());
62
+ connectors_1.ConnectorRegistry.register(new cloud_1.SnowflakeConnector());
63
+ // Serve static files from ui directory
64
+ const uiPath = path.join(__dirname, '..', 'ui');
65
+ app.use(express_1.default.static(uiPath));
66
+ // API Routes
67
+ app.use('/api/connections', connections_1.default);
68
+ // API: Health check
69
+ app.get('/api/health', (_req, res) => {
70
+ res.json({ status: 'ok', version: '2.0.0' });
71
+ });
72
+ // Serve index.html for root
73
+ app.get('/', (_req, res) => {
74
+ res.sendFile(path.join(uiPath, 'index.html'));
75
+ });
76
+ function startServer(port = 4321) {
77
+ return new Promise((resolve, reject) => {
78
+ try {
79
+ const server = app.listen(port, () => {
80
+ console.log(`\nšŸš€ CrushData AI Connection Manager`);
81
+ console.log(` Server running at: http://localhost:${port}`);
82
+ console.log(` Press Ctrl+C to stop\n`);
83
+ resolve();
84
+ });
85
+ server.on('error', (err) => {
86
+ if (err.code === 'EADDRINUSE') {
87
+ reject(new Error(`Port ${port} is already in use`));
88
+ }
89
+ else {
90
+ reject(err);
91
+ }
92
+ });
93
+ }
94
+ catch (error) {
95
+ reject(error);
96
+ }
97
+ });
98
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crushdataai",
3
- "version": "1.0.0",
3
+ "version": "1.2.1",
4
4
  "description": "CLI to install CrushData AI data analyst skill for AI coding assistants",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -23,20 +23,26 @@
23
23
  "author": "",
24
24
  "license": "Apache-2.0",
25
25
  "devDependencies": {
26
+ "@types/express": "^4.17.21",
26
27
  "@types/fs-extra": "^11.0.4",
27
28
  "@types/node": "^20.10.0",
29
+ "@types/papaparse": "^5.5.2",
28
30
  "typescript": "^5.3.0"
29
31
  },
30
32
  "dependencies": {
31
33
  "commander": "^11.1.0",
32
- "fs-extra": "^11.2.0"
34
+ "express": "^4.18.2",
35
+ "fs-extra": "^11.2.0",
36
+ "open": "^10.0.0",
37
+ "papaparse": "^5.5.3"
33
38
  },
34
39
  "engines": {
35
40
  "node": ">=18.0.0"
36
41
  },
37
42
  "files": [
38
43
  "dist",
39
- "assets"
44
+ "assets",
45
+ "ui"
40
46
  ],
41
47
  "repository": {
42
48
  "type": "git",
Binary file
package/ui/favicon.svg ADDED
@@ -0,0 +1,19 @@
1
+ <svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <linearGradient id="bg-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" stop-color="#9333EA"/>
5
+ <stop offset="100%" stop-color="#7C3AED"/>
6
+ </linearGradient>
7
+ </defs>
8
+ <!-- Rounded rectangle background -->
9
+ <rect width="512" height="512" rx="108" fill="url(#bg-gradient)"/>
10
+ <!-- Bar chart icon -->
11
+ <g fill="white">
12
+ <!-- Left bar (shortest) -->
13
+ <rect x="120" y="280" width="56" height="112" rx="12"/>
14
+ <!-- Middle bar (tallest) -->
15
+ <rect x="228" y="120" width="56" height="272" rx="12"/>
16
+ <!-- Right bar (medium) -->
17
+ <rect x="336" y="200" width="56" height="192" rx="12"/>
18
+ </g>
19
+ </svg>