@descix/cli 1.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.
- package/README.md +95 -0
- package/SERVICE_README_sdk.md +399 -0
- package/agent-assets/guides/README.md +61 -0
- package/agent-assets/guides/dynamic-site-pattern.md +125 -0
- package/agent-assets/guides/knowledge-only-pattern.md +93 -0
- package/agent-assets/guides/microservice-pattern.md +152 -0
- package/agent-assets/guides/static-site-pattern.md +111 -0
- package/agent-assets/instructions/app-asset-validation.md +477 -0
- package/agent-assets/instructions/onboarding-flow.md +408 -0
- package/agent-assets/instructions/standard-folder-structure.md +125 -0
- package/agent-assets/reference/app-creation.md +381 -0
- package/agent-assets/reference/architecture.md +406 -0
- package/agent-assets/reference/local-dev.md +138 -0
- package/agent-assets/reference/mcp-integration.md +424 -0
- package/agent-assets/reference/workspace-config.md +415 -0
- package/agent-assets/rules/descix_mcp.template.mdc +243 -0
- package/bin/descix.js +3930 -0
- package/bin/mcp-server.js +382 -0
- package/descix-cli-1.0.0.tgz +0 -0
- package/lib/agent-files.js +162 -0
- package/lib/api-client.js +458 -0
- package/lib/auth-guard.js +67 -0
- package/lib/commands/app-wizard.js +627 -0
- package/lib/commands/auth.js +407 -0
- package/lib/commands/buy.js +207 -0
- package/lib/commands/clone.js +91 -0
- package/lib/commands/config.js +155 -0
- package/lib/commands/doctor.js +277 -0
- package/lib/commands/folder.js +291 -0
- package/lib/commands/init.js +257 -0
- package/lib/commands/kb.js +654 -0
- package/lib/commands/mcp.js +273 -0
- package/lib/commands/serve.js +12 -0
- package/lib/commands/status.js +239 -0
- package/lib/commands/update.js +653 -0
- package/lib/core/Chunker.js +610 -0
- package/lib/core/Hydrator.js +801 -0
- package/lib/core/PathContext.js +335 -0
- package/lib/core/Syncer.js +310 -0
- package/lib/core/index.js +32 -0
- package/lib/global-config.js +86 -0
- package/lib/google-storage-adc.js +511 -0
- package/lib/wallet-file.js +232 -0
- package/lib/wizard/setup.js +502 -0
- package/lib/workspace-config.js +712 -0
- package/lib/workspace-utils.js +126 -0
- package/package.json +41 -0
- package/templates/agent-claude.md +226 -0
- package/templates/agent-cline.md +133 -0
- package/templates/agent-copilot.md +133 -0
- package/templates/agent-cursor.md +133 -0
- package/templates/descix_mcp.mdc +122 -0
- package/templates/drive/README.md +42 -0
- package/templates/drive/app/assets/app_description.md +13 -0
- package/templates/drive/app/assets/icon.png +0 -0
- package/templates/drive/app/assets/system_instructions.md +17 -0
- package/templates/drive/app/kb/General/README.md +25 -0
- package/templates/drive/community/Apps/.gitkeep +4 -0
- package/templates/drive/community/community_assets/community_description.md +15 -0
- package/templates/drive/community/community_assets/icon.png +0 -0
- package/templates/drive_templates/README.md +104 -0
- package/templates/drive_templates/agent_app_template/assets/app_description.txt +13 -0
- package/templates/drive_templates/agent_app_template/assets/system_instructions.txt +17 -0
- package/templates/drive_templates/agent_app_template/kb/General/README.md +25 -0
- package/templates/drive_templates/agent_app_template/microservice/.gitkeep +10 -0
- package/templates/drive_templates/agent_app_template/site/.gitkeep +4 -0
- package/templates/drive_templates/community_template/Apps/.gitkeep +4 -0
- package/templates/drive_templates/community_template/community_assets/community_description.txt +15 -0
- package/templates/scaffolds/README.md +62 -0
- package/templates/scaffolds/microservice/Dockerfile +19 -0
- package/templates/scaffolds/microservice/SERVICE_README_sdk.md +399 -0
- package/templates/scaffolds/microservice/app.js +50 -0
- package/templates/scaffolds/microservice/app.yaml +8 -0
- package/templates/scaffolds/microservice/defaults-config.json +5 -0
- package/templates/scaffolds/microservice/dev-overrides.json.example +5 -0
- package/templates/scaffolds/microservice/manifest.json +49 -0
- package/templates/scaffolds/microservice/package-lock.json +2645 -0
- package/templates/scaffolds/microservice/package.json +29 -0
- package/templates/scaffolds/microservice/scripts/register.js +55 -0
- package/templates/scaffolds/microservice/services/apiFront.js +75 -0
- package/templates/scaffolds/microservice/services/commandHandlers/sampleCommands.js +57 -0
- package/templates/scaffolds/microservice/services/mcpClient.js +78 -0
- package/templates/scaffolds/microservice/services/utils.js +247 -0
- package/templates/scaffolds/microservice/setup-schema.json +18 -0
- package/templates/scaffolds/microservice/templates/SERVICE_README_TEMPLATE.md +143 -0
- package/templates/scaffolds/site/DeSciXAppSDK.js +62 -0
- package/templates/scaffolds/site/README.md +51 -0
- package/templates/scaffolds/site/app.js +22 -0
- package/templates/scaffolds/site/index.html +42 -0
- package/templates/scaffolds/site/styles.css +123 -0
- package/test-hydration.js +150 -0
- package/vendor/mcp/transports/http-sse-transport.js +196 -0
- package/vendor/mcp/transports/index.js +15 -0
- package/vendor/mcp/transports/stdio-transport.js +118 -0
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive Setup Wizard
|
|
3
|
+
*
|
|
4
|
+
* Bootstraps MCP connectivity so the AI agent can guide workspace configuration.
|
|
5
|
+
*
|
|
6
|
+
* Steps:
|
|
7
|
+
* 0. API Configuration (select environment)
|
|
8
|
+
* 1. Authentication (device login or wallet)
|
|
9
|
+
* 2. Fetch Entitlements (communities/apps user owns)
|
|
10
|
+
* 3. Pull SDK Agent Assets (instructions, templates, rules)
|
|
11
|
+
* 4. MCP Configuration (mcp.json + rules file with entitlements)
|
|
12
|
+
* 5. Create workspace.json (with _needsAgentSetup flag)
|
|
13
|
+
* 6. Register SDK Service (vectorize for tell_me_how)
|
|
14
|
+
*
|
|
15
|
+
* After setup, the AI agent uses the rules file and local SDK assets
|
|
16
|
+
* to help the user map folders to apps and configure workspace.json.
|
|
17
|
+
*
|
|
18
|
+
* All operations use HTTP API client - no service imports
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import chalk from 'chalk';
|
|
22
|
+
import ora from 'ora';
|
|
23
|
+
import inquirer from 'inquirer';
|
|
24
|
+
import { DeSciXApiClient } from '../api-client.js';
|
|
25
|
+
import { requireAuth, isAuthenticated } from '../auth-guard.js';
|
|
26
|
+
import * as authCommands from '../commands/auth.js';
|
|
27
|
+
import * as fs from 'fs/promises';
|
|
28
|
+
import * as path from 'path';
|
|
29
|
+
import { fileURLToPath } from 'url';
|
|
30
|
+
import { dirname } from 'path';
|
|
31
|
+
|
|
32
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
33
|
+
const __dirname = dirname(__filename);
|
|
34
|
+
|
|
35
|
+
// SDK version for tracking
|
|
36
|
+
const SDK_VERSION = '2.0.0';
|
|
37
|
+
|
|
38
|
+
// ============ Helper Functions ============
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Copy directory recursively
|
|
42
|
+
* @param {string} src - Source directory
|
|
43
|
+
* @param {string} dest - Destination directory
|
|
44
|
+
*/
|
|
45
|
+
async function copyDir(src, dest) {
|
|
46
|
+
await fs.mkdir(dest, { recursive: true });
|
|
47
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
48
|
+
|
|
49
|
+
for (const entry of entries) {
|
|
50
|
+
const srcPath = path.join(src, entry.name);
|
|
51
|
+
const destPath = path.join(dest, entry.name);
|
|
52
|
+
|
|
53
|
+
if (entry.isDirectory()) {
|
|
54
|
+
await copyDir(srcPath, destPath);
|
|
55
|
+
} else {
|
|
56
|
+
await fs.copyFile(srcPath, destPath);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Pull SDK agent assets to local workspace
|
|
63
|
+
* Copies agent-assets/ to .descix/sdk-assets/ for local AI agent access
|
|
64
|
+
* @param {string} workspacePath - Workspace root path
|
|
65
|
+
* @returns {Promise<boolean>} True if assets were copied
|
|
66
|
+
*/
|
|
67
|
+
async function pullSdkAssets(workspacePath) {
|
|
68
|
+
// agent-assets is in the SDK root, which is ../../.. from wizard/setup.js
|
|
69
|
+
const sdkAssetsSource = path.join(__dirname, '../../../agent-assets');
|
|
70
|
+
const sdkAssetsTarget = path.join(workspacePath, '.descix/sdk-assets');
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
// Check if source exists
|
|
74
|
+
await fs.access(sdkAssetsSource);
|
|
75
|
+
|
|
76
|
+
// Copy recursively
|
|
77
|
+
await copyDir(sdkAssetsSource, sdkAssetsTarget);
|
|
78
|
+
|
|
79
|
+
return true;
|
|
80
|
+
} catch (error) {
|
|
81
|
+
// Source doesn't exist (development mode or not packaged)
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Generate customized rules file from template
|
|
88
|
+
* Uses agent-assets/rules/descix_mcp.template.mdc with placeholder substitution
|
|
89
|
+
* @param {string} workspacePath - Workspace root path
|
|
90
|
+
* @param {Object} entitlements - User's entitlements from fetch_my_purchases
|
|
91
|
+
* @param {string} primaryCommunity - User's primary community
|
|
92
|
+
* @returns {Promise<boolean>} True if rules file was generated
|
|
93
|
+
*/
|
|
94
|
+
async function generateRulesFile(workspacePath, entitlements, primaryCommunity) {
|
|
95
|
+
const templatePath = path.join(__dirname, '../../../agent-assets/rules/descix_mcp.template.mdc');
|
|
96
|
+
const rulesDir = path.join(workspacePath, '.cursor/rules');
|
|
97
|
+
const rulesPath = path.join(rulesDir, 'descix_mcp.mdc');
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
// Read template
|
|
101
|
+
const template = await fs.readFile(templatePath, 'utf-8');
|
|
102
|
+
|
|
103
|
+
// Summarize entitlements for embedding (avoid huge JSON in rules file)
|
|
104
|
+
const entitlementsSummary = {
|
|
105
|
+
communities: (entitlements.communities || []).map(c => ({
|
|
106
|
+
id: c.community_id || c.id,
|
|
107
|
+
name: c.community_name || c.name
|
|
108
|
+
})),
|
|
109
|
+
apps: (entitlements.apps || []).map(a => ({
|
|
110
|
+
community: a.community_id,
|
|
111
|
+
id: a.app_id || a.id,
|
|
112
|
+
name: a.app_name || a.name
|
|
113
|
+
}))
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Customize with workspace-specific values
|
|
117
|
+
const customized = template
|
|
118
|
+
.replace(/\{\{SDK_ASSETS_PATH\}\}/g, '.descix/sdk-assets')
|
|
119
|
+
.replace(/\{\{PRIMARY_COMMUNITY\}\}/g, primaryCommunity || 'descix')
|
|
120
|
+
.replace(/\{\{ENTITLEMENTS_JSON\}\}/g, JSON.stringify(entitlementsSummary, null, 2))
|
|
121
|
+
.replace(/\{\{SDK_VERSION\}\}/g, SDK_VERSION)
|
|
122
|
+
.replace(/\{\{WORKSPACE_PATH\}\}/g, workspacePath);
|
|
123
|
+
|
|
124
|
+
// Write customized rules
|
|
125
|
+
await fs.mkdir(rulesDir, { recursive: true });
|
|
126
|
+
await fs.writeFile(rulesPath, customized, 'utf-8');
|
|
127
|
+
|
|
128
|
+
return true;
|
|
129
|
+
} catch (error) {
|
|
130
|
+
// Template doesn't exist, fall back to simple template
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Auto-register SDK service for tell_me_how discovery
|
|
137
|
+
* Vectorizes SERVICE_README_sdk.md so SDK tools are discoverable
|
|
138
|
+
* @param {DeSciXApiClient} apiClient - Authenticated API client
|
|
139
|
+
* @returns {Promise<boolean>} True if registration succeeded
|
|
140
|
+
*/
|
|
141
|
+
async function autoRegisterSdkService(apiClient) {
|
|
142
|
+
// SDK SERVICE_README is in the SDK root
|
|
143
|
+
const readmePath = path.join(__dirname, '../../../SERVICE_README_sdk.md');
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const readmeContent = await fs.readFile(readmePath, 'utf-8');
|
|
147
|
+
|
|
148
|
+
// Vectorize for tell_me_how discovery
|
|
149
|
+
await apiClient.invoke('vectorize_service_readme', {
|
|
150
|
+
service_name: 'sdk',
|
|
151
|
+
community_id: 'descix',
|
|
152
|
+
app_id: 'docs',
|
|
153
|
+
readme_content: readmeContent
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
return true;
|
|
157
|
+
} catch (error) {
|
|
158
|
+
// README doesn't exist or vectorization failed
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get MCP server configuration
|
|
165
|
+
* Uses direct command if CLI is installed, otherwise suggests install
|
|
166
|
+
* @returns {Object} { command, args } for MCP server
|
|
167
|
+
*/
|
|
168
|
+
function getMcpServerConfig() {
|
|
169
|
+
// Use direct descix command - simpler and no npm download needed
|
|
170
|
+
// Requires CLI to be installed globally first via:
|
|
171
|
+
// npm install -g https://app.descix.net/sdk/descix-cli-1.0.0.tgz
|
|
172
|
+
// or during development:
|
|
173
|
+
// npm install -g /path/to/descix-cli-1.0.0.tgz
|
|
174
|
+
return {
|
|
175
|
+
command: 'descix',
|
|
176
|
+
args: ['mcp-serve'],
|
|
177
|
+
type: 'global'
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ============ Main Wizard ============
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Run the interactive setup wizard
|
|
185
|
+
*/
|
|
186
|
+
export async function runSetupWizard(options = {}) {
|
|
187
|
+
console.log(chalk.cyan('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
188
|
+
console.log(chalk.cyan('ā Welcome to DeSciX CLI/MCP Setup ā'));
|
|
189
|
+
console.log(chalk.cyan('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤'));
|
|
190
|
+
console.log(chalk.cyan('ā This wizard will: ā'));
|
|
191
|
+
console.log(chalk.cyan('ā 1. Configure API endpoint ā'));
|
|
192
|
+
console.log(chalk.cyan('ā 2. Authenticate with DeSciX (required) ā'));
|
|
193
|
+
console.log(chalk.cyan('ā 3. Fetch your entitlements ā'));
|
|
194
|
+
console.log(chalk.cyan('ā 4. Pull SDK agent assets locally ā'));
|
|
195
|
+
console.log(chalk.cyan('ā 5. Configure Cursor MCP integration ā'));
|
|
196
|
+
console.log(chalk.cyan('ā 6. Register SDK for tool discovery ā'));
|
|
197
|
+
console.log(chalk.cyan('ā ā'));
|
|
198
|
+
console.log(chalk.cyan('ā After setup, the AI agent will help you ā'));
|
|
199
|
+
console.log(chalk.cyan('ā configure your workspace folders. ā'));
|
|
200
|
+
console.log(chalk.cyan('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
201
|
+
|
|
202
|
+
const workspaceRoot = process.cwd();
|
|
203
|
+
const spinner = ora('Initializing...').start();
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
// Step 0: Configure API endpoint
|
|
207
|
+
spinner.stop();
|
|
208
|
+
console.log(chalk.cyan('\nš Step 0: API Configuration\n'));
|
|
209
|
+
|
|
210
|
+
let apiUrl = options.url || process.env.DESCIX_API_URL;
|
|
211
|
+
|
|
212
|
+
if (!apiUrl) {
|
|
213
|
+
const { environment } = await inquirer.prompt([
|
|
214
|
+
{
|
|
215
|
+
type: 'list',
|
|
216
|
+
name: 'environment',
|
|
217
|
+
message: 'Which environment are you connecting to?',
|
|
218
|
+
choices: [
|
|
219
|
+
{ name: 'Production (app.descix.net)', value: 'production' },
|
|
220
|
+
{ name: 'Local Development (localhost:4000)', value: 'local' },
|
|
221
|
+
{ name: 'Custom URL', value: 'custom' }
|
|
222
|
+
],
|
|
223
|
+
default: 'production'
|
|
224
|
+
}
|
|
225
|
+
]);
|
|
226
|
+
|
|
227
|
+
if (environment === 'production') {
|
|
228
|
+
apiUrl = 'https://descix.net';
|
|
229
|
+
} else if (environment === 'local') {
|
|
230
|
+
apiUrl = 'https://localhost:4000';
|
|
231
|
+
} else {
|
|
232
|
+
const { customUrl } = await inquirer.prompt([
|
|
233
|
+
{
|
|
234
|
+
type: 'input',
|
|
235
|
+
name: 'customUrl',
|
|
236
|
+
message: 'Enter API URL:',
|
|
237
|
+
default: 'https://localhost:4000',
|
|
238
|
+
validate: (input) => {
|
|
239
|
+
if (!input.startsWith('http://') && !input.startsWith('https://')) {
|
|
240
|
+
return 'URL must start with http:// or https://';
|
|
241
|
+
}
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
]);
|
|
246
|
+
apiUrl = customUrl;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
console.log(chalk.green(`ā API endpoint: ${apiUrl}\n`));
|
|
251
|
+
|
|
252
|
+
spinner.start('Connecting to DeSciX...');
|
|
253
|
+
const apiClient = new DeSciXApiClient({ baseUrl: apiUrl });
|
|
254
|
+
spinner.succeed('Connected to DeSciX');
|
|
255
|
+
|
|
256
|
+
// Step 1: Authentication (required)
|
|
257
|
+
console.log(chalk.cyan('\nš Step 1: Authentication\n'));
|
|
258
|
+
|
|
259
|
+
// Pass the API URL to login commands
|
|
260
|
+
const authOptions = { url: apiUrl };
|
|
261
|
+
|
|
262
|
+
const isAuth = await isAuthenticated(apiClient);
|
|
263
|
+
|
|
264
|
+
if (!isAuth) {
|
|
265
|
+
console.log(chalk.yellow('ā ļø Authentication is required to use DeSciX CLI/MCP.\n'));
|
|
266
|
+
|
|
267
|
+
const { authMethod } = await inquirer.prompt([
|
|
268
|
+
{
|
|
269
|
+
type: 'list',
|
|
270
|
+
name: 'authMethod',
|
|
271
|
+
message: 'How would you like to authenticate?',
|
|
272
|
+
choices: [
|
|
273
|
+
{ name: 'Device Login (recommended - opens browser)', value: 'device' },
|
|
274
|
+
{ name: 'Direct Wallet Connection (advanced)', value: 'wallet' }
|
|
275
|
+
],
|
|
276
|
+
default: 'device'
|
|
277
|
+
}
|
|
278
|
+
]);
|
|
279
|
+
|
|
280
|
+
if (authMethod === 'device') {
|
|
281
|
+
await authCommands.loginDevice(authOptions);
|
|
282
|
+
} else {
|
|
283
|
+
await authCommands.loginWallet();
|
|
284
|
+
}
|
|
285
|
+
} else {
|
|
286
|
+
console.log(chalk.green('ā
Already authenticated\n'));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Verify authentication
|
|
290
|
+
await requireAuth(apiClient);
|
|
291
|
+
console.log(chalk.green('ā
Authentication verified\n'));
|
|
292
|
+
|
|
293
|
+
// Step 2: Fetch Entitlements
|
|
294
|
+
console.log(chalk.cyan('\nš Step 2: Fetching Entitlements\n'));
|
|
295
|
+
|
|
296
|
+
let entitlements = { communities: [], apps: [], service_slots: [] };
|
|
297
|
+
spinner.start('Fetching your entitlements...');
|
|
298
|
+
|
|
299
|
+
try {
|
|
300
|
+
const purchasesResult = await apiClient.invoke('fetch_my_purchases', {});
|
|
301
|
+
if (purchasesResult && purchasesResult.status !== 'ERROR') {
|
|
302
|
+
entitlements = {
|
|
303
|
+
communities: purchasesResult.communities || [],
|
|
304
|
+
apps: purchasesResult.apps || [],
|
|
305
|
+
service_slots: purchasesResult.service_slots || []
|
|
306
|
+
};
|
|
307
|
+
spinner.succeed(`Found ${entitlements.communities.length} communities, ${entitlements.apps.length} apps`);
|
|
308
|
+
|
|
309
|
+
// Display entitlements
|
|
310
|
+
if (entitlements.communities.length > 0) {
|
|
311
|
+
console.log(chalk.gray('\n Communities:'));
|
|
312
|
+
for (const c of entitlements.communities) {
|
|
313
|
+
console.log(chalk.gray(` - ${c.community_name || c.name || c.community_id} (${c.community_id || c.id})`));
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (entitlements.apps.length > 0) {
|
|
317
|
+
console.log(chalk.gray('\n Apps:'));
|
|
318
|
+
for (const a of entitlements.apps.slice(0, 5)) {
|
|
319
|
+
console.log(chalk.gray(` - ${a.community_id}/${a.app_id || a.id}`));
|
|
320
|
+
}
|
|
321
|
+
if (entitlements.apps.length > 5) {
|
|
322
|
+
console.log(chalk.gray(` ... and ${entitlements.apps.length - 5} more`));
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
console.log('');
|
|
326
|
+
} else {
|
|
327
|
+
spinner.warn('Could not fetch entitlements (will use defaults)');
|
|
328
|
+
}
|
|
329
|
+
} catch (error) {
|
|
330
|
+
spinner.warn('Could not fetch entitlements: ' + error.message);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Step 3: Pull SDK Assets
|
|
334
|
+
console.log(chalk.cyan('\nš Step 3: Pulling SDK Agent Assets\n'));
|
|
335
|
+
|
|
336
|
+
spinner.start('Pulling SDK agent assets...');
|
|
337
|
+
const assetsPulled = await pullSdkAssets(workspaceRoot);
|
|
338
|
+
|
|
339
|
+
if (assetsPulled) {
|
|
340
|
+
spinner.succeed('SDK agent assets pulled');
|
|
341
|
+
console.log(chalk.gray(' Created: .descix/sdk-assets/'));
|
|
342
|
+
console.log(chalk.gray(' - instructions/ (onboarding, packaging types, etc.)'));
|
|
343
|
+
console.log(chalk.gray(' - templates/ (app scaffolds)'));
|
|
344
|
+
console.log(chalk.gray(' - rules/ (agent instructions template)\n'));
|
|
345
|
+
} else {
|
|
346
|
+
spinner.warn('SDK agent assets not found (development mode)');
|
|
347
|
+
console.log(chalk.gray(' Skipped: .descix/sdk-assets/\n'));
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Derive primary community from entitlements
|
|
351
|
+
let primaryCommunity = 'descix';
|
|
352
|
+
if (entitlements.communities.length > 0) {
|
|
353
|
+
primaryCommunity = entitlements.communities[0].community_id || entitlements.communities[0].id || 'descix';
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Step 4: MCP Configuration
|
|
357
|
+
console.log(chalk.cyan('\nš Step 4: MCP Configuration\n'));
|
|
358
|
+
|
|
359
|
+
const { setupMCP } = await inquirer.prompt([
|
|
360
|
+
{
|
|
361
|
+
type: 'confirm',
|
|
362
|
+
name: 'setupMCP',
|
|
363
|
+
message: 'Set up Cursor MCP integration?',
|
|
364
|
+
default: true
|
|
365
|
+
}
|
|
366
|
+
]);
|
|
367
|
+
|
|
368
|
+
if (setupMCP) {
|
|
369
|
+
spinner.start('Creating MCP configuration...');
|
|
370
|
+
|
|
371
|
+
// Use npx approach for reliability (like Pinecone does)
|
|
372
|
+
const mcpServer = getMcpServerConfig();
|
|
373
|
+
|
|
374
|
+
// Create .cursor/mcp.json
|
|
375
|
+
const cursorDir = path.join(workspaceRoot, '.cursor');
|
|
376
|
+
await fs.mkdir(cursorDir, { recursive: true });
|
|
377
|
+
|
|
378
|
+
// Build MCP server config - npx handles all dependencies
|
|
379
|
+
const mcpServerConfig = {
|
|
380
|
+
command: mcpServer.command,
|
|
381
|
+
args: mcpServer.args
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// Read existing config if present to preserve other servers
|
|
385
|
+
let existingConfig = { mcpServers: {} };
|
|
386
|
+
const cursorConfigPath = path.join(cursorDir, 'mcp.json');
|
|
387
|
+
try {
|
|
388
|
+
const existing = await fs.readFile(cursorConfigPath, 'utf-8');
|
|
389
|
+
existingConfig = JSON.parse(existing);
|
|
390
|
+
if (!existingConfig.mcpServers) {
|
|
391
|
+
existingConfig.mcpServers = {};
|
|
392
|
+
}
|
|
393
|
+
} catch {
|
|
394
|
+
// No existing config, that's fine
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Add/update descix server
|
|
398
|
+
existingConfig.mcpServers['descix'] = mcpServerConfig;
|
|
399
|
+
|
|
400
|
+
await fs.writeFile(cursorConfigPath, JSON.stringify(existingConfig, null, 2));
|
|
401
|
+
|
|
402
|
+
spinner.succeed('MCP configuration created');
|
|
403
|
+
console.log(chalk.gray(` Created: .cursor/mcp.json`));
|
|
404
|
+
console.log(chalk.gray(` Server: ${mcpServer.command} ${mcpServer.args.join(' ')}`));
|
|
405
|
+
|
|
406
|
+
// Deploy customized rules file with entitlements
|
|
407
|
+
spinner.start('Generating customized agent rules...');
|
|
408
|
+
|
|
409
|
+
const rulesGenerated = await generateRulesFile(workspaceRoot, entitlements, primaryCommunity);
|
|
410
|
+
|
|
411
|
+
if (rulesGenerated) {
|
|
412
|
+
spinner.succeed('Agent rules file generated with entitlements');
|
|
413
|
+
console.log(chalk.gray(` Created: .cursor/rules/descix_mcp.mdc`));
|
|
414
|
+
console.log(chalk.gray(` - Embedded ${entitlements.communities.length} communities`));
|
|
415
|
+
console.log(chalk.gray(` - Embedded ${entitlements.apps.length} apps`));
|
|
416
|
+
console.log(chalk.gray(` - References local SDK assets at .descix/sdk-assets/\n`));
|
|
417
|
+
} else {
|
|
418
|
+
// Fall back to simple template
|
|
419
|
+
spinner.info('Using simple rules template');
|
|
420
|
+
const rulesDir = path.join(workspaceRoot, '.cursor', 'rules');
|
|
421
|
+
await fs.mkdir(rulesDir, { recursive: true });
|
|
422
|
+
|
|
423
|
+
const templatePath = path.join(__dirname, '../../templates/descix_mcp.mdc');
|
|
424
|
+
const rulesPath = path.join(rulesDir, 'descix_mcp.mdc');
|
|
425
|
+
|
|
426
|
+
try {
|
|
427
|
+
const templateContent = await fs.readFile(templatePath, 'utf-8');
|
|
428
|
+
await fs.writeFile(rulesPath, templateContent, 'utf-8');
|
|
429
|
+
console.log(chalk.gray(` Created: .cursor/rules/descix_mcp.mdc\n`));
|
|
430
|
+
} catch (error) {
|
|
431
|
+
console.log(chalk.gray(` Skipped: .cursor/rules/descix_mcp.mdc\n`));
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Step 5: Create workspace config
|
|
437
|
+
spinner.start('Creating workspace configuration...');
|
|
438
|
+
|
|
439
|
+
const config = {
|
|
440
|
+
version: '2.0',
|
|
441
|
+
primaryCommunity,
|
|
442
|
+
directoryMappings: {}, // Empty - AI agent will configure after setup
|
|
443
|
+
additionalContexts: [],
|
|
444
|
+
defaultContext: {
|
|
445
|
+
communityId: primaryCommunity,
|
|
446
|
+
appId: 'agent',
|
|
447
|
+
kbId: 'General'
|
|
448
|
+
},
|
|
449
|
+
apiUrl: apiUrl,
|
|
450
|
+
environment: apiUrl.includes('localhost') ? 'development' : 'production',
|
|
451
|
+
_setupStatus: 'mcp_ready',
|
|
452
|
+
_needsAgentSetup: true, // Flag for AI agent to help with workspace config
|
|
453
|
+
_sdkVersion: SDK_VERSION
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
const descixDir = path.join(workspaceRoot, '.descix');
|
|
457
|
+
await fs.mkdir(descixDir, { recursive: true });
|
|
458
|
+
const configPath = path.join(descixDir, 'workspace.json');
|
|
459
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
460
|
+
|
|
461
|
+
spinner.succeed('Workspace configured');
|
|
462
|
+
console.log(chalk.gray(` Created: .descix/workspace.json\n`));
|
|
463
|
+
|
|
464
|
+
// Step 6: Auto-register SDK service for tell_me_how discovery
|
|
465
|
+
console.log(chalk.cyan('\nš Step 6: Registering SDK Service\n'));
|
|
466
|
+
|
|
467
|
+
spinner.start('Registering SDK for tell_me_how discovery...');
|
|
468
|
+
const sdkRegistered = await autoRegisterSdkService(apiClient);
|
|
469
|
+
|
|
470
|
+
if (sdkRegistered) {
|
|
471
|
+
spinner.succeed('SDK service registered');
|
|
472
|
+
console.log(chalk.gray(' SDK tools now discoverable via tell_me_how\n'));
|
|
473
|
+
} else {
|
|
474
|
+
spinner.warn('Could not register SDK service (will work without discovery)');
|
|
475
|
+
console.log(chalk.gray(' SDK tools available but not indexed for search\n'));
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Done!
|
|
479
|
+
console.log(chalk.green('\nā
MCP Setup Complete!\n'));
|
|
480
|
+
console.log(chalk.white('Next steps:'));
|
|
481
|
+
console.log(chalk.gray(' 1. Restart Cursor (Cmd/Ctrl + Shift + P ā "Reload Window")'));
|
|
482
|
+
console.log(chalk.gray(' 2. Ask the AI agent: "Help me configure my workspace"\n'));
|
|
483
|
+
|
|
484
|
+
console.log(chalk.white('The AI agent will:'));
|
|
485
|
+
console.log(chalk.gray(' - Read your entitlements and show available apps'));
|
|
486
|
+
console.log(chalk.gray(' - Help you map local folders to DeSciX apps'));
|
|
487
|
+
console.log(chalk.gray(' - Analyze folder structure and recommend packaging types'));
|
|
488
|
+
console.log(chalk.gray(' - Register apps in workspace.json\n'));
|
|
489
|
+
|
|
490
|
+
console.log(chalk.white('If MCP fails, use CLI directly:'));
|
|
491
|
+
console.log(chalk.gray(' descix purchases # View your entitlements'));
|
|
492
|
+
console.log(chalk.gray(' descix tell-me-how "question" # Discover tools'));
|
|
493
|
+
console.log(chalk.gray(' descix sync assets -c X -a Y # Sync app assets'));
|
|
494
|
+
console.log(chalk.gray(' descix sync kb -c X -a Y # Sync knowledge base\n'));
|
|
495
|
+
|
|
496
|
+
} catch (error) {
|
|
497
|
+
spinner.fail('Setup failed');
|
|
498
|
+
console.error(chalk.red(error.message));
|
|
499
|
+
throw error;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|