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.
- package/assets/antigravity/data-analyst.md +7 -0
- package/assets/claude/SKILL.md +8 -0
- package/assets/copilot/data-analyst.prompt.md +8 -1
- package/assets/cursor/data-analyst.md +7 -0
- package/assets/kiro/data-analyst.md +8 -1
- package/assets/windsurf/data-analyst.md +8 -1
- package/dist/commands/snippet.d.ts +1 -0
- package/dist/commands/snippet.js +26 -0
- package/dist/commands.js +4 -4
- package/dist/connections.d.ts +37 -0
- package/dist/connections.js +176 -0
- package/dist/connectors/cloud/index.d.ts +16 -0
- package/dist/connectors/cloud/index.js +39 -0
- package/dist/connectors/csv/index.d.ts +9 -0
- package/dist/connectors/csv/index.js +135 -0
- package/dist/connectors/index.d.ts +30 -0
- package/dist/connectors/index.js +17 -0
- package/dist/connectors/mysql/index.d.ts +9 -0
- package/dist/connectors/mysql/index.js +29 -0
- package/dist/connectors/postgresql/index.d.ts +9 -0
- package/dist/connectors/postgresql/index.js +28 -0
- package/dist/connectors/shopify/index.d.ts +9 -0
- package/dist/connectors/shopify/index.js +28 -0
- package/dist/index.js +91 -1
- package/dist/routes/connections.d.ts +2 -0
- package/dist/routes/connections.js +124 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +98 -0
- package/package.json +9 -3
- package/ui/favicon-32x32.png +0 -0
- package/ui/favicon.svg +19 -0
- package/ui/index.html +341 -0
- package/ui/main.js +542 -0
- package/ui/styles.css +680 -0
|
@@ -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.
|
|
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,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;
|
package/dist/server.d.ts
ADDED
|
@@ -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.
|
|
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
|
-
"
|
|
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>
|