From 0dfa0ed7cf3bc18d67bdacd4edde96edf53b8dfe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Mar 2026 23:17:22 +0000 Subject: [PATCH 1/4] Initial plan From af0ca29c956b77631a40481cc07d435620e9f162 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Mar 2026 23:25:08 +0000 Subject: [PATCH 2/4] chore: initial plan for @vlocode/mcp package Co-authored-by: Codeneos <787686+Codeneos@users.noreply.github.com> --- MCP_EXPLORATION_INDEX.md | 212 ++++++++++++ MCP_QUICK_REFERENCE.md | 221 ++++++++++++ README_EXPLORATION.md | 211 ++++++++++++ VLOCODE_EXPLORATION.md | 718 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 1362 insertions(+) create mode 100644 MCP_EXPLORATION_INDEX.md create mode 100644 MCP_QUICK_REFERENCE.md create mode 100644 README_EXPLORATION.md create mode 100644 VLOCODE_EXPLORATION.md diff --git a/MCP_EXPLORATION_INDEX.md b/MCP_EXPLORATION_INDEX.md new file mode 100644 index 000000000..2e19ebeb8 --- /dev/null +++ b/MCP_EXPLORATION_INDEX.md @@ -0,0 +1,212 @@ +# Vlocode MCP Exploration - Complete Index + +## πŸ“‹ Documents Created + +This exploration has created comprehensive documentation to guide MCP package creation: + +### 1. **VLOCODE_EXPLORATION.md** (718 lines) + - Complete detailed exploration of the entire monorepo + - All 10 questions answered in depth + - Code examples and file paths + - **Location:** `/home/runner/work/vlocode/vlocode/VLOCODE_EXPLORATION.md` + +### 2. **MCP_QUICK_REFERENCE.md** (This file) + - Quick summary of 10 key findings + - Quick copy-paste patterns + - File paths for reference + - MCP package template structure + - Checklist for creating new package + - **Location:** `/home/runner/work/vlocode/vlocode/MCP_QUICK_REFERENCE.md` + +--- + +## 🎯 Key Takeaways (30-second summary) + +| Aspect | Finding | +|--------|---------| +| **Monorepo Type** | pnpm workspace + Lerna Lite | +| **Packages** | 10 total (@vlocode/* + vscode extension) | +| **MCP Status** | βœ… NO existing MCP package | +| **DI Framework** | Custom IoC container with @injectable/@inject | +| **Exports Pattern** | Direct `export * from './module'` in src/index.ts | +| **Build System** | TypeScript with composite projects | +| **Commands** | Decorator-based (@vscodeCommand) | +| **Salesforce APIs** | Complete (SOAP, REST, Bulk, Metadata, Schema, Query) | +| **Deployment** | DatapackDeployer with 25+ component specs | +| **TsConfig** | Requires emitDecoratorMetadata, experimentalDecorators, useDefineForClassFields: false | + +--- + +## πŸ“š Quick Navigation + +### Understanding the Structure +β†’ Read: **VLOCODE_EXPLORATION.md Section 1-3** +- Monorepo packages and their purposes +- VSCode extension architecture +- Commands system + +### Creating Services with DI +β†’ Read: **VLOCODE_EXPLORATION.md Section 9** +- Container usage patterns +- @injectable and @inject decorators +- Code examples from datapackDeployer.ts + +### Exporting APIs +β†’ Read: **VLOCODE_EXPLORATION.md Section 5-7** +- How @vlocode/util exports simple utilities +- How @vlocode/salesforce exports complex APIs +- Datapack deployment specs + +### Configuration +β†’ Read: **VLOCODE_EXPLORATION.md Section 10** +- Complete tsconfig.json with all required settings +- package.json template +- pnpm-workspace.yaml configuration + +### Copy-Paste Templates +β†’ Read: **MCP_QUICK_REFERENCE.md** +- Package.json template +- tsconfig.json template +- DI service pattern +- MCP package directory structure + +--- + +## πŸ” Finding Specific Information + +### "How do I..." + +**...create a new service?** +β†’ See MCP_QUICK_REFERENCE.md - DI Container Usage Pattern (Section 9️⃣) +β†’ See VLOCODE_EXPLORATION.md Section 9 - Full DI examples + +**...export APIs from my package?** +β†’ See VLOCODE_EXPLORATION.md Section 5 - API Export Patterns +β†’ See @vlocode/util example (packages/util/src/index.ts) + +**...structure a new package?** +β†’ See VLOCODE_EXPLORATION.md Section 6 - Simple Package Structure +β†’ See MCP_QUICK_REFERENCE.md - MCP Package Template + +**...register a VSCode command?** +β†’ See VLOCODE_EXPLORATION.md Section 4 & Command Registration +β†’ File: packages/vscode-extension/src/lib/commandRouter.ts + +**...call Salesforce APIs?** +β†’ See VLOCODE_EXPLORATION.md Section 8 - Salesforce APIs +β†’ File: packages/salesforce/src/salesforceService.ts + +**...use the DI container?** +β†’ See VLOCODE_EXPLORATION.md Section 9 - DI Container Usage +β†’ Files: packages/core/src/di/*.ts + +**...configure TypeScript for DI?** +β†’ See VLOCODE_EXPLORATION.md Section 10 - Config Conventions +β†’ Root: /tsconfig.json (has all required settings) + +--- + +## πŸ“‚ Critical File Paths + +### Must-Read Implementation Files + +``` +packages/core/src/di/ +β”œβ”€β”€ container.ts # DI container (800+ lines) +β”œβ”€β”€ injectable.decorator.ts # @injectable implementation +└── inject.decorator.ts # @inject implementation + +packages/vscode-extension/src/lib/ +β”œβ”€β”€ commandRouter.ts # Command registration system +β”œβ”€β”€ commandBase.ts # Base command class +└── vlocodeService.ts # Main service + +packages/salesforce/src/ +β”œβ”€β”€ salesforceService.ts # Main Salesforce service (26KB) +β”œβ”€β”€ schema/ # Schema APIs +└── queryService.ts # Query service + +packages/vlocity-deploy/src/ +β”œβ”€β”€ datapackDeployer.ts # Main deployer +β”œβ”€β”€ datapackDeployment.ts # Deployment lifecycle +└── deploymentSpecs/ # 25+ component specifications +``` + +### Configuration Files + +``` +/tsconfig.json # Root config (has path mappings) +/pnpm-workspace.yaml # Workspace configuration +/lerna.json # Version management +/packages/*/tsconfig.json # Package-specific configs +/packages/*/package.json # Package manifests +``` + +--- + +## πŸš€ Next Steps + +1. **Read VLOCODE_EXPLORATION.md** for comprehensive understanding +2. **Reference MCP_QUICK_REFERENCE.md** for templates and patterns +3. **Create /packages/mcp/** directory +4. **Copy template files** from templates/ or similar packages +5. **Run pnpm install** to link the new package +6. **Build and test** with `pnpm build` and `pnpm test` + +--- + +## ✨ Key Insights for MCP Package + +### What to Leverage +- βœ… **@vlocode/core** - DI container, Logger, FileSystem +- βœ… **@vlocode/salesforce** - Complete Salesforce APIs +- βœ… **@vlocode/vlocity-deploy** - Datapack deployment engine +- βœ… **@vlocode/util** - Utilities (async, string, object helpers) +- βœ… **@vlocode/vlocity** - Vlocity-specific functionality + +### Convention to Follow +- πŸ“¦ `src/index.ts` with `export * from './modules'` +- πŸ—οΈ Services decorated with `@injectable()` +- πŸ”Œ Dependencies injected with `@inject()` +- πŸ“ TypeScript with decorators enabled +- πŸ§ͺ Jest tests in `src/__tests__/` +- πŸ“š TypeDoc comments for public APIs + +### Patterns to Adopt +- Container scoping for lifecycle management +- Property injection for optional dependencies +- Constructor injection for required dependencies +- Lazy evaluation where appropriate +- Logger integration for diagnostics + +--- + +## πŸ“– Document Statistics + +- **VLOCODE_EXPLORATION.md**: 718 lines, ~42 KB +- **MCP_QUICK_REFERENCE.md**: ~300 lines, ~10 KB +- **Total Coverage**: All 10 exploration questions answered +- **Code Examples**: 50+ snippets across both documents +- **File References**: 100+ specific file paths provided + +--- + +## ❓ Questions Answered + +βœ… 1. What is the overall structure of the monorepo? List the packages and what they do. +βœ… 2. Is there an existing MCP (Model Context Protocol) package? If so, where is it? +βœ… 3. What does the vscode-extension package look like? List its key files and structure. +βœ… 4. How are commands structured in the vscode-extension? Look at commands.yaml if it exists and show key examples. +βœ… 5. How do existing packages export their APIs? Look at package.json exports and main entry points. +βœ… 6. Show me the structure of an existing simple package (like @vlocode/util or @vlocode/cli) to understand the conventions. +βœ… 7. What Datapack-related APIs exist? Look at @vlocode/vlocity-deploy for key exports. +βœ… 8. What Salesforce-related APIs exist for describing objects and fields? +βœ… 9. How is the DI container used to get services? +βœ… 10. What tsconfig.json and package.json conventions are used for new packages? + +All with file paths, code snippets, and concrete details! + +--- + +**Created:** Vlocode Monorepo Exploration +**Status:** βœ… Complete with 2 comprehensive documents diff --git a/MCP_QUICK_REFERENCE.md b/MCP_QUICK_REFERENCE.md new file mode 100644 index 000000000..01ebc3eeb --- /dev/null +++ b/MCP_QUICK_REFERENCE.md @@ -0,0 +1,221 @@ +# Vlocode Monorepo - Quick Reference for MCP Package Creation + +## πŸ“¦ 10 Key Findings + +### 1️⃣ Monorepo Structure +- **Type:** pnpm workspace + Lerna Lite versioning +- **Packages:** 10 total (9 @vlocode/* + 1 vlocode extension) +- **Core Stack:** TypeScript, DI Container, Logger, File System abstraction + +### 2️⃣ NO Existing MCP Package βœ… +- Clear opportunity for new `@vlocode/mcp` package +- No naming conflicts + +### 3️⃣ VSCode Extension at `/packages/vscode-extension` +``` +src/ +β”œβ”€β”€ commands/ # Datapack, apex, logs, metadata, profiles commands +β”œβ”€β”€ lib/ +β”‚ β”œβ”€β”€ commandRouter.ts # Command registration & routing +β”‚ β”œβ”€β”€ commandBase.ts # Base command class +β”‚ β”œβ”€β”€ vlocodeService.ts # Main extension service +β”‚ └── salesforce/vlocity/ # Domain logic +β”œβ”€β”€ treeDataProviders/ # Explorer views +β”œβ”€β”€ codeLensProviders/ # Code lenses +└── events/ # File watchers, handlers +``` + +### 4️⃣ Commands via @vscodeCommand Decorator +```typescript +@vscodeCommand('vlocode.selectOrg') +export class SelectOrgCommand extends CommandBase { + public async execute(...args) { } +} +// Commands automatically registered by CommandRouter +``` + +### 5️⃣ API Export Pattern (Simple) +All packages use: +```typescript +// src/index.ts +export * from './module1'; +export * from './module2'; +// ... +``` +No `exports` field needed - direct index import pattern + +### 6️⃣ Simple Package Example: @vlocode/util +``` +packages/util/ +β”œβ”€β”€ package.json (main: "src/index.ts") +β”œβ”€β”€ tsconfig.json (extends root) +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ async.ts, cache.ts, collection.ts, ... +β”‚ └── index.ts (re-exports all) +└── dist/ (published output) +``` + +### 7️⃣ Datapack APIs: @vlocode/vlocity-deploy +```typescript +export * from './datapackDeployer'; +export * from './datapackDeployment'; +export * from './datapackDeploymentOptions'; +export * from './deploymentSpecs'; // 25+ specs (OmniScript, OmniCard, etc) +export * from './export'; +``` +**Key Classes:** DatapackDeployer, DatapackDeployment, DatapackDeploymentSpec + +### 8️⃣ Salesforce APIs: @vlocode/salesforce +```typescript +SalesforceService has: + .schema // SalesforceSchemaService + .deploy // SalesforceDeployService + .data // SalesforceDataService (CRUD) + .logs // DeveloperLogs + .batch // SalesforceBatchService + .tooling // Tooling API service + +Plus: queryBuilder, queryService, metadataRegistry, etc +``` + +### 9️⃣ DI Container Usage Pattern +```typescript +import { injectable, inject, container, LifecyclePolicy } from '@vlocode/core'; + +@injectable({ lifecycle: LifecyclePolicy.singleton }) +export class MyService { + @inject() private readonly dependency: OtherService; + + constructor( + @inject(SalesforceService) private sf: SalesforceService + ) {} +} + +// Usage +const instance = container.get(MyService); +const child = container.create(); // Child container +``` + +### πŸ”Ÿ Config Conventions +**tsconfig.json:** +```json +{ + "compilerOptions": { + "emitDecoratorMetadata": true, // ⚠️ REQUIRED + "experimentalDecorators": true, // ⚠️ REQUIRED + "useDefineForClassFields": false, // ⚠️ REQUIRED for @inject + "module": "node20", + "target": "es2022" + } +} +``` + +**package.json:** +```json +{ + "name": "@vlocode/package-name", + "main": "src/index.ts", + "publishConfig": { + "main": "dist/index.js", + "typings": "dist/index.d.ts" + }, + "files": ["dist/**/*.js", "dist/**/*.d.ts"], + "dependencies": { "@vlocode/core": "workspace:*" } +} +``` + +--- + +## πŸ“ Key File Paths for Reference + +### Core DI Framework +- `/packages/core/src/di/container.ts` - Container implementation (800+ lines) +- `/packages/core/src/di/injectable.decorator.ts` - @injectable decorator +- `/packages/core/src/di/inject.decorator.ts` - @inject decorator + +### Command System +- `/packages/vscode-extension/src/lib/commandRouter.ts` - Command registration +- `/packages/vscode-extension/src/lib/commandBase.ts` - Base command class +- `/packages/vscode-extension/src/commands/selectOrgCommand.ts` - Example command + +### Salesforce APIs +- `/packages/salesforce/src/salesforceService.ts` - Main service (26KB) +- `/packages/salesforce/src/schema/` - Schema APIs +- `/packages/salesforce/src/queryService.ts` - Query service + +### Deployment Engine +- `/packages/vlocity-deploy/src/datapackDeployer.ts` - Main deployer +- `/packages/vlocity-deploy/src/datapackDeployment.ts` - Deployment lifecycle +- `/packages/vlocity-deploy/src/deploymentSpecs/` - 25+ component specs + +### Configuration +- `/tsconfig.json` - Root config with path mappings +- `/pnpm-workspace.yaml` - Workspace configuration +- `/lerna.json` - Version management + +--- + +## οΏ½οΏ½ MCP Package Template + +``` +packages/mcp/ +β”œβ”€β”€ package.json +β”œβ”€β”€ tsconfig.json +β”œβ”€β”€ jest.config.js +β”œβ”€β”€ CHANGELOG.md +β”œβ”€β”€ README.md +└── src/ + β”œβ”€β”€ __tests__/ + β”‚ └── mcpServer.test.ts + β”œβ”€β”€ index.ts # Main exports + β”œβ”€β”€ mcpServer.ts # MCP server implementation + β”œβ”€β”€ resources/ + β”‚ β”œβ”€β”€ index.ts + β”‚ β”œβ”€β”€ datapackResource.ts + β”‚ └── schemaResource.ts + β”œβ”€β”€ tools/ + β”‚ β”œβ”€β”€ index.ts + β”‚ β”œβ”€β”€ deployTool.ts + β”‚ └── querySoqlTool.ts + β”œβ”€β”€ prompts/ + β”‚ β”œβ”€β”€ index.ts + β”‚ └── deploymentPrompts.ts + └── services/ + β”œβ”€β”€ index.ts + β”œβ”€β”€ mcpResourceManager.ts + └── mcpToolManager.ts +``` + +--- + +## πŸ”— Workspace Dependencies + +Use `workspace:*` for internal dependencies: +```json +{ + "dependencies": { + "@vlocode/core": "workspace:*", + "@vlocode/util": "workspace:*", + "@vlocode/salesforce": "workspace:*", + "@vlocode/vlocity": "workspace:*", + "@vlocode/vlocity-deploy": "workspace:*" + } +} +``` + +--- + +## βœ… Checklist for New Package + +- [ ] Create `/packages/mcp/` directory +- [ ] Copy `package.json` template and update name +- [ ] Copy `tsconfig.json` and set references +- [ ] Add `src/index.ts` with exports +- [ ] Add `src/__tests__/` with jest.config.js reference +- [ ] Add to pnpm-workspace.yaml (auto if in packages/*) +- [ ] Create services using @injectable/@inject pattern +- [ ] Run `pnpm install` to link package +- [ ] Run `pnpm build` to test compilation +- [ ] Run `pnpm test` for tests +- [ ] Update root `tsconfig.json` path mappings for "@vlocode/mcp" + diff --git a/README_EXPLORATION.md b/README_EXPLORATION.md new file mode 100644 index 000000000..cb017745e --- /dev/null +++ b/README_EXPLORATION.md @@ -0,0 +1,211 @@ +# πŸ“– Vlocode Monorepo Exploration - Start Here + +This directory now contains comprehensive documentation about the Vlocode monorepo structure, perfect for creating new packages like the proposed MCP (Model Context Protocol) package. + +## πŸš€ Quick Start + +**Time needed:** 20 minutes to understand everything + +### Step 1: Quick Overview (5 min) +Start with: **`MCP_QUICK_REFERENCE.md`** +- 10 key findings summarized +- Copy-paste templates for new packages +- Implementation checklist + +### Step 2: Detailed Reference (10 min) +Use: **`MCP_EXPLORATION_INDEX.md`** +- Navigation guide for specific topics +- File path reference +- "How do I..." quick answers + +### Step 3: Deep Dive (5 min) +Full details: **`VLOCODE_EXPLORATION.md`** +- 718 lines of comprehensive information +- 50+ code examples +- All 10 questions answered in depth + +--- + +## πŸ“‹ The Three Documents + +### 1. **MCP_QUICK_REFERENCE.md** ⭐ Start Here +- **Length:** 221 lines (~6 min read) +- **Best for:** Quick understanding and copy-paste templates +- **Contains:** + - 10 key findings with emojis + - package.json template + - tsconfig.json template + - DI Container pattern + - MCP package directory structure + - Implementation checklist + +### 2. **MCP_EXPLORATION_INDEX.md** πŸ—ΊοΈ Navigation Guide +- **Length:** 212 lines (~5 min read) +- **Best for:** Finding specific information +- **Contains:** + - Navigation by topic (structure, DI, APIs, config) + - "How do I..." quick links + - File path reference (grouped by purpose) + - Next steps checklist + - Key insights for MCP + +### 3. **VLOCODE_EXPLORATION.md** πŸ“š Complete Reference +- **Length:** 718 lines (~30 min read) +- **Best for:** Deep understanding and implementation details +- **Contains:** + - Question 1: Monorepo structure (10 packages) + - Question 2: MCP package status (βœ… doesn't exist) + - Question 3: VSCode extension structure + - Question 4: Command structure (commands.yaml) + - Question 5: API export patterns + - Question 6: Simple package structure (@vlocode/util) + - Question 7: Datapack APIs (@vlocode/vlocity-deploy) + - Question 8: Salesforce APIs (@vlocode/salesforce) + - Question 9: DI container usage patterns + - Question 10: Configuration conventions + - Plus: Command registration details, MCP package template + +--- + +## 🎯 What You'll Learn + +### About the Monorepo +- βœ… 10 total packages (9 @vlocode/* + 1 extension) +- βœ… pnpm workspace + Lerna Lite versioning +- βœ… TypeScript with custom DI container +- βœ… All packages follow consistent conventions + +### About APIs Available +- βœ… **@vlocode/core** - IoC container, Logger, FileSystem +- βœ… **@vlocode/util** - 25+ utility modules +- βœ… **@vlocode/salesforce** - Complete Salesforce integration (SOAP, REST, Bulk, Metadata, Schema, Query) +- βœ… **@vlocode/vlocity-deploy** - Datapack deployment with 25+ component specs +- βœ… **@vlocode/vlocity** - OmniStudio/Vlocity functionality + +### About Creating New Packages +- βœ… Exact package.json template +- βœ… Exact tsconfig.json configuration (with DI requirements) +- βœ… Directory structure conventions +- βœ… Export patterns (src/index.ts with export *) +- βœ… Service creation with @injectable/@inject decorators +- βœ… Testing setup with Jest + +### About the Command System +- βœ… @vscodeCommand decorator pattern +- βœ… CommandRouter automatic registration +- βœ… CommandBase class usage +- βœ… 40+ existing commands as examples + +--- + +## πŸ“‚ File Paths Quick Reference + +### Must-Read Implementation Files +``` +packages/core/src/di/ + β”œβ”€β”€ container.ts # DI container (main!) + β”œβ”€β”€ injectable.decorator.ts # @injectable + └── inject.decorator.ts # @inject + +packages/vscode-extension/src/lib/ + β”œβ”€β”€ commandRouter.ts # Command system + β”œβ”€β”€ commandBase.ts # Base command class + └── vlocodeService.ts # Main service + +packages/salesforce/src/ + β”œβ”€β”€ salesforceService.ts # Main Salesforce service + └── schema/ # Schema APIs + +packages/vlocity-deploy/src/ + β”œβ”€β”€ datapackDeployer.ts # Main deployer + └── deploymentSpecs/ # 25+ specs +``` + +### Configuration Files +``` +/tsconfig.json # Root config +/pnpm-workspace.yaml # Workspace +/lerna.json # Versioning +``` + +--- + +## 🎬 How to Use These Documents + +### If you want to understand the overall structure +β†’ Read: **MCP_QUICK_REFERENCE.md** Section 1️⃣ +β†’ Then: **VLOCODE_EXPLORATION.md** Section 1-3 + +### If you want to create a new service +β†’ Read: **MCP_QUICK_REFERENCE.md** Section 9️⃣ +β†’ Then: **VLOCODE_EXPLORATION.md** Section 9 + +### If you want to understand the command system +β†’ Read: **MCP_QUICK_REFERENCE.md** Section 4️⃣ +β†’ Then: **VLOCODE_EXPLORATION.md** Section 4 + Command Registration + +### If you want to create a new package +β†’ Read: **MCP_QUICK_REFERENCE.md** MCP Package Template +β†’ Then: **VLOCODE_EXPLORATION.md** Section 6 + 10 +β†’ Finally: **MCP_EXPLORATION_INDEX.md** βœ… Checklist + +### If you want specific information +β†’ Use: **MCP_EXPLORATION_INDEX.md** "How do I..." section +β†’ Get direct links to the right documentation + +--- + +## βœ… 10 Questions Answered + +All with file paths, code examples, and practical templates: + +1. βœ… **Monorepo structure?** - 10 packages described with purposes +2. βœ… **Existing MCP package?** - No (clear opportunity!) +3. βœ… **VSCode extension structure?** - Full directory tree +4. βœ… **Command structure?** - commands.yaml format with examples +5. βœ… **API exports?** - Pattern: export * from './module' +6. βœ… **Simple package structure?** - @vlocode/util example +7. βœ… **Datapack APIs?** - @vlocode/vlocity-deploy with 25+ specs +8. βœ… **Salesforce APIs?** - SalesforceService with subservices +9. βœ… **DI container usage?** - @injectable/@inject patterns +10. βœ… **Configuration conventions?** - Complete templates + +--- + +## πŸš€ Next Steps + +1. **Read MCP_QUICK_REFERENCE.md** (10 minutes) +2. **Browse MCP_EXPLORATION_INDEX.md** (5 minutes) +3. **Reference VLOCODE_EXPLORATION.md** as needed +4. **Create /packages/mcp/** directory +5. **Copy templates** from the documents +6. **Build and test** with `pnpm build` and `pnpm test` + +--- + +## πŸ“Š Statistics + +- **Total Lines:** 1,151 lines of documentation +- **Total Size:** ~35 KB +- **Code Examples:** 50+ +- **File References:** 100+ +- **Questions Answered:** 10/10 + +--- + +## πŸ’‘ Key Takeaway + +The Vlocode monorepo is well-structured with: +- ✨ **Consistent conventions** across all packages +- πŸ—οΈ **Powerful DI framework** for service management +- πŸ”Œ **Rich APIs** for Salesforce, Datapacks, and Vlocity +- πŸ“¦ **Simple export pattern** (no complex "exports" field) +- πŸ§ͺ **Full testing infrastructure** with Jest + +**Ready to create the @vlocode/mcp package!** πŸŽ‰ + +--- + +**Created:** March 15, 2025 +**Status:** βœ… Complete with comprehensive documentation +**Last Updated:** Latest exploration with all 10 questions answered diff --git a/VLOCODE_EXPLORATION.md b/VLOCODE_EXPLORATION.md new file mode 100644 index 000000000..dc14537ce --- /dev/null +++ b/VLOCODE_EXPLORATION.md @@ -0,0 +1,718 @@ +# Vlocode Monorepo Exploration Summary + +## 1. Monorepo Structure & Packages + +**Location:** `/home/runner/work/vlocode/vlocode` + +**Monorepo Type:** pnpm workspace with Lerna Lite versioning + +### Packages Overview: + +| Package | Location | Purpose | +|---------|----------|---------| +| **@vlocode/core** | `packages/core` | IoC container framework, logging, file system abstraction | +| **@vlocode/util** | `packages/util` | Utility library with async, string, object, salesforce helpers | +| **@vlocode/salesforce** | `packages/salesforce` | Salesforce APIs (SOAP, REST, Bulk, Metadata, Query, Deploy, Schema) | +| **@vlocode/vlocity** | `packages/vlocity` | Vlocity/OmniStudio shared functionality | +| **@vlocode/vlocity-deploy** | `packages/vlocity-deploy` | Datapack deployment library (core deployment engine) | +| **@vlocode/omniscript** | `packages/omniscript` | OmniScript compilation and processing | +| **@vlocode/apex** | `packages/apex` | Apex parser and grammar | +| **@vlocode/sass** | `packages/sass` | SASS compiler for Vlocity | +| **@vlocode/cli** | `packages/cli` | CLI tool for datapack deployment | +| **vlocode** | `packages/vscode-extension` | VSCode extension for Vlocity/OmniStudio development | + +--- + +## 2. No Existing MCP Package + +**Result:** βœ… No MCP (Model Context Protocol) package exists +- Searched for "mcp", "MCP", "model-context-protocol" in all `package.json` files +- No hits found +- This is a good opportunity to create a new `@vlocode/mcp` package + +--- + +## 3. VSCode Extension Package Structure + +**Location:** `/home/runner/work/vlocode/vlocode/packages/vscode-extension` + +### Key Files: +- **`package.json`** (71.1 KB) - Extension manifest with bin, publisher info +- **`commands.yaml`** - Declarative command definitions for VSCode menus +- **`src/extension.ts`** - Main entry point +- **`src/commands/`** - Command implementations +- **`src/lib/`** - Core services and utilities +- **`tsconfig.json`** - TypeScript configuration +- **`jest/`** - Test configuration + +### Directory Structure: +``` +packages/vscode-extension/ +β”œβ”€β”€ build/ # Build output +β”œβ”€β”€ commands.yaml # Command declarations +β”œβ”€β”€ jest/ # Jest test setup +β”œβ”€β”€ jest.config.js +β”œβ”€β”€ loader.mjs # Custom loader +β”œβ”€β”€ package.json # Extension manifest +β”œβ”€β”€ resources/ # Static resources +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ commands/ # Command implementations +β”‚ β”‚ β”œβ”€β”€ apex/ +β”‚ β”‚ β”œβ”€β”€ datapacks/ +β”‚ β”‚ β”œβ”€β”€ developerLogs/ +β”‚ β”‚ β”œβ”€β”€ metadata/ +β”‚ β”‚ β”œβ”€β”€ profiles/ +β”‚ β”‚ β”œβ”€β”€ index.ts +β”‚ β”‚ β”œβ”€β”€ selectOrgCommand.ts +β”‚ β”‚ β”œβ”€β”€ execRestApiCommand.ts +β”‚ β”‚ └── ... +β”‚ β”œβ”€β”€ lib/ +β”‚ β”‚ β”œβ”€β”€ commandBase.ts # Base class for commands +β”‚ β”‚ β”œβ”€β”€ commandRouter.ts # Command registration & routing +β”‚ β”‚ β”œβ”€β”€ vlocodeService.ts # Main service +β”‚ β”‚ β”œβ”€β”€ vlocodeContext.ts # Context utilities +β”‚ β”‚ β”œβ”€β”€ config/ # Configuration +β”‚ β”‚ β”œβ”€β”€ ui/ # UI utilities +β”‚ β”‚ β”œβ”€β”€ vlocity/ # Vlocity-specific logic +β”‚ β”‚ └── salesforce/ # Salesforce-specific logic +β”‚ β”œβ”€β”€ treeDataProviders/ # Explorers (datapacks, logs, jobs) +β”‚ β”œβ”€β”€ codeLensProviders/ # Code lens implementations +β”‚ β”œβ”€β”€ contentProviders/ # Virtual content providers +β”‚ β”œβ”€β”€ events/ # Event handlers +β”‚ β”œβ”€β”€ symbolProviders/ # Symbol providers +β”‚ β”œβ”€β”€ constants.ts # Extension constants +β”‚ └── extension.ts # Main entry point +β”œβ”€β”€ syntax/ # Syntax definitions +β”œβ”€β”€ types/ # Type definitions +└── tsconfig.json +``` + +--- + +## 4. Commands Structure (commands.yaml) + +**File:** `/home/runner/work/vlocode/vlocode/packages/vscode-extension/commands.yaml` + +### Structure: +```yaml +# Command ID: vlocode.selectOrg +vlocode.selectOrg: + title: 'Vlocode: Select Salesforce Org' + group: v_vlocity + menus: + - menu: commandPalette + +# Datapack commands with conditionals +vlocode.refreshDatapack: + title: 'Datapack: Refresh from Org' + group: v_vlocity + when: 'vlocode.conditionalContextMenus == false || resourcePath in vlocode.datapacks' + menus: + - menu: commandPalette + - menu: explorer/context + - menu: editor/context + +vlocode.deployDatapack: + title: 'Datapack: Deploy to Org' + # ... similar structure + +vlocode.openSalesforce: + title: 'Datapack: Open in Org' + +vlocode.renameDatapack: + title: 'Datapack: Rename...' + +vlocode.cloneDatapack: + title: 'Datapack: Clone...' + +vlocode.exportDatapack: + title: 'Datapack: Export from Org' +``` + +### Key Examples: +- **Extension setup:** `vlocode.selectOrg` - Org selection +- **Vlocity basics:** Refresh, Deploy, Open, Rename, Clone, Export datapacks +- **Developer tools:** Execute Anonymous, REST API execution, Logs +- **Metadata:** Operations on Salesforce metadata +- **Groups:** Commands grouped with `group: v_vlocity` for organization + +--- + +## 5. API Export Patterns + +### @vlocode/util (Simple Utility Package) + +**File:** `/home/runner/work/vlocode/vlocode/packages/util/src/index.ts` + +```typescript +export * from './async'; // Promise utilities +export * from './cache'; // Caching +export * from './cancellationToken'; // Cancellation support +export * from './collection'; // Collection utilities +export * from './compiler'; // Compilation utilities +export * from './decorator'; // Decorator utilities +export * from './events'; // Event management +export * from './fs'; // File system +export * from './object'; // Object utilities +export * from './string'; // String utilities +export * from './salesforce'; // Salesforce-specific +export * from './sfdx'; // SFDX utilities +export * from './types'; // Type definitions +``` + +**Package Structure:** +- Uses `main: "src/index.ts"` for development +- Published to `dist/index.js` with `dist/index.d.ts` types +- No `exports` field (direct index export pattern) +- Include `dist/**/*.js`, `dist/**/*.d.ts` in files + +### @vlocode/core (DI Container Package) + +**File:** `/home/runner/work/vlocode/vlocode/packages/core/src/index.ts` + +```typescript +export * from './di/container'; +export * from './di/injectable.decorator'; +export * from './di/inject.decorator'; +export * from './fs'; +export * from './logging'; +export * from './logging/writers'; +export * from './deferredWorkQueue'; +``` + +**Key Exports:** +- Container class (DI framework) +- `@injectable` decorator +- `@inject` decorator +- Logger, LogManager +- FileSystem abstractions +- DeferredWorkQueue + +### @vlocode/salesforce (Complex API Package) + +**File:** `/home/runner/work/vlocode/vlocode/packages/salesforce/src/index.ts` + +```typescript +export * from './bulk'; +export * from './connection'; +export * from './deploy'; +export * from './schema'; +export * from './queryBuilder'; +export * from './queryService'; +export * from './salesforceService'; +export * from './salesforceSchemaService'; +export * from './metadataRegistry'; +// ... 30+ exports total +``` + +**Main Services:** +- **SalesforceService** - Main service with connections, APIs, batch, tooling, logs +- **SalesforceSchemaService** - Schema operations +- **SalesforceDataService** - Data operations +- **SalesforceBatchService** - Batch operations +- **QueryService**, **QueryBuilder** - SOQL operations +- **RestClient**, **SoapClient** - API clients + +--- + +## 6. Simple Package Structure (@vlocode/util) + +**Location:** `/home/runner/work/vlocode/vlocode/packages/util` + +### Directory Layout: +``` +packages/util/ +β”œβ”€β”€ CHANGELOG.md +β”œβ”€β”€ jest.config.js +β”œβ”€β”€ package.json # Main configuration +β”œβ”€β”€ tsconfig.json # TypeScript config +└── src/ + β”œβ”€β”€ __tests__/ # Jest test directory + β”œβ”€β”€ async.ts # ~15KB - async utilities + β”œβ”€β”€ cache.ts # ~9KB - caching + β”œβ”€β”€ cancellationToken.ts # ~2.6KB + β”œβ”€β”€ collection.ts # ~24KB - collection utils + β”œβ”€β”€ compiler.ts # ~4.4KB + β”œβ”€β”€ decorator.ts # ~7.4KB + β”œβ”€β”€ events.ts # ~12KB - event system + β”œβ”€β”€ fs.ts # ~3.9KB + β”œβ”€β”€ lazy.ts # ~1.6KB + β”œβ”€β”€ object.ts # ~31KB - object utilities + β”œβ”€β”€ salesforce.ts # ~6.9KB + β”œβ”€β”€ sfdx.ts # ~26KB - SFDX integration + β”œβ”€β”€ string.ts # ~16KB - string utilities + └── index.ts # Main export file +``` + +### package.json Pattern: +```json +{ + "name": "@vlocode/util", + "version": "1.41.1", + "description": "Vlocode utility library", + "main": "src/index.ts", + "publishConfig": { + "main": "dist/index.js", + "typings": "dist/index.d.ts", + "access": "public" + }, + "scripts": { + "build": "tsc -b", + "watch": "tsc -b --watch", + "test": "jest" + }, + "files": [ + "dist/**/*.d.ts", + "!dist/**/*.test.d.ts", + "dist/**/*.js", + "dist/**/*.json", + "!dist/**/*.test.js" + ], + "dependencies": { + "@salesforce/core": "3.31.18" + } +} +``` + +### tsconfig.json Pattern: +```json +{ + "extends": "../../tsconfig", + "compilerOptions": { + "composite": true, + "outDir": "dist", + "rootDir": "src", + "declaration": true, + "declarationMap": false + }, + "include": ["src/**/*"] +} +``` + +--- + +## 7. Datapack Deployment APIs (@vlocode/vlocity-deploy) + +**Location:** `/home/runner/work/vlocode/vlocode/packages/vlocity-deploy/src` + +### Main Exports: +```typescript +export * from './deploymentSpecs'; +export * from './types'; +export * from './convert'; +export * from './export'; +export * from './export/definition-converter'; +export * from './flexCard'; +export * from './datapackDeploy'; +export * from './datapackDeployer'; +export * from './datapackDeployment'; +export * from './datapackDeploymentEvent'; +export * from './datapackDeploymentError'; +export * from './datapackDeploymentOptions'; +export * from './datapackDeploymentRecord'; +export * from './datapackDeploymentRecordGroup'; +export * from './datapackDeploymentSpec'; +export * from './datapackDeploymentSpecRegistry'; +export * from './datapackDeploymentStatus'; +export * from './datapackRecordFactory'; +export * from './datapackLookupService'; +``` + +### Key Classes: +- **DatapackDeployer** - Main deployment orchestrator +- **DatapackDeployment** - Deployment instance with lifecycle +- **DatapackDeploymentOptions** - Configuration +- **DatapackDeploymentStatus** - Status tracking +- **DatapackRecordFactory** - Record creation +- **DatapackLookupService** - Lookup resolution + +### Deployment Specs (25+ specs): +Located in `packages/vlocity-deploy/src/deploymentSpecs/`: +- **Vlocity Components:** OmniScript, OmniUI Card, OmniDataTransform, DataRaptor, VlocityCard +- **OmniStudio:** omniScriptElementOrder, omniProcess, omniUICard +- **Salesforce:** decisionMatrix, Product2, contentVersion +- **Specialized:** calculationMatrix, customObjectMap, recordActivator, vlocityAction + +Each spec file defines deployment logic for its component type. + +--- + +## 8. Salesforce APIs for Objects & Fields + +**Location:** `/home/runner/work/vlocode/vlocode/packages/salesforce/src` + +### Schema-Related APIs: +```typescript +// packages/salesforce/src/schema/index.ts +export * from './types'; +export * from './compositeSchemaAccess'; +export * from './describeSchemaAccess'; +export * from './schemaDataStore'; +export * from './sobjectSchemaInfo'; +export * from './toolingApiSchemaAccess'; +``` + +### Key Services: +- **SalesforceSchemaService** - Main schema service +- **SalesforceDataService** - Data operations (CRUD) +- **SalesforceProfileService** - User profiles +- **SalesforceUserPermissions** - Permission handling + +### Available in SalesforceService: +```typescript +@injectable() +class SalesforceService { + // Properties providing subservices + get schema(): SalesforceSchemaService + get deploy(): SalesforceDeployService + get logs(): DeveloperLogs + get data(): SalesforceDataService + get tooling(): SalesforceDataService + get batch(): SalesforceBatchService + + // Key methods + async getOrganizationDetails() + async isPackageInstalled(packageName) + async getInstalledPackageDetails(packageName) + async isProductionOrg() + getJsForceConnection() +} +``` + +--- + +## 9. DI Container Usage Patterns + +**Location:** `/home/runner/work/vlocode/vlocode/packages/core/src/di/container.ts` + +### Key Concepts: + +#### Lifecycle Policies: +```typescript +enum LifecyclePolicy { + singleton = 1, // Single instance reused + transient = 2 // New instance per resolution +} +``` + +#### Decorators: + +**@injectable() - Mark class as injectable:** +```typescript +@injectable() +class MyService { + constructor(private dependency: OtherService) {} +} + +@injectable({ lifecycle: LifecyclePolicy.transient }) +class TransientService {} + +@injectable.singleton() +class SingletonService {} +``` + +**@inject() - Inject dependency:** +```typescript +class MyClass { + @inject() private readonly myService: SomeService; // Property injection + + constructor(@inject(SomeService) private service: SomeService) {} // Constructor injection +} +``` + +#### Usage Examples from codebase: + +**From datapackDeployer.ts:** +```typescript +@injectable({ lifecycle: LifecyclePolicy.transient }) +export class DatapackDeployer { + @inject() private readonly container: Container; + @inject() private readonly specRegistry: DatapackDeploymentSpecRegistry; + + // Services are injected and available + public async deploy(datapacks, options) { + this.container.get(SalesforceService).data.cache.configure({ enabled: false }); + } +} +``` + +**From datapackDeploy.ts:** +```typescript +const localContainer = container.create(); +localContainer.add(new Logger(...), ...options); +localContainer.add(new JsForceConnectionProvider(...), { + provides: [SalesforceConnectionProvider] +}); +localContainer.add(new VlocityNamespaceService()); + +const datapackLoader = localContainer.new(DatapackLoader); +return await localContainer.new(DatapackDeployer).deploy(datapacks, options); +``` + +#### Container Methods: +```typescript +// Global container +container.get(ServiceType) // Get instance +container.new(ServiceType) // Create new instance +container.add(instance, options) // Add service +container.create() // Create child container +container.resolveProperty(obj, key) // Resolve property + +// Class methods +Container.root // Access root container +Container.scope // Get current scope +``` + +--- + +## 10. Configuration Conventions (tsconfig.json & package.json) + +### Root tsconfig.json +**Location:** `/home/runner/work/vlocode/vlocode/tsconfig.json` + +```json +{ + "compilerOptions": { + "module": "node20", + "target": "es2022", + "lib": ["ES2023", "DOM"], + "outDir": "out", + "sourceMap": true, + "alwaysStrict": true, + "strictPropertyInitialization": false, + "useDefineForClassFields": false, // ⚠️ REQUIRED for @inject + "strictNullChecks": true, + "moduleResolution": "node16", + "emitDecoratorMetadata": true, // ⚠️ REQUIRED for DI + "experimentalDecorators": true, // ⚠️ REQUIRED for DI + "forceConsistentCasingInFileNames": true, + "strict": true, + "isolatedModules": true, + "skipLibCheck": true, + "paths": { + "@vlocode/apex": ["./packages/apex/src"], + "@vlocode/core": ["./packages/core/src"], + "@vlocode/util": ["./packages/util/src"], + "@vlocode/salesforce": ["./packages/salesforce/src"], + "@vlocode/vlocity": ["./packages/vlocity/src"], + "@vlocode/vlocity-deploy": ["./packages/vlocity-deploy/src"], + "@vlocode/omniscript": ["./packages/omniscript/src"] + } + } +} +``` + +### Package tsconfig.json Pattern +**Location:** `/home/runner/work/vlocode/vlocode/packages/*/tsconfig.json` + +```json +{ + "extends": "../../tsconfig", + "compilerOptions": { + "composite": true, + "outDir": "dist", + "rootDir": "src", + "declaration": true, + "declarationMap": false // Can be true for packages with deps + }, + "include": ["src/**/*"], + "references": [{ "path": "../util" }] // Only if has dependencies +} +``` + +### Standard package.json Pattern +```json +{ + "name": "@vlocode/package-name", + "version": "1.41.1", + "description": "Short description", + "main": "src/index.ts", + "publishConfig": { + "main": "dist/index.js", + "typings": "dist/index.d.ts", + "access": "public" + }, + "engines": { + "node": ">=20.0.0" + }, + "scripts": { + "build": "tsc -b", + "watch": "tsc -b --watch", + "test": "jest" + }, + "files": [ + "dist/**/*.d.ts", + "!dist/**/*.test.d.ts", + "dist/**/*.js", + "!dist/**/*.test.js" + ], + "dependencies": { + "@vlocode/core": "workspace:*" + }, + "devDependencies": { + "jest": "^29.7.0", + "ts-jest": "^29.3.4" + } +} +``` + +### Root pnpm-workspace.yaml +**Location:** `/home/runner/work/vlocode/vlocode/pnpm-workspace.yaml` + +```yaml +packages: + - 'packages/*' + - '!**/test/**' + +publicHoistPattern: + - 'eslint' + - 'tslib' + - 'eslint-config-*' + - 'eslint-plugin-*' + - 'prettier' + - '@rollup/*' + - 'rollup' + +resolutionMode: highest +dedupeDirectDeps: true +preferWorkspacePackages: true +strictPeerDependencies: true + +catalog: + typescript: "5.9.3" +``` + +--- + +## Command Registration in VSCode Extension + +**File:** `/home/runner/work/vlocode/vlocode/packages/vscode-extension/src/lib/commandRouter.ts` + +### Command Registration Pattern: + +```typescript +// 1. Define command class with @vscodeCommand decorator +@vscodeCommand(VlocodeCommand.selectOrg) +export default class SelectOrgCommand extends CommandBase { + public validate(): void { + // Validation logic + } + + public async execute(...args: any[]): Promise { + // Command logic + } +} + +// 2. CommandRouter automatically registers from decorator +@injectable({ lifecycle: LifecyclePolicy.singleton }) +export default class CommandRouter { + constructor(private readonly logger: Logger) { + // Iterates through commandRegistry and registers all commands + for (const [id, {command, options}] of Object.entries(commandRegistry)) { + this.register(id, command, options); + } + } + + public async execute(commandName: string, args?: any[]): Promise { + const command = this.commands.get(commandName); + if (command) { + await command.execute(...args); + } + } +} + +// 3. Base class provides utilities +export abstract class CommandBase implements Command { + protected readonly logger = LogManager.get(this.getName()); + protected readonly vlocode = lazy(() => container.get(VlocodeService)); + + public abstract execute(...args: any[]): any | Promise; + public validate?(...args: any[]): any | Promise; +} +``` + +### CommandOptions: +```typescript +interface CommandOptions { + params?: any[]; // Constructor parameters + executeParams?: any[]; // Execute method parameters + focusLog?: boolean; // Focus output channel on execution + showProductionWarning?: boolean; // Warn if production org +} +``` + +### Example Command Usage (DeployDatapackCommand): +```typescript +@vscodeCommand(VlocodeCommand.deployDatapack, { + focusLog: true, + showProductionWarning: true +}) +export class DeployDatapackCommand extends DatapackCommand { + private get strategy(): VlocityDeploy { + if (this.vlocode.config.deploymentMode === 'direct') { + return container.get(VlocodeDirectDeployment); + } + return container.get(VlocityToolsDeployment); + } + + public execute(...args: any[]): void | Promise { + // Implementation + } +} +``` + +--- + +## Summary for Creating New MCP Package + +Based on this exploration, here's what you need for a new `@vlocode/mcp` package: + +### File Structure: +``` +packages/mcp/ +β”œβ”€β”€ package.json # Standard pattern from @vlocode/util +β”œβ”€β”€ tsconfig.json # Extends root, composite: true +β”œβ”€β”€ jest.config.js +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ __tests__/ # Jest tests +β”‚ β”œβ”€β”€ index.ts # Main exports +β”‚ β”œβ”€β”€ mcpServer.ts # Main MCP server +β”‚ β”œβ”€β”€ resources/ # MCP resource handlers +β”‚ β”œβ”€β”€ tools/ # MCP tools +β”‚ β”œβ”€β”€ prompts/ # MCP prompts +β”‚ └── services/ # Business logic +└── CHANGELOG.md +``` + +### Key Dependencies: +- `@vlocode/core` - For DI container, Logger +- `@vlocode/util` - For utilities +- `@vlocode/salesforce` - For Salesforce APIs +- `@vlocode/vlocity-deploy` - For datapack APIs +- Core MCP library + +### TSConfig DI Requirements: +```json +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "useDefineForClassFields": false + } +} +``` + +### Service Pattern: +```typescript +import { injectable, inject, Logger } from '@vlocode/core'; +import { SalesforceService } from '@vlocode/salesforce'; + +@injectable() +export class MCPService { + @inject() private readonly logger: Logger; + @inject() private readonly sfService: SalesforceService; + + // Implementation using DI +} +``` + From 88cd54efbcb0b0741d95ea47b26c3dcd53a546eb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Mar 2026 23:37:29 +0000 Subject: [PATCH 3/4] feat: add @vlocode/mcp package with MCP server for Salesforce/Vlocity operations Co-authored-by: Codeneos <787686+Codeneos@users.noreply.github.com> --- MCP_EXPLORATION_INDEX.md | 212 -------- MCP_QUICK_REFERENCE.md | 221 --------- README_EXPLORATION.md | 211 -------- VLOCODE_EXPLORATION.md | 718 ---------------------------- packages/mcp/README.md | 98 ++++ packages/mcp/bin/run | 17 + packages/mcp/package.json | 61 +++ packages/mcp/src/index.ts | 82 ++++ packages/mcp/src/server.ts | 164 +++++++ packages/mcp/src/tools/datapacks.ts | 262 ++++++++++ packages/mcp/src/tools/metadata.ts | 133 ++++++ packages/mcp/src/tools/profiles.ts | 146 ++++++ packages/mcp/src/tools/schema.ts | 198 ++++++++ packages/mcp/tsconfig.json | 22 + packages/mcp/tsdown.config.mts | 46 ++ pnpm-lock.yaml | 525 ++++++++++++++++++-- tsconfig.json | 3 +- 17 files changed, 1729 insertions(+), 1390 deletions(-) delete mode 100644 MCP_EXPLORATION_INDEX.md delete mode 100644 MCP_QUICK_REFERENCE.md delete mode 100644 README_EXPLORATION.md delete mode 100644 VLOCODE_EXPLORATION.md create mode 100644 packages/mcp/README.md create mode 100755 packages/mcp/bin/run create mode 100644 packages/mcp/package.json create mode 100644 packages/mcp/src/index.ts create mode 100644 packages/mcp/src/server.ts create mode 100644 packages/mcp/src/tools/datapacks.ts create mode 100644 packages/mcp/src/tools/metadata.ts create mode 100644 packages/mcp/src/tools/profiles.ts create mode 100644 packages/mcp/src/tools/schema.ts create mode 100644 packages/mcp/tsconfig.json create mode 100644 packages/mcp/tsdown.config.mts diff --git a/MCP_EXPLORATION_INDEX.md b/MCP_EXPLORATION_INDEX.md deleted file mode 100644 index 2e19ebeb8..000000000 --- a/MCP_EXPLORATION_INDEX.md +++ /dev/null @@ -1,212 +0,0 @@ -# Vlocode MCP Exploration - Complete Index - -## πŸ“‹ Documents Created - -This exploration has created comprehensive documentation to guide MCP package creation: - -### 1. **VLOCODE_EXPLORATION.md** (718 lines) - - Complete detailed exploration of the entire monorepo - - All 10 questions answered in depth - - Code examples and file paths - - **Location:** `/home/runner/work/vlocode/vlocode/VLOCODE_EXPLORATION.md` - -### 2. **MCP_QUICK_REFERENCE.md** (This file) - - Quick summary of 10 key findings - - Quick copy-paste patterns - - File paths for reference - - MCP package template structure - - Checklist for creating new package - - **Location:** `/home/runner/work/vlocode/vlocode/MCP_QUICK_REFERENCE.md` - ---- - -## 🎯 Key Takeaways (30-second summary) - -| Aspect | Finding | -|--------|---------| -| **Monorepo Type** | pnpm workspace + Lerna Lite | -| **Packages** | 10 total (@vlocode/* + vscode extension) | -| **MCP Status** | βœ… NO existing MCP package | -| **DI Framework** | Custom IoC container with @injectable/@inject | -| **Exports Pattern** | Direct `export * from './module'` in src/index.ts | -| **Build System** | TypeScript with composite projects | -| **Commands** | Decorator-based (@vscodeCommand) | -| **Salesforce APIs** | Complete (SOAP, REST, Bulk, Metadata, Schema, Query) | -| **Deployment** | DatapackDeployer with 25+ component specs | -| **TsConfig** | Requires emitDecoratorMetadata, experimentalDecorators, useDefineForClassFields: false | - ---- - -## πŸ“š Quick Navigation - -### Understanding the Structure -β†’ Read: **VLOCODE_EXPLORATION.md Section 1-3** -- Monorepo packages and their purposes -- VSCode extension architecture -- Commands system - -### Creating Services with DI -β†’ Read: **VLOCODE_EXPLORATION.md Section 9** -- Container usage patterns -- @injectable and @inject decorators -- Code examples from datapackDeployer.ts - -### Exporting APIs -β†’ Read: **VLOCODE_EXPLORATION.md Section 5-7** -- How @vlocode/util exports simple utilities -- How @vlocode/salesforce exports complex APIs -- Datapack deployment specs - -### Configuration -β†’ Read: **VLOCODE_EXPLORATION.md Section 10** -- Complete tsconfig.json with all required settings -- package.json template -- pnpm-workspace.yaml configuration - -### Copy-Paste Templates -β†’ Read: **MCP_QUICK_REFERENCE.md** -- Package.json template -- tsconfig.json template -- DI service pattern -- MCP package directory structure - ---- - -## πŸ” Finding Specific Information - -### "How do I..." - -**...create a new service?** -β†’ See MCP_QUICK_REFERENCE.md - DI Container Usage Pattern (Section 9️⃣) -β†’ See VLOCODE_EXPLORATION.md Section 9 - Full DI examples - -**...export APIs from my package?** -β†’ See VLOCODE_EXPLORATION.md Section 5 - API Export Patterns -β†’ See @vlocode/util example (packages/util/src/index.ts) - -**...structure a new package?** -β†’ See VLOCODE_EXPLORATION.md Section 6 - Simple Package Structure -β†’ See MCP_QUICK_REFERENCE.md - MCP Package Template - -**...register a VSCode command?** -β†’ See VLOCODE_EXPLORATION.md Section 4 & Command Registration -β†’ File: packages/vscode-extension/src/lib/commandRouter.ts - -**...call Salesforce APIs?** -β†’ See VLOCODE_EXPLORATION.md Section 8 - Salesforce APIs -β†’ File: packages/salesforce/src/salesforceService.ts - -**...use the DI container?** -β†’ See VLOCODE_EXPLORATION.md Section 9 - DI Container Usage -β†’ Files: packages/core/src/di/*.ts - -**...configure TypeScript for DI?** -β†’ See VLOCODE_EXPLORATION.md Section 10 - Config Conventions -β†’ Root: /tsconfig.json (has all required settings) - ---- - -## πŸ“‚ Critical File Paths - -### Must-Read Implementation Files - -``` -packages/core/src/di/ -β”œβ”€β”€ container.ts # DI container (800+ lines) -β”œβ”€β”€ injectable.decorator.ts # @injectable implementation -└── inject.decorator.ts # @inject implementation - -packages/vscode-extension/src/lib/ -β”œβ”€β”€ commandRouter.ts # Command registration system -β”œβ”€β”€ commandBase.ts # Base command class -└── vlocodeService.ts # Main service - -packages/salesforce/src/ -β”œβ”€β”€ salesforceService.ts # Main Salesforce service (26KB) -β”œβ”€β”€ schema/ # Schema APIs -└── queryService.ts # Query service - -packages/vlocity-deploy/src/ -β”œβ”€β”€ datapackDeployer.ts # Main deployer -β”œβ”€β”€ datapackDeployment.ts # Deployment lifecycle -└── deploymentSpecs/ # 25+ component specifications -``` - -### Configuration Files - -``` -/tsconfig.json # Root config (has path mappings) -/pnpm-workspace.yaml # Workspace configuration -/lerna.json # Version management -/packages/*/tsconfig.json # Package-specific configs -/packages/*/package.json # Package manifests -``` - ---- - -## πŸš€ Next Steps - -1. **Read VLOCODE_EXPLORATION.md** for comprehensive understanding -2. **Reference MCP_QUICK_REFERENCE.md** for templates and patterns -3. **Create /packages/mcp/** directory -4. **Copy template files** from templates/ or similar packages -5. **Run pnpm install** to link the new package -6. **Build and test** with `pnpm build` and `pnpm test` - ---- - -## ✨ Key Insights for MCP Package - -### What to Leverage -- βœ… **@vlocode/core** - DI container, Logger, FileSystem -- βœ… **@vlocode/salesforce** - Complete Salesforce APIs -- βœ… **@vlocode/vlocity-deploy** - Datapack deployment engine -- βœ… **@vlocode/util** - Utilities (async, string, object helpers) -- βœ… **@vlocode/vlocity** - Vlocity-specific functionality - -### Convention to Follow -- πŸ“¦ `src/index.ts` with `export * from './modules'` -- πŸ—οΈ Services decorated with `@injectable()` -- πŸ”Œ Dependencies injected with `@inject()` -- πŸ“ TypeScript with decorators enabled -- πŸ§ͺ Jest tests in `src/__tests__/` -- πŸ“š TypeDoc comments for public APIs - -### Patterns to Adopt -- Container scoping for lifecycle management -- Property injection for optional dependencies -- Constructor injection for required dependencies -- Lazy evaluation where appropriate -- Logger integration for diagnostics - ---- - -## πŸ“– Document Statistics - -- **VLOCODE_EXPLORATION.md**: 718 lines, ~42 KB -- **MCP_QUICK_REFERENCE.md**: ~300 lines, ~10 KB -- **Total Coverage**: All 10 exploration questions answered -- **Code Examples**: 50+ snippets across both documents -- **File References**: 100+ specific file paths provided - ---- - -## ❓ Questions Answered - -βœ… 1. What is the overall structure of the monorepo? List the packages and what they do. -βœ… 2. Is there an existing MCP (Model Context Protocol) package? If so, where is it? -βœ… 3. What does the vscode-extension package look like? List its key files and structure. -βœ… 4. How are commands structured in the vscode-extension? Look at commands.yaml if it exists and show key examples. -βœ… 5. How do existing packages export their APIs? Look at package.json exports and main entry points. -βœ… 6. Show me the structure of an existing simple package (like @vlocode/util or @vlocode/cli) to understand the conventions. -βœ… 7. What Datapack-related APIs exist? Look at @vlocode/vlocity-deploy for key exports. -βœ… 8. What Salesforce-related APIs exist for describing objects and fields? -βœ… 9. How is the DI container used to get services? -βœ… 10. What tsconfig.json and package.json conventions are used for new packages? - -All with file paths, code snippets, and concrete details! - ---- - -**Created:** Vlocode Monorepo Exploration -**Status:** βœ… Complete with 2 comprehensive documents diff --git a/MCP_QUICK_REFERENCE.md b/MCP_QUICK_REFERENCE.md deleted file mode 100644 index 01ebc3eeb..000000000 --- a/MCP_QUICK_REFERENCE.md +++ /dev/null @@ -1,221 +0,0 @@ -# Vlocode Monorepo - Quick Reference for MCP Package Creation - -## πŸ“¦ 10 Key Findings - -### 1️⃣ Monorepo Structure -- **Type:** pnpm workspace + Lerna Lite versioning -- **Packages:** 10 total (9 @vlocode/* + 1 vlocode extension) -- **Core Stack:** TypeScript, DI Container, Logger, File System abstraction - -### 2️⃣ NO Existing MCP Package βœ… -- Clear opportunity for new `@vlocode/mcp` package -- No naming conflicts - -### 3️⃣ VSCode Extension at `/packages/vscode-extension` -``` -src/ -β”œβ”€β”€ commands/ # Datapack, apex, logs, metadata, profiles commands -β”œβ”€β”€ lib/ -β”‚ β”œβ”€β”€ commandRouter.ts # Command registration & routing -β”‚ β”œβ”€β”€ commandBase.ts # Base command class -β”‚ β”œβ”€β”€ vlocodeService.ts # Main extension service -β”‚ └── salesforce/vlocity/ # Domain logic -β”œβ”€β”€ treeDataProviders/ # Explorer views -β”œβ”€β”€ codeLensProviders/ # Code lenses -└── events/ # File watchers, handlers -``` - -### 4️⃣ Commands via @vscodeCommand Decorator -```typescript -@vscodeCommand('vlocode.selectOrg') -export class SelectOrgCommand extends CommandBase { - public async execute(...args) { } -} -// Commands automatically registered by CommandRouter -``` - -### 5️⃣ API Export Pattern (Simple) -All packages use: -```typescript -// src/index.ts -export * from './module1'; -export * from './module2'; -// ... -``` -No `exports` field needed - direct index import pattern - -### 6️⃣ Simple Package Example: @vlocode/util -``` -packages/util/ -β”œβ”€β”€ package.json (main: "src/index.ts") -β”œβ”€β”€ tsconfig.json (extends root) -β”œβ”€β”€ src/ -β”‚ β”œβ”€β”€ async.ts, cache.ts, collection.ts, ... -β”‚ └── index.ts (re-exports all) -└── dist/ (published output) -``` - -### 7️⃣ Datapack APIs: @vlocode/vlocity-deploy -```typescript -export * from './datapackDeployer'; -export * from './datapackDeployment'; -export * from './datapackDeploymentOptions'; -export * from './deploymentSpecs'; // 25+ specs (OmniScript, OmniCard, etc) -export * from './export'; -``` -**Key Classes:** DatapackDeployer, DatapackDeployment, DatapackDeploymentSpec - -### 8️⃣ Salesforce APIs: @vlocode/salesforce -```typescript -SalesforceService has: - .schema // SalesforceSchemaService - .deploy // SalesforceDeployService - .data // SalesforceDataService (CRUD) - .logs // DeveloperLogs - .batch // SalesforceBatchService - .tooling // Tooling API service - -Plus: queryBuilder, queryService, metadataRegistry, etc -``` - -### 9️⃣ DI Container Usage Pattern -```typescript -import { injectable, inject, container, LifecyclePolicy } from '@vlocode/core'; - -@injectable({ lifecycle: LifecyclePolicy.singleton }) -export class MyService { - @inject() private readonly dependency: OtherService; - - constructor( - @inject(SalesforceService) private sf: SalesforceService - ) {} -} - -// Usage -const instance = container.get(MyService); -const child = container.create(); // Child container -``` - -### πŸ”Ÿ Config Conventions -**tsconfig.json:** -```json -{ - "compilerOptions": { - "emitDecoratorMetadata": true, // ⚠️ REQUIRED - "experimentalDecorators": true, // ⚠️ REQUIRED - "useDefineForClassFields": false, // ⚠️ REQUIRED for @inject - "module": "node20", - "target": "es2022" - } -} -``` - -**package.json:** -```json -{ - "name": "@vlocode/package-name", - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "typings": "dist/index.d.ts" - }, - "files": ["dist/**/*.js", "dist/**/*.d.ts"], - "dependencies": { "@vlocode/core": "workspace:*" } -} -``` - ---- - -## πŸ“ Key File Paths for Reference - -### Core DI Framework -- `/packages/core/src/di/container.ts` - Container implementation (800+ lines) -- `/packages/core/src/di/injectable.decorator.ts` - @injectable decorator -- `/packages/core/src/di/inject.decorator.ts` - @inject decorator - -### Command System -- `/packages/vscode-extension/src/lib/commandRouter.ts` - Command registration -- `/packages/vscode-extension/src/lib/commandBase.ts` - Base command class -- `/packages/vscode-extension/src/commands/selectOrgCommand.ts` - Example command - -### Salesforce APIs -- `/packages/salesforce/src/salesforceService.ts` - Main service (26KB) -- `/packages/salesforce/src/schema/` - Schema APIs -- `/packages/salesforce/src/queryService.ts` - Query service - -### Deployment Engine -- `/packages/vlocity-deploy/src/datapackDeployer.ts` - Main deployer -- `/packages/vlocity-deploy/src/datapackDeployment.ts` - Deployment lifecycle -- `/packages/vlocity-deploy/src/deploymentSpecs/` - 25+ component specs - -### Configuration -- `/tsconfig.json` - Root config with path mappings -- `/pnpm-workspace.yaml` - Workspace configuration -- `/lerna.json` - Version management - ---- - -## οΏ½οΏ½ MCP Package Template - -``` -packages/mcp/ -β”œβ”€β”€ package.json -β”œβ”€β”€ tsconfig.json -β”œβ”€β”€ jest.config.js -β”œβ”€β”€ CHANGELOG.md -β”œβ”€β”€ README.md -└── src/ - β”œβ”€β”€ __tests__/ - β”‚ └── mcpServer.test.ts - β”œβ”€β”€ index.ts # Main exports - β”œβ”€β”€ mcpServer.ts # MCP server implementation - β”œβ”€β”€ resources/ - β”‚ β”œβ”€β”€ index.ts - β”‚ β”œβ”€β”€ datapackResource.ts - β”‚ └── schemaResource.ts - β”œβ”€β”€ tools/ - β”‚ β”œβ”€β”€ index.ts - β”‚ β”œβ”€β”€ deployTool.ts - β”‚ └── querySoqlTool.ts - β”œβ”€β”€ prompts/ - β”‚ β”œβ”€β”€ index.ts - β”‚ └── deploymentPrompts.ts - └── services/ - β”œβ”€β”€ index.ts - β”œβ”€β”€ mcpResourceManager.ts - └── mcpToolManager.ts -``` - ---- - -## πŸ”— Workspace Dependencies - -Use `workspace:*` for internal dependencies: -```json -{ - "dependencies": { - "@vlocode/core": "workspace:*", - "@vlocode/util": "workspace:*", - "@vlocode/salesforce": "workspace:*", - "@vlocode/vlocity": "workspace:*", - "@vlocode/vlocity-deploy": "workspace:*" - } -} -``` - ---- - -## βœ… Checklist for New Package - -- [ ] Create `/packages/mcp/` directory -- [ ] Copy `package.json` template and update name -- [ ] Copy `tsconfig.json` and set references -- [ ] Add `src/index.ts` with exports -- [ ] Add `src/__tests__/` with jest.config.js reference -- [ ] Add to pnpm-workspace.yaml (auto if in packages/*) -- [ ] Create services using @injectable/@inject pattern -- [ ] Run `pnpm install` to link package -- [ ] Run `pnpm build` to test compilation -- [ ] Run `pnpm test` for tests -- [ ] Update root `tsconfig.json` path mappings for "@vlocode/mcp" - diff --git a/README_EXPLORATION.md b/README_EXPLORATION.md deleted file mode 100644 index cb017745e..000000000 --- a/README_EXPLORATION.md +++ /dev/null @@ -1,211 +0,0 @@ -# πŸ“– Vlocode Monorepo Exploration - Start Here - -This directory now contains comprehensive documentation about the Vlocode monorepo structure, perfect for creating new packages like the proposed MCP (Model Context Protocol) package. - -## πŸš€ Quick Start - -**Time needed:** 20 minutes to understand everything - -### Step 1: Quick Overview (5 min) -Start with: **`MCP_QUICK_REFERENCE.md`** -- 10 key findings summarized -- Copy-paste templates for new packages -- Implementation checklist - -### Step 2: Detailed Reference (10 min) -Use: **`MCP_EXPLORATION_INDEX.md`** -- Navigation guide for specific topics -- File path reference -- "How do I..." quick answers - -### Step 3: Deep Dive (5 min) -Full details: **`VLOCODE_EXPLORATION.md`** -- 718 lines of comprehensive information -- 50+ code examples -- All 10 questions answered in depth - ---- - -## πŸ“‹ The Three Documents - -### 1. **MCP_QUICK_REFERENCE.md** ⭐ Start Here -- **Length:** 221 lines (~6 min read) -- **Best for:** Quick understanding and copy-paste templates -- **Contains:** - - 10 key findings with emojis - - package.json template - - tsconfig.json template - - DI Container pattern - - MCP package directory structure - - Implementation checklist - -### 2. **MCP_EXPLORATION_INDEX.md** πŸ—ΊοΈ Navigation Guide -- **Length:** 212 lines (~5 min read) -- **Best for:** Finding specific information -- **Contains:** - - Navigation by topic (structure, DI, APIs, config) - - "How do I..." quick links - - File path reference (grouped by purpose) - - Next steps checklist - - Key insights for MCP - -### 3. **VLOCODE_EXPLORATION.md** πŸ“š Complete Reference -- **Length:** 718 lines (~30 min read) -- **Best for:** Deep understanding and implementation details -- **Contains:** - - Question 1: Monorepo structure (10 packages) - - Question 2: MCP package status (βœ… doesn't exist) - - Question 3: VSCode extension structure - - Question 4: Command structure (commands.yaml) - - Question 5: API export patterns - - Question 6: Simple package structure (@vlocode/util) - - Question 7: Datapack APIs (@vlocode/vlocity-deploy) - - Question 8: Salesforce APIs (@vlocode/salesforce) - - Question 9: DI container usage patterns - - Question 10: Configuration conventions - - Plus: Command registration details, MCP package template - ---- - -## 🎯 What You'll Learn - -### About the Monorepo -- βœ… 10 total packages (9 @vlocode/* + 1 extension) -- βœ… pnpm workspace + Lerna Lite versioning -- βœ… TypeScript with custom DI container -- βœ… All packages follow consistent conventions - -### About APIs Available -- βœ… **@vlocode/core** - IoC container, Logger, FileSystem -- βœ… **@vlocode/util** - 25+ utility modules -- βœ… **@vlocode/salesforce** - Complete Salesforce integration (SOAP, REST, Bulk, Metadata, Schema, Query) -- βœ… **@vlocode/vlocity-deploy** - Datapack deployment with 25+ component specs -- βœ… **@vlocode/vlocity** - OmniStudio/Vlocity functionality - -### About Creating New Packages -- βœ… Exact package.json template -- βœ… Exact tsconfig.json configuration (with DI requirements) -- βœ… Directory structure conventions -- βœ… Export patterns (src/index.ts with export *) -- βœ… Service creation with @injectable/@inject decorators -- βœ… Testing setup with Jest - -### About the Command System -- βœ… @vscodeCommand decorator pattern -- βœ… CommandRouter automatic registration -- βœ… CommandBase class usage -- βœ… 40+ existing commands as examples - ---- - -## πŸ“‚ File Paths Quick Reference - -### Must-Read Implementation Files -``` -packages/core/src/di/ - β”œβ”€β”€ container.ts # DI container (main!) - β”œβ”€β”€ injectable.decorator.ts # @injectable - └── inject.decorator.ts # @inject - -packages/vscode-extension/src/lib/ - β”œβ”€β”€ commandRouter.ts # Command system - β”œβ”€β”€ commandBase.ts # Base command class - └── vlocodeService.ts # Main service - -packages/salesforce/src/ - β”œβ”€β”€ salesforceService.ts # Main Salesforce service - └── schema/ # Schema APIs - -packages/vlocity-deploy/src/ - β”œβ”€β”€ datapackDeployer.ts # Main deployer - └── deploymentSpecs/ # 25+ specs -``` - -### Configuration Files -``` -/tsconfig.json # Root config -/pnpm-workspace.yaml # Workspace -/lerna.json # Versioning -``` - ---- - -## 🎬 How to Use These Documents - -### If you want to understand the overall structure -β†’ Read: **MCP_QUICK_REFERENCE.md** Section 1️⃣ -β†’ Then: **VLOCODE_EXPLORATION.md** Section 1-3 - -### If you want to create a new service -β†’ Read: **MCP_QUICK_REFERENCE.md** Section 9️⃣ -β†’ Then: **VLOCODE_EXPLORATION.md** Section 9 - -### If you want to understand the command system -β†’ Read: **MCP_QUICK_REFERENCE.md** Section 4️⃣ -β†’ Then: **VLOCODE_EXPLORATION.md** Section 4 + Command Registration - -### If you want to create a new package -β†’ Read: **MCP_QUICK_REFERENCE.md** MCP Package Template -β†’ Then: **VLOCODE_EXPLORATION.md** Section 6 + 10 -β†’ Finally: **MCP_EXPLORATION_INDEX.md** βœ… Checklist - -### If you want specific information -β†’ Use: **MCP_EXPLORATION_INDEX.md** "How do I..." section -β†’ Get direct links to the right documentation - ---- - -## βœ… 10 Questions Answered - -All with file paths, code examples, and practical templates: - -1. βœ… **Monorepo structure?** - 10 packages described with purposes -2. βœ… **Existing MCP package?** - No (clear opportunity!) -3. βœ… **VSCode extension structure?** - Full directory tree -4. βœ… **Command structure?** - commands.yaml format with examples -5. βœ… **API exports?** - Pattern: export * from './module' -6. βœ… **Simple package structure?** - @vlocode/util example -7. βœ… **Datapack APIs?** - @vlocode/vlocity-deploy with 25+ specs -8. βœ… **Salesforce APIs?** - SalesforceService with subservices -9. βœ… **DI container usage?** - @injectable/@inject patterns -10. βœ… **Configuration conventions?** - Complete templates - ---- - -## πŸš€ Next Steps - -1. **Read MCP_QUICK_REFERENCE.md** (10 minutes) -2. **Browse MCP_EXPLORATION_INDEX.md** (5 minutes) -3. **Reference VLOCODE_EXPLORATION.md** as needed -4. **Create /packages/mcp/** directory -5. **Copy templates** from the documents -6. **Build and test** with `pnpm build` and `pnpm test` - ---- - -## πŸ“Š Statistics - -- **Total Lines:** 1,151 lines of documentation -- **Total Size:** ~35 KB -- **Code Examples:** 50+ -- **File References:** 100+ -- **Questions Answered:** 10/10 - ---- - -## πŸ’‘ Key Takeaway - -The Vlocode monorepo is well-structured with: -- ✨ **Consistent conventions** across all packages -- πŸ—οΈ **Powerful DI framework** for service management -- πŸ”Œ **Rich APIs** for Salesforce, Datapacks, and Vlocity -- πŸ“¦ **Simple export pattern** (no complex "exports" field) -- πŸ§ͺ **Full testing infrastructure** with Jest - -**Ready to create the @vlocode/mcp package!** πŸŽ‰ - ---- - -**Created:** March 15, 2025 -**Status:** βœ… Complete with comprehensive documentation -**Last Updated:** Latest exploration with all 10 questions answered diff --git a/VLOCODE_EXPLORATION.md b/VLOCODE_EXPLORATION.md deleted file mode 100644 index dc14537ce..000000000 --- a/VLOCODE_EXPLORATION.md +++ /dev/null @@ -1,718 +0,0 @@ -# Vlocode Monorepo Exploration Summary - -## 1. Monorepo Structure & Packages - -**Location:** `/home/runner/work/vlocode/vlocode` - -**Monorepo Type:** pnpm workspace with Lerna Lite versioning - -### Packages Overview: - -| Package | Location | Purpose | -|---------|----------|---------| -| **@vlocode/core** | `packages/core` | IoC container framework, logging, file system abstraction | -| **@vlocode/util** | `packages/util` | Utility library with async, string, object, salesforce helpers | -| **@vlocode/salesforce** | `packages/salesforce` | Salesforce APIs (SOAP, REST, Bulk, Metadata, Query, Deploy, Schema) | -| **@vlocode/vlocity** | `packages/vlocity` | Vlocity/OmniStudio shared functionality | -| **@vlocode/vlocity-deploy** | `packages/vlocity-deploy` | Datapack deployment library (core deployment engine) | -| **@vlocode/omniscript** | `packages/omniscript` | OmniScript compilation and processing | -| **@vlocode/apex** | `packages/apex` | Apex parser and grammar | -| **@vlocode/sass** | `packages/sass` | SASS compiler for Vlocity | -| **@vlocode/cli** | `packages/cli` | CLI tool for datapack deployment | -| **vlocode** | `packages/vscode-extension` | VSCode extension for Vlocity/OmniStudio development | - ---- - -## 2. No Existing MCP Package - -**Result:** βœ… No MCP (Model Context Protocol) package exists -- Searched for "mcp", "MCP", "model-context-protocol" in all `package.json` files -- No hits found -- This is a good opportunity to create a new `@vlocode/mcp` package - ---- - -## 3. VSCode Extension Package Structure - -**Location:** `/home/runner/work/vlocode/vlocode/packages/vscode-extension` - -### Key Files: -- **`package.json`** (71.1 KB) - Extension manifest with bin, publisher info -- **`commands.yaml`** - Declarative command definitions for VSCode menus -- **`src/extension.ts`** - Main entry point -- **`src/commands/`** - Command implementations -- **`src/lib/`** - Core services and utilities -- **`tsconfig.json`** - TypeScript configuration -- **`jest/`** - Test configuration - -### Directory Structure: -``` -packages/vscode-extension/ -β”œβ”€β”€ build/ # Build output -β”œβ”€β”€ commands.yaml # Command declarations -β”œβ”€β”€ jest/ # Jest test setup -β”œβ”€β”€ jest.config.js -β”œβ”€β”€ loader.mjs # Custom loader -β”œβ”€β”€ package.json # Extension manifest -β”œβ”€β”€ resources/ # Static resources -β”œβ”€β”€ src/ -β”‚ β”œβ”€β”€ commands/ # Command implementations -β”‚ β”‚ β”œβ”€β”€ apex/ -β”‚ β”‚ β”œβ”€β”€ datapacks/ -β”‚ β”‚ β”œβ”€β”€ developerLogs/ -β”‚ β”‚ β”œβ”€β”€ metadata/ -β”‚ β”‚ β”œβ”€β”€ profiles/ -β”‚ β”‚ β”œβ”€β”€ index.ts -β”‚ β”‚ β”œβ”€β”€ selectOrgCommand.ts -β”‚ β”‚ β”œβ”€β”€ execRestApiCommand.ts -β”‚ β”‚ └── ... -β”‚ β”œβ”€β”€ lib/ -β”‚ β”‚ β”œβ”€β”€ commandBase.ts # Base class for commands -β”‚ β”‚ β”œβ”€β”€ commandRouter.ts # Command registration & routing -β”‚ β”‚ β”œβ”€β”€ vlocodeService.ts # Main service -β”‚ β”‚ β”œβ”€β”€ vlocodeContext.ts # Context utilities -β”‚ β”‚ β”œβ”€β”€ config/ # Configuration -β”‚ β”‚ β”œβ”€β”€ ui/ # UI utilities -β”‚ β”‚ β”œβ”€β”€ vlocity/ # Vlocity-specific logic -β”‚ β”‚ └── salesforce/ # Salesforce-specific logic -β”‚ β”œβ”€β”€ treeDataProviders/ # Explorers (datapacks, logs, jobs) -β”‚ β”œβ”€β”€ codeLensProviders/ # Code lens implementations -β”‚ β”œβ”€β”€ contentProviders/ # Virtual content providers -β”‚ β”œβ”€β”€ events/ # Event handlers -β”‚ β”œβ”€β”€ symbolProviders/ # Symbol providers -β”‚ β”œβ”€β”€ constants.ts # Extension constants -β”‚ └── extension.ts # Main entry point -β”œβ”€β”€ syntax/ # Syntax definitions -β”œβ”€β”€ types/ # Type definitions -└── tsconfig.json -``` - ---- - -## 4. Commands Structure (commands.yaml) - -**File:** `/home/runner/work/vlocode/vlocode/packages/vscode-extension/commands.yaml` - -### Structure: -```yaml -# Command ID: vlocode.selectOrg -vlocode.selectOrg: - title: 'Vlocode: Select Salesforce Org' - group: v_vlocity - menus: - - menu: commandPalette - -# Datapack commands with conditionals -vlocode.refreshDatapack: - title: 'Datapack: Refresh from Org' - group: v_vlocity - when: 'vlocode.conditionalContextMenus == false || resourcePath in vlocode.datapacks' - menus: - - menu: commandPalette - - menu: explorer/context - - menu: editor/context - -vlocode.deployDatapack: - title: 'Datapack: Deploy to Org' - # ... similar structure - -vlocode.openSalesforce: - title: 'Datapack: Open in Org' - -vlocode.renameDatapack: - title: 'Datapack: Rename...' - -vlocode.cloneDatapack: - title: 'Datapack: Clone...' - -vlocode.exportDatapack: - title: 'Datapack: Export from Org' -``` - -### Key Examples: -- **Extension setup:** `vlocode.selectOrg` - Org selection -- **Vlocity basics:** Refresh, Deploy, Open, Rename, Clone, Export datapacks -- **Developer tools:** Execute Anonymous, REST API execution, Logs -- **Metadata:** Operations on Salesforce metadata -- **Groups:** Commands grouped with `group: v_vlocity` for organization - ---- - -## 5. API Export Patterns - -### @vlocode/util (Simple Utility Package) - -**File:** `/home/runner/work/vlocode/vlocode/packages/util/src/index.ts` - -```typescript -export * from './async'; // Promise utilities -export * from './cache'; // Caching -export * from './cancellationToken'; // Cancellation support -export * from './collection'; // Collection utilities -export * from './compiler'; // Compilation utilities -export * from './decorator'; // Decorator utilities -export * from './events'; // Event management -export * from './fs'; // File system -export * from './object'; // Object utilities -export * from './string'; // String utilities -export * from './salesforce'; // Salesforce-specific -export * from './sfdx'; // SFDX utilities -export * from './types'; // Type definitions -``` - -**Package Structure:** -- Uses `main: "src/index.ts"` for development -- Published to `dist/index.js` with `dist/index.d.ts` types -- No `exports` field (direct index export pattern) -- Include `dist/**/*.js`, `dist/**/*.d.ts` in files - -### @vlocode/core (DI Container Package) - -**File:** `/home/runner/work/vlocode/vlocode/packages/core/src/index.ts` - -```typescript -export * from './di/container'; -export * from './di/injectable.decorator'; -export * from './di/inject.decorator'; -export * from './fs'; -export * from './logging'; -export * from './logging/writers'; -export * from './deferredWorkQueue'; -``` - -**Key Exports:** -- Container class (DI framework) -- `@injectable` decorator -- `@inject` decorator -- Logger, LogManager -- FileSystem abstractions -- DeferredWorkQueue - -### @vlocode/salesforce (Complex API Package) - -**File:** `/home/runner/work/vlocode/vlocode/packages/salesforce/src/index.ts` - -```typescript -export * from './bulk'; -export * from './connection'; -export * from './deploy'; -export * from './schema'; -export * from './queryBuilder'; -export * from './queryService'; -export * from './salesforceService'; -export * from './salesforceSchemaService'; -export * from './metadataRegistry'; -// ... 30+ exports total -``` - -**Main Services:** -- **SalesforceService** - Main service with connections, APIs, batch, tooling, logs -- **SalesforceSchemaService** - Schema operations -- **SalesforceDataService** - Data operations -- **SalesforceBatchService** - Batch operations -- **QueryService**, **QueryBuilder** - SOQL operations -- **RestClient**, **SoapClient** - API clients - ---- - -## 6. Simple Package Structure (@vlocode/util) - -**Location:** `/home/runner/work/vlocode/vlocode/packages/util` - -### Directory Layout: -``` -packages/util/ -β”œβ”€β”€ CHANGELOG.md -β”œβ”€β”€ jest.config.js -β”œβ”€β”€ package.json # Main configuration -β”œβ”€β”€ tsconfig.json # TypeScript config -└── src/ - β”œβ”€β”€ __tests__/ # Jest test directory - β”œβ”€β”€ async.ts # ~15KB - async utilities - β”œβ”€β”€ cache.ts # ~9KB - caching - β”œβ”€β”€ cancellationToken.ts # ~2.6KB - β”œβ”€β”€ collection.ts # ~24KB - collection utils - β”œβ”€β”€ compiler.ts # ~4.4KB - β”œβ”€β”€ decorator.ts # ~7.4KB - β”œβ”€β”€ events.ts # ~12KB - event system - β”œβ”€β”€ fs.ts # ~3.9KB - β”œβ”€β”€ lazy.ts # ~1.6KB - β”œβ”€β”€ object.ts # ~31KB - object utilities - β”œβ”€β”€ salesforce.ts # ~6.9KB - β”œβ”€β”€ sfdx.ts # ~26KB - SFDX integration - β”œβ”€β”€ string.ts # ~16KB - string utilities - └── index.ts # Main export file -``` - -### package.json Pattern: -```json -{ - "name": "@vlocode/util", - "version": "1.41.1", - "description": "Vlocode utility library", - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "typings": "dist/index.d.ts", - "access": "public" - }, - "scripts": { - "build": "tsc -b", - "watch": "tsc -b --watch", - "test": "jest" - }, - "files": [ - "dist/**/*.d.ts", - "!dist/**/*.test.d.ts", - "dist/**/*.js", - "dist/**/*.json", - "!dist/**/*.test.js" - ], - "dependencies": { - "@salesforce/core": "3.31.18" - } -} -``` - -### tsconfig.json Pattern: -```json -{ - "extends": "../../tsconfig", - "compilerOptions": { - "composite": true, - "outDir": "dist", - "rootDir": "src", - "declaration": true, - "declarationMap": false - }, - "include": ["src/**/*"] -} -``` - ---- - -## 7. Datapack Deployment APIs (@vlocode/vlocity-deploy) - -**Location:** `/home/runner/work/vlocode/vlocode/packages/vlocity-deploy/src` - -### Main Exports: -```typescript -export * from './deploymentSpecs'; -export * from './types'; -export * from './convert'; -export * from './export'; -export * from './export/definition-converter'; -export * from './flexCard'; -export * from './datapackDeploy'; -export * from './datapackDeployer'; -export * from './datapackDeployment'; -export * from './datapackDeploymentEvent'; -export * from './datapackDeploymentError'; -export * from './datapackDeploymentOptions'; -export * from './datapackDeploymentRecord'; -export * from './datapackDeploymentRecordGroup'; -export * from './datapackDeploymentSpec'; -export * from './datapackDeploymentSpecRegistry'; -export * from './datapackDeploymentStatus'; -export * from './datapackRecordFactory'; -export * from './datapackLookupService'; -``` - -### Key Classes: -- **DatapackDeployer** - Main deployment orchestrator -- **DatapackDeployment** - Deployment instance with lifecycle -- **DatapackDeploymentOptions** - Configuration -- **DatapackDeploymentStatus** - Status tracking -- **DatapackRecordFactory** - Record creation -- **DatapackLookupService** - Lookup resolution - -### Deployment Specs (25+ specs): -Located in `packages/vlocity-deploy/src/deploymentSpecs/`: -- **Vlocity Components:** OmniScript, OmniUI Card, OmniDataTransform, DataRaptor, VlocityCard -- **OmniStudio:** omniScriptElementOrder, omniProcess, omniUICard -- **Salesforce:** decisionMatrix, Product2, contentVersion -- **Specialized:** calculationMatrix, customObjectMap, recordActivator, vlocityAction - -Each spec file defines deployment logic for its component type. - ---- - -## 8. Salesforce APIs for Objects & Fields - -**Location:** `/home/runner/work/vlocode/vlocode/packages/salesforce/src` - -### Schema-Related APIs: -```typescript -// packages/salesforce/src/schema/index.ts -export * from './types'; -export * from './compositeSchemaAccess'; -export * from './describeSchemaAccess'; -export * from './schemaDataStore'; -export * from './sobjectSchemaInfo'; -export * from './toolingApiSchemaAccess'; -``` - -### Key Services: -- **SalesforceSchemaService** - Main schema service -- **SalesforceDataService** - Data operations (CRUD) -- **SalesforceProfileService** - User profiles -- **SalesforceUserPermissions** - Permission handling - -### Available in SalesforceService: -```typescript -@injectable() -class SalesforceService { - // Properties providing subservices - get schema(): SalesforceSchemaService - get deploy(): SalesforceDeployService - get logs(): DeveloperLogs - get data(): SalesforceDataService - get tooling(): SalesforceDataService - get batch(): SalesforceBatchService - - // Key methods - async getOrganizationDetails() - async isPackageInstalled(packageName) - async getInstalledPackageDetails(packageName) - async isProductionOrg() - getJsForceConnection() -} -``` - ---- - -## 9. DI Container Usage Patterns - -**Location:** `/home/runner/work/vlocode/vlocode/packages/core/src/di/container.ts` - -### Key Concepts: - -#### Lifecycle Policies: -```typescript -enum LifecyclePolicy { - singleton = 1, // Single instance reused - transient = 2 // New instance per resolution -} -``` - -#### Decorators: - -**@injectable() - Mark class as injectable:** -```typescript -@injectable() -class MyService { - constructor(private dependency: OtherService) {} -} - -@injectable({ lifecycle: LifecyclePolicy.transient }) -class TransientService {} - -@injectable.singleton() -class SingletonService {} -``` - -**@inject() - Inject dependency:** -```typescript -class MyClass { - @inject() private readonly myService: SomeService; // Property injection - - constructor(@inject(SomeService) private service: SomeService) {} // Constructor injection -} -``` - -#### Usage Examples from codebase: - -**From datapackDeployer.ts:** -```typescript -@injectable({ lifecycle: LifecyclePolicy.transient }) -export class DatapackDeployer { - @inject() private readonly container: Container; - @inject() private readonly specRegistry: DatapackDeploymentSpecRegistry; - - // Services are injected and available - public async deploy(datapacks, options) { - this.container.get(SalesforceService).data.cache.configure({ enabled: false }); - } -} -``` - -**From datapackDeploy.ts:** -```typescript -const localContainer = container.create(); -localContainer.add(new Logger(...), ...options); -localContainer.add(new JsForceConnectionProvider(...), { - provides: [SalesforceConnectionProvider] -}); -localContainer.add(new VlocityNamespaceService()); - -const datapackLoader = localContainer.new(DatapackLoader); -return await localContainer.new(DatapackDeployer).deploy(datapacks, options); -``` - -#### Container Methods: -```typescript -// Global container -container.get(ServiceType) // Get instance -container.new(ServiceType) // Create new instance -container.add(instance, options) // Add service -container.create() // Create child container -container.resolveProperty(obj, key) // Resolve property - -// Class methods -Container.root // Access root container -Container.scope // Get current scope -``` - ---- - -## 10. Configuration Conventions (tsconfig.json & package.json) - -### Root tsconfig.json -**Location:** `/home/runner/work/vlocode/vlocode/tsconfig.json` - -```json -{ - "compilerOptions": { - "module": "node20", - "target": "es2022", - "lib": ["ES2023", "DOM"], - "outDir": "out", - "sourceMap": true, - "alwaysStrict": true, - "strictPropertyInitialization": false, - "useDefineForClassFields": false, // ⚠️ REQUIRED for @inject - "strictNullChecks": true, - "moduleResolution": "node16", - "emitDecoratorMetadata": true, // ⚠️ REQUIRED for DI - "experimentalDecorators": true, // ⚠️ REQUIRED for DI - "forceConsistentCasingInFileNames": true, - "strict": true, - "isolatedModules": true, - "skipLibCheck": true, - "paths": { - "@vlocode/apex": ["./packages/apex/src"], - "@vlocode/core": ["./packages/core/src"], - "@vlocode/util": ["./packages/util/src"], - "@vlocode/salesforce": ["./packages/salesforce/src"], - "@vlocode/vlocity": ["./packages/vlocity/src"], - "@vlocode/vlocity-deploy": ["./packages/vlocity-deploy/src"], - "@vlocode/omniscript": ["./packages/omniscript/src"] - } - } -} -``` - -### Package tsconfig.json Pattern -**Location:** `/home/runner/work/vlocode/vlocode/packages/*/tsconfig.json` - -```json -{ - "extends": "../../tsconfig", - "compilerOptions": { - "composite": true, - "outDir": "dist", - "rootDir": "src", - "declaration": true, - "declarationMap": false // Can be true for packages with deps - }, - "include": ["src/**/*"], - "references": [{ "path": "../util" }] // Only if has dependencies -} -``` - -### Standard package.json Pattern -```json -{ - "name": "@vlocode/package-name", - "version": "1.41.1", - "description": "Short description", - "main": "src/index.ts", - "publishConfig": { - "main": "dist/index.js", - "typings": "dist/index.d.ts", - "access": "public" - }, - "engines": { - "node": ">=20.0.0" - }, - "scripts": { - "build": "tsc -b", - "watch": "tsc -b --watch", - "test": "jest" - }, - "files": [ - "dist/**/*.d.ts", - "!dist/**/*.test.d.ts", - "dist/**/*.js", - "!dist/**/*.test.js" - ], - "dependencies": { - "@vlocode/core": "workspace:*" - }, - "devDependencies": { - "jest": "^29.7.0", - "ts-jest": "^29.3.4" - } -} -``` - -### Root pnpm-workspace.yaml -**Location:** `/home/runner/work/vlocode/vlocode/pnpm-workspace.yaml` - -```yaml -packages: - - 'packages/*' - - '!**/test/**' - -publicHoistPattern: - - 'eslint' - - 'tslib' - - 'eslint-config-*' - - 'eslint-plugin-*' - - 'prettier' - - '@rollup/*' - - 'rollup' - -resolutionMode: highest -dedupeDirectDeps: true -preferWorkspacePackages: true -strictPeerDependencies: true - -catalog: - typescript: "5.9.3" -``` - ---- - -## Command Registration in VSCode Extension - -**File:** `/home/runner/work/vlocode/vlocode/packages/vscode-extension/src/lib/commandRouter.ts` - -### Command Registration Pattern: - -```typescript -// 1. Define command class with @vscodeCommand decorator -@vscodeCommand(VlocodeCommand.selectOrg) -export default class SelectOrgCommand extends CommandBase { - public validate(): void { - // Validation logic - } - - public async execute(...args: any[]): Promise { - // Command logic - } -} - -// 2. CommandRouter automatically registers from decorator -@injectable({ lifecycle: LifecyclePolicy.singleton }) -export default class CommandRouter { - constructor(private readonly logger: Logger) { - // Iterates through commandRegistry and registers all commands - for (const [id, {command, options}] of Object.entries(commandRegistry)) { - this.register(id, command, options); - } - } - - public async execute(commandName: string, args?: any[]): Promise { - const command = this.commands.get(commandName); - if (command) { - await command.execute(...args); - } - } -} - -// 3. Base class provides utilities -export abstract class CommandBase implements Command { - protected readonly logger = LogManager.get(this.getName()); - protected readonly vlocode = lazy(() => container.get(VlocodeService)); - - public abstract execute(...args: any[]): any | Promise; - public validate?(...args: any[]): any | Promise; -} -``` - -### CommandOptions: -```typescript -interface CommandOptions { - params?: any[]; // Constructor parameters - executeParams?: any[]; // Execute method parameters - focusLog?: boolean; // Focus output channel on execution - showProductionWarning?: boolean; // Warn if production org -} -``` - -### Example Command Usage (DeployDatapackCommand): -```typescript -@vscodeCommand(VlocodeCommand.deployDatapack, { - focusLog: true, - showProductionWarning: true -}) -export class DeployDatapackCommand extends DatapackCommand { - private get strategy(): VlocityDeploy { - if (this.vlocode.config.deploymentMode === 'direct') { - return container.get(VlocodeDirectDeployment); - } - return container.get(VlocityToolsDeployment); - } - - public execute(...args: any[]): void | Promise { - // Implementation - } -} -``` - ---- - -## Summary for Creating New MCP Package - -Based on this exploration, here's what you need for a new `@vlocode/mcp` package: - -### File Structure: -``` -packages/mcp/ -β”œβ”€β”€ package.json # Standard pattern from @vlocode/util -β”œβ”€β”€ tsconfig.json # Extends root, composite: true -β”œβ”€β”€ jest.config.js -β”œβ”€β”€ src/ -β”‚ β”œβ”€β”€ __tests__/ # Jest tests -β”‚ β”œβ”€β”€ index.ts # Main exports -β”‚ β”œβ”€β”€ mcpServer.ts # Main MCP server -β”‚ β”œβ”€β”€ resources/ # MCP resource handlers -β”‚ β”œβ”€β”€ tools/ # MCP tools -β”‚ β”œβ”€β”€ prompts/ # MCP prompts -β”‚ └── services/ # Business logic -└── CHANGELOG.md -``` - -### Key Dependencies: -- `@vlocode/core` - For DI container, Logger -- `@vlocode/util` - For utilities -- `@vlocode/salesforce` - For Salesforce APIs -- `@vlocode/vlocity-deploy` - For datapack APIs -- Core MCP library - -### TSConfig DI Requirements: -```json -{ - "compilerOptions": { - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "useDefineForClassFields": false - } -} -``` - -### Service Pattern: -```typescript -import { injectable, inject, Logger } from '@vlocode/core'; -import { SalesforceService } from '@vlocode/salesforce'; - -@injectable() -export class MCPService { - @inject() private readonly logger: Logger; - @inject() private readonly sfService: SalesforceService; - - // Implementation using DI -} -``` - diff --git a/packages/mcp/README.md b/packages/mcp/README.md new file mode 100644 index 000000000..420c04b21 --- /dev/null +++ b/packages/mcp/README.md @@ -0,0 +1,98 @@ +# @vlocode/mcp + +Vlocode **Model Context Protocol (MCP)** server that enables AI agents (GitHub Copilot, Claude, etc.) to interact with Salesforce and Vlocity datapacks directly from your IDE. + +## Features + +The server exposes the following tools: + +| Tool | Description | +|------|-------------| +| `deploy_datapacks` | Deploy Vlocity datapacks from local folders to Salesforce | +| `retrieve_datapacks` | Export/retrieve Salesforce objects as Vlocity datapacks | +| `deploy_metadata` | Deploy Salesforce metadata (Apex, LWC, etc.) | +| `list_sobjects` | List all Salesforce objects in the connected org | +| `describe_sobject` | Describe a Salesforce object with its fields and metadata | +| `describe_sobject_field` | Describe a specific field on a Salesforce object | +| `list_profiles` | List all Salesforce profiles | +| `add_fls_to_profile` | Add Field Level Security permissions to a profile | + +## Installation + +```bash +npm install -g @vlocode/mcp +``` + +## Usage + +### Command-line options + +``` +vlocode-mcp [options] + +Options: + -u, --user SFDX username or alias to connect to Salesforce + -i, --instance Salesforce instance URL (default: login.salesforce.com) + --log-level Log level: debug | verbose | info | warn | error + --debug Enable debug logging + --verbose Enable verbose logging + -h, --help Show help +``` + +### VS Code MCP configuration + +Add the following to your `.vscode/mcp.json` (or VS Code User Settings) to make the Vlocode MCP server available to GitHub Copilot and other agents: + +```json +{ + "servers": { + "vlocode": { + "type": "stdio", + "command": "npx", + "args": ["-y", "@vlocode/mcp", "--user", "myorg@example.com"] + } + } +} +``` + +Replace `myorg@example.com` with your SFDX org username or alias. + +### Authentication + +The server uses SFDX authentication. Ensure you have authenticated with the target org before starting the server: + +```bash +sf org login web --alias myorg +``` + +## Examples + +### Deploy datapacks + +An agent can deploy datapacks using the `deploy_datapacks` tool: + +``` +Deploy the datapacks in ./datapacks/OmniScript to my Salesforce org +``` + +### Retrieve datapacks + +``` +Export the OmniScript record with ID a1B000000000000 as a datapack to ./output +``` + +### Describe a Salesforce object + +``` +What fields does the Account object have? +``` + +### Add FLS to a profile + +``` +Grant read access to Account.Phone and Account.Fax for the Standard profile +``` + +## License + +MIT diff --git a/packages/mcp/bin/run b/packages/mcp/bin/run new file mode 100755 index 000000000..08da17f99 --- /dev/null +++ b/packages/mcp/bin/run @@ -0,0 +1,17 @@ +#!/usr/bin/env node +import { existsSync } from 'node:fs'; +import { join, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +// Recreate __dirname for ESM +const __dirname = dirname(fileURLToPath(import.meta.url)); + +if (existsSync(join(__dirname, '../dist/mcp.mjs'))) { + await import('../dist/mcp.mjs'); +} else { + // Development mode: run via ts-node / tsx + const { register } = await import('node:module'); + const { pathToFileURL } = await import('node:url'); + register('ts-node/esm', pathToFileURL('./')); + await import('../src/index.ts'); +} diff --git a/packages/mcp/package.json b/packages/mcp/package.json new file mode 100644 index 000000000..c6afe1a38 --- /dev/null +++ b/packages/mcp/package.json @@ -0,0 +1,61 @@ +{ + "name": "@vlocode/mcp", + "version": "1.41.2", + "description": "Vlocode MCP (Model Context Protocol) server for Salesforce and Vlocity datapack operations", + "keywords": [ + "Vlocity", + "Salesforce", + "Datapacks", + "MCP", + "ModelContextProtocol" + ], + "bin": { + "vlocode-mcp": "bin/run" + }, + "main": "src/index.ts", + "type": "module", + "publishConfig": { + "main": "dist/mcp.mjs", + "access": "public" + }, + "readme": "./README.md", + "engines": { + "node": ">=20.0.0" + }, + "scripts": { + "watch": "tsdown -c tsdown.config.mts --watch", + "build": "tsdown -c tsdown.config.mts", + "prepublish": "pnpm run clean && pnpm run build", + "pack-only": "pnpm pack", + "clean": "shx rm -rf ./dist './*.tgz' './src/**/*.{d.ts,ts.map,js.map,js}'" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Codeneos/vlocode.git" + }, + "author": { + "name": "Peter van Gulik", + "email": "peter@curlybracket.nl" + }, + "files": [ + "/dist", + "/bin" + ], + "license": "MIT", + "bugs": { + "url": "https://github.com/Codeneos/vlocode/issues" + }, + "homepage": "https://github.com/Codeneos/vlocode#readme", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.27.1" + }, + "devDependencies": { + "@vlocode/core": "workspace:*", + "@vlocode/salesforce": "workspace:*", + "@vlocode/util": "workspace:*", + "@vlocode/vlocity": "workspace:*", + "@vlocode/vlocity-deploy": "workspace:*", + "shx": "^0.3.4" + }, + "publisher": "curlybracket" +} diff --git a/packages/mcp/src/index.ts b/packages/mcp/src/index.ts new file mode 100644 index 000000000..056c6fd84 --- /dev/null +++ b/packages/mcp/src/index.ts @@ -0,0 +1,82 @@ +import { LogLevel } from '@vlocode/core'; +import { startMcpServer, type VlocodeMcpOptions } from './server.js'; + +/** + * Parse a minimal set of command-line options for the MCP server. + * We deliberately keep this lightweight (no Commander dependency) + * because the MCP server is meant to be embedded in agent configurations. + */ +function parseArgs(argv: string[]): VlocodeMcpOptions { + const opts: VlocodeMcpOptions = {}; + + for (let i = 2; i < argv.length; i++) { + const arg = argv[i]; + + if ((arg === '-u' || arg === '--user') && argv[i + 1]) { + opts.user = argv[++i]; + } else if ((arg === '-i' || arg === '--instance') && argv[i + 1]) { + opts.instance = argv[++i]; + } else if (arg === '--debug') { + opts.logLevel = LogLevel.debug; + } else if (arg === '--verbose') { + opts.logLevel = LogLevel.verbose; + } else if ((arg === '--log-level') && argv[i + 1]) { + const level = argv[++i].toLowerCase(); + const levelMap: Record = { + debug: LogLevel.debug, + verbose: LogLevel.verbose, + info: LogLevel.info, + warn: LogLevel.warn, + error: LogLevel.error, + }; + opts.logLevel = levelMap[level] ?? LogLevel.warn; + } else if (arg === '--help' || arg === '-h') { + printHelp(); + process.exit(0); + } + } + + return opts; +} + +function printHelp() { + process.stderr.write( + [ + 'Usage: vlocode-mcp [options]', + '', + 'Start the Vlocode MCP (Model Context Protocol) server over stdio.', + '', + 'Options:', + ' -u, --user SFDX username or alias to connect to Salesforce', + ' -i, --instance Salesforce instance URL (default: login.salesforce.com)', + ' --log-level Log level: debug | verbose | info | warn | error (default: warn)', + ' --debug Enable debug logging', + ' --verbose Enable verbose logging', + ' -h, --help Show this help message', + '', + 'MCP tools exposed:', + ' deploy_datapacks Deploy Vlocity datapacks from local folders', + ' retrieve_datapacks Export Salesforce objects as datapacks', + ' deploy_metadata Deploy Salesforce metadata', + ' list_sobjects List all Salesforce objects', + ' describe_sobject Describe a Salesforce object and its fields', + ' describe_sobject_field Describe a specific field on a Salesforce object', + ' list_profiles List all Salesforce profiles', + ' add_fls_to_profile Add Field Level Security to a profile', + '', + 'Example VS Code MCP configuration (.vscode/mcp.json):', + ' {', + ' "servers": {', + ' "vlocode": {', + ' "type": "stdio",', + ' "command": "npx",', + ' "args": ["-y", "@vlocode/mcp", "--user", "myorg@example.com"]', + ' }', + ' }', + ' }', + ].join('\n') + '\n' + ); +} + +const options = parseArgs(process.argv); +await startMcpServer(options); diff --git a/packages/mcp/src/server.ts b/packages/mcp/src/server.ts new file mode 100644 index 000000000..154239dc1 --- /dev/null +++ b/packages/mcp/src/server.ts @@ -0,0 +1,164 @@ +import { CachedFileSystemAdapter, container, Logger, LogLevel, LogManager, NodeFileSystem, FileSystem, type LogEntry, type LogWriter } from '@vlocode/core'; +import { + InteractiveConnectionProvider, + SalesforceConnectionProvider, + SfdxConnectionProvider, +} from '@vlocode/salesforce'; +import { VlocityNamespaceService } from '@vlocode/vlocity'; +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { + CallToolRequestSchema, + ErrorCode, + ListToolsRequestSchema, + McpError, +} from '@modelcontextprotocol/sdk/types.js'; +import { readFileSync } from 'fs'; +import { join, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +import { datapackTools, executeDatapackTool } from './tools/datapacks.js'; +import { metadataTools, executeMetadataTool } from './tools/metadata.js'; +import { schemaTools, executeSchemaTool } from './tools/schema.js'; +import { profileTools, executeProfileTool } from './tools/profiles.js'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +// Read version from package.json +let version = '1.0.0'; +try { + const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8')); + version = pkg.version ?? version; +} catch { + // ignore +} + +export interface VlocodeMcpOptions { + /** SFDX username or alias to connect to Salesforce */ + user?: string; + /** Salesforce instance URL (e.g. login.salesforce.com) */ + instance?: string; + /** Log level */ + logLevel?: LogLevel; +} + +/** + * Starts the Vlocode MCP server over stdio. + * + * The server exposes tools for deploying and retrieving Vlocity datapacks, + * describing Salesforce objects, managing profiles, and deploying metadata. + */ +export async function startMcpServer(options: VlocodeMcpOptions = {}) { + // Configure logging β€” MCP communicates over stdio so all log output must + // go to stderr to avoid corrupting the protocol stream. + const stderrWriter: LogWriter = { + write({ level, time, category, message }: LogEntry) { + const ts = (time ?? new Date()).toISOString(); + process.stderr.write(`${ts} [${LogLevel[level]}] [${category}]: ${message}\n`); + }, + }; + LogManager.registerWriter(stderrWriter); + LogManager.setGlobalLogLevel(options.logLevel ?? LogLevel.warn); + + const logger = LogManager.get('vlocode-mcp'); + logger.info('Starting Vlocode MCP server v%s', version); + + // Create an isolated DI container for this server instance + const localContainer = container.create(); + + // Register connection provider based on authentication options + if (options.user) { + localContainer.add(new SfdxConnectionProvider(options.user), { + provides: [SalesforceConnectionProvider], + }); + } else if (options.instance) { + localContainer.add( + new InteractiveConnectionProvider(`https://${options.instance}`), + { provides: [SalesforceConnectionProvider] } + ); + } else { + // Fall back to interactive provider using the default Salesforce login URL + localContainer.add( + new InteractiveConnectionProvider('https://login.salesforce.com'), + { provides: [SalesforceConnectionProvider] } + ); + } + + // Provide a cached file system adapter for loading/writing local files + localContainer.add(new CachedFileSystemAdapter(new NodeFileSystem()), { + provides: [FileSystem], + }); + + // Register a named logger in the container + localContainer.registerProvider(Logger, (receiver) => + LogManager.get(receiver ?? 'vlocode-mcp') + ); + + // Register the Vlocity namespace service so namespace placeholders are resolved. + // Initialization is deferred to the first tool call so the server starts quickly. + const nsService = localContainer.get(VlocityNamespaceService); + let nsInitialized = false; + + async function ensureNamespaceInitialized() { + if (!nsInitialized) { + await nsService.initialize(localContainer.get(SalesforceConnectionProvider)); + localContainer.add(nsService); + nsInitialized = true; + } + } + + // ------------------------------------------------------------------ // + // Build the MCP server + // ------------------------------------------------------------------ // + const server = new Server( + { name: 'vlocode', version }, + { capabilities: { tools: {} } } + ); + + // List all available tools + server.setRequestHandler(ListToolsRequestSchema, async () => ({ + tools: [ + ...datapackTools, + ...metadataTools, + ...schemaTools, + ...profileTools, + ], + })); + + // Dispatch tool calls to the appropriate handler + server.setRequestHandler(CallToolRequestSchema, async (request) => { + const { name, arguments: args } = request.params; + + try { + // Initialize the Vlocity namespace service on the first tool call + await ensureNamespaceInitialized(); + + if (datapackTools.some((t) => t.name === name)) { + return await executeDatapackTool(name, args ?? {}, localContainer); + } + if (metadataTools.some((t) => t.name === name)) { + return await executeMetadataTool(name, args ?? {}, localContainer); + } + if (schemaTools.some((t) => t.name === name)) { + return await executeSchemaTool(name, args ?? {}, localContainer); + } + if (profileTools.some((t) => t.name === name)) { + return await executeProfileTool(name, args ?? {}, localContainer); + } + throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); + } catch (err: unknown) { + if (err instanceof McpError) { + throw err; + } + const message = err instanceof Error ? err.message : String(err); + return { + content: [{ type: 'text' as const, text: `Error: ${message}` }], + isError: true, + }; + } + }); + + const transport = new StdioServerTransport(); + await server.connect(transport); + logger.info('Vlocode MCP server ready'); +} diff --git a/packages/mcp/src/tools/datapacks.ts b/packages/mcp/src/tools/datapacks.ts new file mode 100644 index 000000000..ec7def4a5 --- /dev/null +++ b/packages/mcp/src/tools/datapacks.ts @@ -0,0 +1,262 @@ +import { mkdir, writeFile } from 'fs/promises'; +import { join } from 'path'; +import type { Container } from '@vlocode/core'; +import { + DatapackDeployer, + DatapackDeploymentOptions, + DatapackExporter, + DatapackExportDefinitionStore, +} from '@vlocode/vlocity-deploy'; +import { DatapackLoader } from '@vlocode/vlocity'; +import type { Tool } from '@modelcontextprotocol/sdk/types.js'; + +export const datapackTools: Tool[] = [ + { + name: 'deploy_datapacks', + description: + 'Deploy one or more Vlocity datapacks from local folders to Salesforce. ' + + 'Provide a list of folder paths that contain datapack files (*_DataPack.json).', + inputSchema: { + type: 'object', + properties: { + paths: { + type: 'array', + items: { type: 'string' }, + description: + 'List of absolute or relative paths to folders containing datapack files.', + minItems: 1, + }, + continueOnError: { + type: 'boolean', + description: + 'Continue deploying even if some datapacks fail to load. Defaults to false.', + default: false, + }, + strictOrder: { + type: 'boolean', + description: + 'Enforce strict deployment order for dependent datapacks. Defaults to false.', + default: false, + }, + deltaCheck: { + type: 'boolean', + description: + 'Only deploy datapacks that differ from the target org. Defaults to false.', + default: false, + }, + }, + required: ['paths'], + }, + }, + { + name: 'retrieve_datapacks', + description: + 'Export/retrieve one or more Salesforce objects as Vlocity datapacks. ' + + 'Objects are identified by their Salesforce IDs or by a SOQL query. ' + + 'The datapacks are written to the specified output directory.', + inputSchema: { + type: 'object', + properties: { + ids: { + type: 'array', + items: { type: 'string' }, + description: + 'List of Salesforce record IDs to export as datapacks.', + }, + query: { + type: 'string', + description: + 'SOQL query to identify the records to export. ' + + 'Use this instead of `ids` when you need to filter records.', + }, + outputDir: { + type: 'string', + description: + 'Absolute or relative path to the directory where the exported datapack files will be written.', + }, + expand: { + type: 'boolean', + description: + 'Expand each datapack into separate files (one file per child record / resource). Defaults to true.', + default: true, + }, + exportDefinitions: { + type: 'string', + description: + 'Path to a YAML or JSON file containing custom export definitions. ' + + 'When omitted, the built-in definitions are used.', + }, + }, + required: ['outputDir'], + }, + }, +]; + +export async function executeDatapackTool( + name: string, + args: Record, + localContainer: Container +) { + if (name === 'deploy_datapacks') { + return deployDatapacks(args, localContainer); + } + if (name === 'retrieve_datapacks') { + return retrieveDatapacks(args, localContainer); + } + throw new Error(`Unknown datapack tool: ${name}`); +} + +async function deployDatapacks( + args: Record, + localContainer: Container +) { + const paths = args['paths'] as string[]; + const options: DatapackDeploymentOptions = { + continueOnError: (args['continueOnError'] as boolean) ?? false, + strictOrder: (args['strictOrder'] as boolean) ?? false, + deltaCheck: (args['deltaCheck'] as boolean) ?? false, + }; + + const loader = localContainer.new(DatapackLoader); + const datapacks = ( + await Promise.all(paths.map((p) => loader.loadDatapacksFromFolder(p))) + ).flat(1); + + if (datapacks.length === 0) { + return { + content: [ + { + type: 'text' as const, + text: `No datapacks found in the specified folders: ${paths.join(', ')}`, + }, + ], + }; + } + + const deployer = localContainer.new(DatapackDeployer); + const deployment = await deployer.deploy(datapacks, options); + const status = deployment.getStatus(); + + const succeeded = status.datapacks.filter((d) => d.status === 'success').length; + const failed = status.datapacks.filter((d) => d.status === 'error').length; + const partial = status.datapacks.filter((d) => d.status === 'partialSuccess').length; + + const lines: string[] = [ + `Deployment complete: ${succeeded} succeeded, ${failed} failed, ${partial} partial (${status.total} total)`, + ]; + + for (const d of status.datapacks) { + if (d.status === 'error' || d.status === 'partialSuccess') { + lines.push(` [${d.status.toUpperCase()}] ${d.datapack}:`); + for (const msg of d.messages) { + lines.push( + ` ${msg.type === 'error' ? '[ERROR]' : '[WARN]'} ${msg.message}` + ); + } + } + } + + return { + content: [{ type: 'text' as const, text: lines.join('\n') }], + isError: failed > 0, + }; +} + +async function retrieveDatapacks( + args: Record, + localContainer: Container +) { + const outputDir = args['outputDir'] as string; + const doExpand = (args['expand'] as boolean) ?? true; + + // Load custom export definitions when provided + if (args['exportDefinitions']) { + const { readFileSync } = await import('fs'); + const content = readFileSync(args['exportDefinitions'] as string, 'utf-8'); + let definitions: Record; + try { + const yaml = await import('js-yaml'); + definitions = yaml.load(content) as Record; + } catch { + definitions = JSON.parse(content) as Record; + } + localContainer.get(DatapackExportDefinitionStore).load( + definitions as Record> + ); + } + + // Resolve the list of IDs to export + let ids: string[]; + if (args['query']) { + const { SalesforceService } = await import('@vlocode/salesforce'); + const records = await localContainer + .get(SalesforceService) + .data.query(args['query'] as string); + if (records.length === 0) { + return { + content: [ + { + type: 'text' as const, + text: `No records found for the query: ${args['query']}`, + }, + ], + }; + } + ids = records.map((r) => r.Id as string); + } else if (args['ids'] && Array.isArray(args['ids'])) { + ids = args['ids'] as string[]; + } else { + return { + content: [ + { + type: 'text' as const, + text: 'Either `ids` or `query` must be specified.', + }, + ], + isError: true, + }; + } + + const exporter = localContainer.new(DatapackExporter); + const written: string[] = []; + await mkdir(outputDir, { recursive: true }); + + for (const id of ids) { + if (doExpand) { + const expanded = await exporter.exportObjectAndExpand(id); + const folderPath = join(outputDir, expanded.folder); + await mkdir(folderPath, { recursive: true }); + + for (const [fileName, fileData] of Object.entries(expanded.files)) { + const filePath = join(folderPath, fileName); + await writeFile(filePath, fileData); + written.push(filePath); + } + } else { + const result = await exporter.exportObject(id); + const baseName = (result.datapack['Name'] as string | undefined) ?? id; + const dpPath = join(outputDir, baseName + '_DataPack.json'); + const pkPath = join(outputDir, baseName + '_ParentKeys.json'); + await writeFile(dpPath, JSON.stringify(result.datapack, null, 4), 'utf-8'); + await writeFile( + pkPath, + JSON.stringify(result.parentKeys, null, 4), + 'utf-8' + ); + written.push(dpPath, pkPath); + } + } + + return { + content: [ + { + type: 'text' as const, + text: [ + `Exported ${ids.length} datapack(s) to '${outputDir}'.`, + 'Files written:', + ...written.map((f) => ` ${f}`), + ].join('\n'), + }, + ], + }; +} diff --git a/packages/mcp/src/tools/metadata.ts b/packages/mcp/src/tools/metadata.ts new file mode 100644 index 000000000..fa7ff45d7 --- /dev/null +++ b/packages/mcp/src/tools/metadata.ts @@ -0,0 +1,133 @@ +import type { Container } from '@vlocode/core'; +import { + SalesforceDeployService, + SalesforcePackageBuilder, + SalesforcePackageType, +} from '@vlocode/salesforce'; +import type { Tool } from '@modelcontextprotocol/sdk/types.js'; + +export const metadataTools: Tool[] = [ + { + name: 'deploy_metadata', + description: + 'Deploy Salesforce metadata (Apex classes, triggers, LWC components, etc.) ' + + 'from local source files or directories to the target Salesforce org. ' + + 'Accepts any files or folders that form a valid Salesforce metadata package.', + inputSchema: { + type: 'object', + properties: { + paths: { + type: 'array', + items: { type: 'string' }, + description: + 'List of absolute paths to metadata source files or directories to deploy. ' + + 'Directories are scanned recursively. ' + + 'Accepts standard Salesforce metadata layout (e.g. force-app/main/default).', + minItems: 1, + }, + checkOnly: { + type: 'boolean', + description: + 'Validate the deployment without committing changes (dry-run). Defaults to false.', + default: false, + }, + ignoreWarnings: { + type: 'boolean', + description: + 'Treat deployment warnings as non-fatal. Defaults to true.', + default: true, + }, + rollbackOnError: { + type: 'boolean', + description: + 'Roll back the entire deployment when any component fails. Defaults to false.', + default: false, + }, + apiVersion: { + type: 'string', + description: + 'Salesforce API version to use for the deployment (e.g. "59.0"). ' + + 'Defaults to the connection\'s default API version.', + }, + }, + required: ['paths'], + }, + }, +]; + +export async function executeMetadataTool( + name: string, + args: Record, + localContainer: Container +) { + if (name === 'deploy_metadata') { + return deployMetadata(args, localContainer); + } + throw new Error(`Unknown metadata tool: ${name}`); +} + +async function deployMetadata( + args: Record, + localContainer: Container +) { + const paths = args['paths'] as string[]; + const apiVersion = args['apiVersion'] as string | undefined; + const checkOnly = (args['checkOnly'] as boolean) ?? false; + const ignoreWarnings = (args['ignoreWarnings'] as boolean) ?? true; + const rollbackOnError = (args['rollbackOnError'] as boolean) ?? false; + + // Build the metadata package + const packageBuilder = localContainer.new( + SalesforcePackageBuilder, + SalesforcePackageType.deploy, + apiVersion + ); + await packageBuilder.addFiles(paths); + + const components = packageBuilder.getPackageComponents(); + if (components.length === 0) { + return { + content: [ + { + type: 'text' as const, + text: `No deployable metadata components found in the specified paths: ${paths.join(', ')}`, + }, + ], + }; + } + + const sfPackage = await packageBuilder.build(); + const deployService = localContainer.get(SalesforceDeployService); + + const result = await deployService.deployPackage(sfPackage, { + checkOnly, + ignoreWarnings, + rollbackOnError, + allowMissingFiles: false, + purgeOnDelete: true, + singlePackage: true, + }); + + const lines: string[] = [ + `Deployment ${result.success ? 'SUCCEEDED' : 'FAILED'} [${result.status}]`, + ` Components: ${result.numberComponentsDeployed ?? 0}/${result.numberComponentsTotal ?? components.length} deployed, ${result.numberComponentErrors ?? 0} errors`, + ]; + + if (result.details?.componentFailures) { + const failures = Array.isArray(result.details.componentFailures) + ? result.details.componentFailures + : [result.details.componentFailures]; + for (const failure of failures) { + lines.push(` [ERROR] ${failure.fileName}: ${failure.problem}`); + } + } + + if (result.errorMessage) { + lines.push(` ${result.errorMessage}`); + } + + return { + content: [{ type: 'text' as const, text: lines.join('\n') }], + isError: !result.success, + }; +} diff --git a/packages/mcp/src/tools/profiles.ts b/packages/mcp/src/tools/profiles.ts new file mode 100644 index 000000000..931cea07c --- /dev/null +++ b/packages/mcp/src/tools/profiles.ts @@ -0,0 +1,146 @@ +import type { Container } from '@vlocode/core'; +import { + SalesforceProfileService, + SalesforceConnectionProvider, + SalesforceFieldPermission, +} from '@vlocode/salesforce'; +import type { Tool } from '@modelcontextprotocol/sdk/types.js'; + +export const profileTools: Tool[] = [ + { + name: 'list_profiles', + description: + 'List all Salesforce profiles available in the connected org. ' + + 'Returns the developer name (fullName) for each profile.', + inputSchema: { + type: 'object', + properties: {}, + }, + }, + { + name: 'add_fls_to_profile', + description: + 'Add or update Field Level Security (FLS) permissions for one or more fields on a Salesforce profile. ' + + 'Each field can be set to "editable" (read + write), "readable" (read-only), or "none" (no access).', + inputSchema: { + type: 'object', + properties: { + profile: { + type: 'string', + description: + 'The developer name (fullName) of the profile to update (e.g. "Admin", "Standard"). ' + + 'If omitted, the current user\'s profile is updated.', + }, + fields: { + type: 'array', + description: + 'List of field permission entries to apply to the profile.', + items: { + type: 'object', + properties: { + field: { + type: 'string', + description: + 'The fully qualified field API name in the format "ObjectType.FieldName" ' + + '(e.g. "Account.Name", "Contact.Phone").', + }, + access: { + type: 'string', + enum: ['editable', 'readable', 'none'], + description: + '"editable" grants read + write, "readable" grants read-only, "none" removes all access.', + }, + }, + required: ['field', 'access'], + }, + minItems: 1, + }, + }, + required: ['fields'], + }, + }, +]; + +export async function executeProfileTool( + name: string, + args: Record, + localContainer: Container +) { + if (name === 'list_profiles') { + return listProfiles(localContainer); + } + if (name === 'add_fls_to_profile') { + return addFlsToProfile(args, localContainer); + } + throw new Error(`Unknown profile tool: ${name}`); +} + +async function listProfiles(localContainer: Container) { + const profileService = localContainer.get(SalesforceProfileService); + const profiles = await profileService.listProfiles(); + + return { + content: [ + { + type: 'text' as const, + text: + profiles.length > 0 + ? profiles.join('\n') + : 'No profiles found.', + }, + ], + }; +} + +async function addFlsToProfile( + args: Record, + localContainer: Container +) { + const profileName = args['profile'] as string | undefined; + const fields = args['fields'] as Array<{ field: string; access: string }>; + + const profileService = localContainer.get(SalesforceProfileService); + const profile = await profileService.getProfile(profileName); + + for (const { field, access } of fields) { + if (access === 'none') { + profile.removeField(field); + } else { + profile.addField( + field, + access === 'editable' + ? SalesforceFieldPermission.editable + : SalesforceFieldPermission.readable + ); + } + } + + if (!profile.hasChanges) { + return { + content: [ + { + type: 'text' as const, + text: `Profile '${profile.developerName}': no changes needed (permissions already match).`, + }, + ], + }; + } + + const connection = await localContainer + .get(SalesforceConnectionProvider) + .getJsForceConnection(); + await profile.save(connection); + + return { + content: [ + { + type: 'text' as const, + text: [ + `Profile '${profile.developerName}' updated successfully.`, + `Fields updated (${fields.length}):`, + ...fields.map((f) => ` ${f.field} β†’ ${f.access}`), + ].join('\n'), + }, + ], + }; +} diff --git a/packages/mcp/src/tools/schema.ts b/packages/mcp/src/tools/schema.ts new file mode 100644 index 000000000..e45233a22 --- /dev/null +++ b/packages/mcp/src/tools/schema.ts @@ -0,0 +1,198 @@ +import type { Container } from '@vlocode/core'; +import { SalesforceSchemaService } from '@vlocode/salesforce'; +import type { Tool } from '@modelcontextprotocol/sdk/types.js'; + +export const schemaTools: Tool[] = [ + { + name: 'list_sobjects', + description: + 'List all Salesforce objects (SObjects) available in the connected org. ' + + 'Returns the API names and labels for all standard and custom objects.', + inputSchema: { + type: 'object', + properties: { + filter: { + type: 'string', + description: + 'Optional case-insensitive substring filter applied to object API names and labels. ' + + 'For example, "Account" returns objects whose name or label contains "Account".', + }, + }, + }, + }, + { + name: 'describe_sobject', + description: + 'Describe a Salesforce object (SObject) including all its fields, relationships, ' + + 'and metadata. Useful for understanding the structure of a Salesforce record type.', + inputSchema: { + type: 'object', + properties: { + objectType: { + type: 'string', + description: + 'The API name of the Salesforce object to describe (e.g. "Account", "Contact", "vlocity_cmt__OmniScript__c").', + }, + includeFields: { + type: 'boolean', + description: + 'Include field-level details (type, label, required, etc.) in the result. Defaults to true.', + default: true, + }, + }, + required: ['objectType'], + }, + }, + { + name: 'describe_sobject_field', + description: + 'Describe a specific field on a Salesforce object. ' + + 'Returns detailed metadata including type, label, picklist values, and relationship details.', + inputSchema: { + type: 'object', + properties: { + objectType: { + type: 'string', + description: 'The API name of the Salesforce object (e.g. "Account").', + }, + fieldName: { + type: 'string', + description: 'The API name of the field to describe (e.g. "Name", "OwnerId").', + }, + }, + required: ['objectType', 'fieldName'], + }, + }, +]; + +export async function executeSchemaTool( + name: string, + args: Record, + localContainer: Container +) { + if (name === 'list_sobjects') { + return listSObjects(args, localContainer); + } + if (name === 'describe_sobject') { + return describeSObject(args, localContainer); + } + if (name === 'describe_sobject_field') { + return describeSObjectField(args, localContainer); + } + throw new Error(`Unknown schema tool: ${name}`); +} + +async function listSObjects( + args: Record, + localContainer: Container +) { + const filter = (args['filter'] as string | undefined)?.toLowerCase(); + const schemaService = localContainer.get(SalesforceSchemaService); + const sobjects = await schemaService.describeSObjects(); + + const filtered = filter + ? sobjects.filter( + (o) => + o.name.toLowerCase().includes(filter) || + o.label.toLowerCase().includes(filter) + ) + : sobjects; + + const lines = filtered.map((o) => `${o.name} β€” ${o.label}`); + + return { + content: [ + { + type: 'text' as const, + text: + lines.length > 0 + ? lines.join('\n') + : 'No objects found matching the filter.', + }, + ], + }; +} + +async function describeSObject( + args: Record, + localContainer: Container +) { + const objectType = args['objectType'] as string; + const includeFields = (args['includeFields'] as boolean) ?? true; + + const schemaService = localContainer.get(SalesforceSchemaService); + const describe = await schemaService.describeSObject(objectType); + + const lines: string[] = [ + `Object: ${describe.name}`, + `Label: ${describe.label}`, + `Label (plural): ${describe.labelPlural}`, + `Key prefix: ${describe.keyPrefix ?? 'n/a'}`, + `Custom: ${describe.custom}`, + `Queryable: ${describe.queryable}`, + `Createable: ${describe.createable}`, + `Updateable: ${describe.updateable}`, + `Deletable: ${describe.deletable}`, + `Fields: ${describe.fields.length}`, + ]; + + if (includeFields) { + lines.push('', 'Fields:'); + for (const field of describe.fields) { + const attrs: string[] = [field.type]; + if (field.length) attrs.push(`length: ${field.length}`); + if (!field.nillable) attrs.push('required'); + if (field.externalId) attrs.push('externalId'); + if (field.unique) attrs.push('unique'); + lines.push( + ` ${field.name} (${field.label}) [${attrs.join(', ')}]` + ); + } + } + + return { + content: [{ type: 'text' as const, text: lines.join('\n') }], + }; +} + +async function describeSObjectField( + args: Record, + localContainer: Container +) { + const objectType = args['objectType'] as string; + const fieldName = args['fieldName'] as string; + + const schemaService = localContainer.get(SalesforceSchemaService); + const field = await schemaService.describeSObjectField(objectType, fieldName); + + const lines: string[] = [ + `Field: ${field.name}`, + `Label: ${field.label}`, + `Type: ${field.type}`, + `Length: ${field.length ?? 'n/a'}`, + `Required: ${!field.nillable}`, + `Unique: ${field.unique}`, + `External ID: ${field.externalId}`, + `Createable: ${field.createable}`, + `Updateable: ${field.updateable}`, + `Filterable: ${field.filterable}`, + `Sortable: ${field.sortable}`, + `Calculated: ${field.calculated}`, + ]; + + if (field.referenceTo && field.referenceTo.length > 0) { + lines.push(`References: ${field.referenceTo.join(', ')}`); + lines.push(`Relationship name: ${field.relationshipName ?? 'n/a'}`); + } + + if (field.picklistValues && field.picklistValues.length > 0) { + lines.push('', 'Picklist values:'); + for (const pv of field.picklistValues) { + lines.push(` ${pv.value}${pv.label !== pv.value ? ` (${pv.label})` : ''}${pv.defaultValue ? ' [default]' : ''}${!pv.active ? ' [inactive]' : ''}`); + } + } + + return { + content: [{ type: 'text' as const, text: lines.join('\n') }], + }; +} diff --git a/packages/mcp/tsconfig.json b/packages/mcp/tsconfig.json new file mode 100644 index 000000000..b49ae4944 --- /dev/null +++ b/packages/mcp/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { + "module": "es2022", + "target": "es2022", + "moduleResolution": "node", + "outDir": "dist", + "baseUrl": "src", + "declaration": true, + "noEmit": true, + "declarationMap": true, + "allowImportingTsExtensions": true + }, + "exclude": [ + "../../build/**/*.ts" + ], + "include": [ + "src/**/*", + "../../build/**/*.ts", + "tsdown.config.mts" + ] +} diff --git a/packages/mcp/tsdown.config.mts b/packages/mcp/tsdown.config.mts new file mode 100644 index 000000000..2843faee3 --- /dev/null +++ b/packages/mcp/tsdown.config.mts @@ -0,0 +1,46 @@ +import { defineConfig } from 'tsdown'; + +import fileTypesPatch from '../../build/patches/file-types.ts'; +import vlocityPatch from '../../build/patches/vlocity.ts'; +import dtracePatch from '../../build/patches/dtrace.ts'; +import jsdomPatch from '../../build/patches/jsdom.ts'; + +const packageExternals = [ + 'vscode', + 'vscode-languageclient', + 'electron' +]; + +export default defineConfig({ + entry: { + 'mcp': './src/index.ts', + }, + outDir: './dist', + format: 'esm', + fixedExtension: true, + external: [...packageExternals], + sourcemap: false, + shims: true, + minify: false, + treeshake: false, + inlineOnly: false, + env: { + NODE_ENV: 'production', + DEBUG: false + }, + nodeProtocol: true, + tsconfig: './tsconfig.json', + inputOptions: { + preserveEntrySignatures: 'strict', + }, + outputOptions: { + keepNames: true, + strictExecutionOrder: true, + }, + plugins: [ + fileTypesPatch(), + vlocityPatch(), + jsdomPatch(), + dtracePatch() + ] +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 85c218ce9..e92af9c83 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -326,6 +326,31 @@ importers: specifier: ^29.3.4 version: 29.4.6(@babel/core@7.23.6)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.6))(jest-util@29.7.0)(jest@29.7.0(@types/node@25.2.1)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@25.2.1)(typescript@5.9.3)))(typescript@5.9.3) + packages/mcp: + dependencies: + '@modelcontextprotocol/sdk': + specifier: ^1.27.1 + version: 1.27.1(zod@4.3.6) + devDependencies: + '@vlocode/core': + specifier: workspace:* + version: link:../core + '@vlocode/salesforce': + specifier: workspace:* + version: link:../salesforce + '@vlocode/util': + specifier: workspace:* + version: link:../util + '@vlocode/vlocity': + specifier: workspace:* + version: link:../vlocity + '@vlocode/vlocity-deploy': + specifier: workspace:* + version: link:../vlocity-deploy + shx: + specifier: ^0.3.4 + version: 0.3.4 + packages/omniscript: dependencies: '@vlocode/core': @@ -1210,6 +1235,12 @@ packages: resolution: {integrity: sha512-2JYy//YE2YINTe21hpdVMBNc7aYFkgDeY9JUz/BCjFZmYLn0UjGaCc4BpTcMGXNJwuqoUenw2WGOFGHsJqlIDw==} engines: {node: '>=6.0.0'} + '@hono/node-server@1.19.11': + resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanwhocodes/config-array@0.13.0': resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} @@ -1571,6 +1602,16 @@ packages: '@microsoft/applicationinsights-web-snippet@1.0.1': resolution: {integrity: sha512-2IHAOaLauc8qaAitvWS+U931T+ze+7MNWrDHY47IENP5y2UA0vqJDu67kWZDdpCN1fFC77sfgfB+HV7SrKshnQ==} + '@modelcontextprotocol/sdk@1.27.1': + resolution: {integrity: sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -2635,6 +2676,10 @@ packages: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: @@ -2678,6 +2723,14 @@ packages: resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} engines: {node: '>= 14'} + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -2968,6 +3021,10 @@ packages: bluebird@3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -3052,6 +3109,10 @@ packages: '@75lb/nature': optional: true + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -3344,6 +3405,14 @@ packages: constant-case@3.0.4: resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} + content-disposition@1.0.1: + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + continuation-local-storage@3.2.1: resolution: {integrity: sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==} @@ -3382,6 +3451,14 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + core-js-pure@3.26.0: resolution: {integrity: sha512-LiN6fylpVBVwT8twhhluD9TzXmZQQsr2I2eIKtWNbZI1XMfBT7CV18itaN6RA7EtQd/SDdRx/wzvAShX2HvhQA==} @@ -3394,6 +3471,10 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + crc-32@1.2.2: resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} engines: {node: '>=0.8'} @@ -3602,6 +3683,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + detect-indent@7.0.1: resolution: {integrity: sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==} engines: {node: '>=12.20'} @@ -3718,6 +3803,9 @@ packages: resolution: {integrity: sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==} engines: {ecmascript: '>= es5', node: '>=4'} + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + electron-to-chromium@1.5.286: resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} @@ -3744,6 +3832,10 @@ packages: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} engines: {node: '>=14'} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} @@ -3833,6 +3925,9 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -3956,6 +4051,10 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -3967,6 +4066,14 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + execa@0.10.0: resolution: {integrity: sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==} engines: {node: '>=4'} @@ -3998,6 +4105,16 @@ packages: exponential-backoff@3.1.1: resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} + express-rate-limit@8.3.1: + resolution: {integrity: sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -4119,6 +4236,10 @@ packages: resolution: {integrity: sha512-iXfpBqHrr9v/Kv/I25kQ4fhr2qu9Uwedh3BK1K8c7l0YGNc7PCsZcsmM8Og78bYgrJhlPYkiEiBOroxUAf0XgA==} hasBin: true + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + find-up@3.0.0: resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} engines: {node: '>=6'} @@ -4177,6 +4298,14 @@ packages: resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} engines: {node: '>= 6'} + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -4455,6 +4584,10 @@ packages: resolution: {integrity: sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==} hasBin: true + hono@4.12.8: + resolution: {integrity: sha512-VJCEvtrezO1IAR+kqEYnxUOoStaQPGrCmX3j4wDTNOcD1uRPFpGlwQUIW8niPuvHXaTUxeOUl5MMDGrl+tmO9A==} + engines: {node: '>=16.9.0'} + hookable@6.0.1: resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==} @@ -4487,6 +4620,10 @@ packages: http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + http-parser-js@0.5.6: resolution: {integrity: sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==} @@ -4642,10 +4779,18 @@ packages: resolution: {integrity: sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==} engines: {node: '>=4'} + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + ip-address@9.0.5: resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} engines: {node: '>= 12'} + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + is-array-buffer@3.0.4: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} @@ -4788,6 +4933,9 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -5087,6 +5235,9 @@ packages: node-notifier: optional: true + jose@6.2.1: + resolution: {integrity: sha512-jUaKr1yrbfaImV7R2TN/b3IcZzsw38/chqMpo2XJ7i2F8AfM/lA4G1goC3JVEwg0H7UldTmSt3P68nt31W7/mw==} + js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} @@ -5166,6 +5317,9 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -5454,6 +5608,10 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + mem@4.3.0: resolution: {integrity: sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==} engines: {node: '>=6'} @@ -5467,6 +5625,10 @@ packages: resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} engines: {node: '>=18'} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -5490,6 +5652,10 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -5812,9 +5978,6 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - object-inspect@1.13.1: - resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} - object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} @@ -5853,6 +6016,10 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -6044,6 +6211,10 @@ packages: parse5@7.1.2: resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + pascal-case@3.1.2: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} @@ -6092,6 +6263,9 @@ packages: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} + path-to-regexp@8.3.0: + resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -6137,6 +6311,10 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -6240,6 +6418,10 @@ packages: protocols@2.0.2: resolution: {integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==} + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -6268,6 +6450,10 @@ packages: resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} engines: {node: '>=0.6'} + qs@6.15.0: + resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} + engines: {node: '>=0.6'} + qs@6.5.3: resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} engines: {node: '>=0.6'} @@ -6285,6 +6471,14 @@ packages: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + rc-config-loader@4.1.3: resolution: {integrity: sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==} @@ -6481,6 +6675,10 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + rrweb-cssom@0.6.0: resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} @@ -6596,6 +6794,10 @@ packages: engines: {node: '>=10'} hasBin: true + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + sentence-case@3.0.4: resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} @@ -6603,6 +6805,10 @@ packages: resolution: {integrity: sha512-hJWMZRwP75ocoBM+1/YaCsvS0j5MTPeBHJkS2/wruehl9xwtX30HlDF1Gt6UZ8HHHY8SJa2/IL+jo+JJCd59rA==} engines: {node: '>=0.4.0'} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} @@ -6621,6 +6827,9 @@ packages: setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + sha.js@2.4.12: resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} engines: {node: '>= 0.10'} @@ -6670,9 +6879,6 @@ packages: resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} - side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} - side-channel@1.1.0: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} @@ -6797,6 +7003,10 @@ packages: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + stdin-discarder@0.2.2: resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} engines: {node: '>=18'} @@ -7057,6 +7267,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + tough-cookie@4.1.4: resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} engines: {node: '>=6'} @@ -7230,6 +7444,10 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} @@ -7358,6 +7576,10 @@ packages: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + unplugin-unused@0.5.7: resolution: {integrity: sha512-quvqrHs6mPhk1hjbGwMoypXfagveue+/22dtgDrEzc2K9485ZAsnVfq7iYIgv7FwooiRa6+HDaLWgK2IavN+2g==} engines: {node: '>=20.19.0'} @@ -7433,6 +7655,10 @@ packages: resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==} engines: {node: ^20.17.0 || >=22.9.0} + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + verror@1.10.0: resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} engines: {'0': node >=0.6.0} @@ -7769,6 +7995,14 @@ packages: resolution: {integrity: sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==} engines: {node: '>= 10'} + zod-to-json-schema@3.25.1: + resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} + peerDependencies: + zod: ^3.25 || ^4 + + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + snapshots: '@ampproject/remapping@2.2.1': @@ -8289,7 +8523,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.6 + debug: 4.4.3(supports-color@8.1.1) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -8322,10 +8556,14 @@ snapshots: supports-color: 5.5.0 tslib: 1.14.1 + '@hono/node-server@1.19.11(hono@4.12.8)': + dependencies: + hono: 4.12.8 + '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.6 + debug: 4.4.3(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -8932,6 +9170,28 @@ snapshots: '@microsoft/applicationinsights-web-snippet@1.0.1': {} + '@modelcontextprotocol/sdk@1.27.1(zod@4.3.6)': + dependencies: + '@hono/node-server': 1.19.11(hono@4.12.8) + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.3.1(express@5.2.1) + hono: 4.12.8 + jose: 6.2.1 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.3.6 + zod-to-json-schema: 3.25.1(zod@4.3.6) + transitivePeerDependencies: + - supports-color + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.8.1 @@ -10200,6 +10460,11 @@ snapshots: dependencies: event-target-shim: 5.0.1 + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + acorn-import-attributes@1.9.5(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -10236,6 +10501,10 @@ snapshots: agent-base@7.1.3: {} + ajv-formats@3.0.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -10420,7 +10689,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 @@ -10598,6 +10867,20 @@ snapshots: bluebird@3.7.2: {} + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3(supports-color@8.1.1) + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.0 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + boolbase@1.0.0: {} boundary@2.0.0: {} @@ -10682,6 +10965,8 @@ snapshots: byte-size@9.0.1: {} + bytes@3.1.2: {} + cac@6.7.14: {} cacache@20.0.3: @@ -11030,6 +11315,10 @@ snapshots: tslib: 2.8.1 upper-case: 2.0.2 + content-disposition@1.0.1: {} + + content-type@1.0.5: {} + continuation-local-storage@3.2.1: dependencies: async-listener: 0.6.10 @@ -11077,6 +11366,10 @@ snapshots: convert-source-map@2.0.0: {} + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + core-js-pure@3.26.0: {} core-js@3.26.0: {} @@ -11085,6 +11378,11 @@ snapshots: core-util-is@1.0.3: {} + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + crc-32@1.2.2: {} crc32-stream@2.0.0: @@ -11298,6 +11596,8 @@ snapshots: delayed-stream@1.0.0: {} + depd@2.0.0: {} + detect-indent@7.0.1: {} detect-libc@1.0.3: @@ -11407,6 +11707,8 @@ snapshots: dependencies: version-range: 4.15.0 + ee-first@1.1.1: {} + electron-to-chromium@1.5.286: {} emitter-listener@1.1.2: @@ -11425,6 +11727,8 @@ snapshots: empathic@2.0.0: {} + encodeurl@2.0.0: {} + encoding@0.1.13: dependencies: iconv-lite: 0.6.3 @@ -11481,7 +11785,7 @@ snapshots: is-string: 1.0.7 is-typed-array: 1.1.13 is-weakref: 1.0.2 - object-inspect: 1.13.1 + object-inspect: 1.13.4 object-keys: 1.1.1 object.assign: 4.1.5 regexp.prototype.flags: 1.5.2 @@ -11556,7 +11860,7 @@ snapshots: es-define-property@1.0.0: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 es-define-property@1.0.1: {} @@ -11572,7 +11876,7 @@ snapshots: es-set-tostringtag@2.0.3: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 hasown: 2.0.2 @@ -11632,6 +11936,8 @@ snapshots: escalade@3.2.0: {} + escape-html@1.0.3: {} + escape-string-regexp@1.0.5: {} escape-string-regexp@2.0.0: {} @@ -11793,12 +12099,20 @@ snapshots: esutils@2.0.3: {} + etag@1.8.1: {} + event-target-shim@5.0.1: {} eventemitter3@5.0.4: {} events@3.3.0: {} + eventsource-parser@3.0.6: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + execa@0.10.0: dependencies: cross-spawn: 6.0.6 @@ -11861,6 +12175,44 @@ snapshots: exponential-backoff@3.1.1: {} + express-rate-limit@8.3.1(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.1.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.1 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3(supports-color@8.1.1) + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + extend@3.0.2: {} external-editor@3.1.0: @@ -11997,6 +12349,17 @@ snapshots: xmldom: '@xmldom/xmldom@0.9.8' xpath: 0.0.24 + finalhandler@2.1.1: + dependencies: + debug: 4.4.3(supports-color@8.1.1) + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + find-up@3.0.0: dependencies: locate-path: 3.0.0 @@ -12060,6 +12423,10 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 + forwarded@0.2.0: {} + + fresh@2.0.0: {} + fs-constants@1.0.0: {} fs-extra@11.3.3: @@ -12163,7 +12530,7 @@ snapshots: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 get-symbol-description@1.1.0: dependencies: @@ -12285,7 +12652,7 @@ snapshots: gopd@1.0.1: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 gopd@1.2.0: {} @@ -12394,6 +12761,8 @@ snapshots: mkdirp: 0.3.0 nopt: 1.0.10 + hono@4.12.8: {} + hookable@6.0.1: {} hosted-git-info@4.1.0: @@ -12427,6 +12796,14 @@ snapshots: http-cache-semantics@4.1.1: {} + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + http-parser-js@0.5.6: {} http-proxy-agent@7.0.2: @@ -12496,7 +12873,6 @@ snapshots: iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 - optional: true ieee754@1.2.1: {} @@ -12578,7 +12954,7 @@ snapshots: dependencies: es-errors: 1.3.0 hasown: 2.0.2 - side-channel: 1.0.4 + side-channel: 1.1.0 internal-slot@1.1.0: dependencies: @@ -12588,15 +12964,19 @@ snapshots: invert-kv@2.0.0: {} + ip-address@10.1.0: {} + ip-address@9.0.5: dependencies: jsbn: 1.1.0 sprintf-js: 1.1.3 + ipaddr.js@1.9.1: {} + is-array-buffer@3.0.4: dependencies: call-bind: 1.0.7 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 is-array-buffer@3.0.5: dependencies: @@ -12723,6 +13103,8 @@ snapshots: is-potential-custom-element-name@1.0.1: {} + is-promise@4.0.0: {} + is-regex@1.1.4: dependencies: call-bind: 1.0.7 @@ -13312,6 +13694,8 @@ snapshots: - supports-color - ts-node + jose@6.2.1: {} + js-tokens@10.0.0: {} js-tokens@4.0.0: {} @@ -13440,6 +13824,8 @@ snapshots: json-schema-traverse@1.0.0: {} + json-schema-typed@8.0.2: {} + json-schema@0.4.0: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -13758,6 +14144,8 @@ snapshots: mdurl@2.0.0: {} + media-typer@1.1.0: {} + mem@4.3.0: dependencies: map-age-cleaner: 0.1.3 @@ -13783,6 +14171,8 @@ snapshots: meow@13.2.0: {} + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -13800,6 +14190,10 @@ snapshots: dependencies: mime-db: 1.52.0 + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mime@1.6.0: {} mime@2.4.6: {} @@ -14125,8 +14519,6 @@ snapshots: object-assign@4.1.1: {} - object-inspect@1.13.1: {} - object-inspect@1.13.4: {} object-keys@0.4.0: {} @@ -14173,6 +14565,10 @@ snapshots: obug@2.1.1: {} + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -14399,6 +14795,8 @@ snapshots: dependencies: entities: 4.5.0 + parseurl@1.3.3: {} + pascal-case@3.1.2: dependencies: no-case: 3.0.4 @@ -14443,6 +14841,8 @@ snapshots: lru-cache: 11.2.1 minipass: 7.1.3 + path-to-regexp@8.3.0: {} + path-type@4.0.0: {} path-type@6.0.0: {} @@ -14467,6 +14867,8 @@ snapshots: pirates@4.0.6: {} + pkce-challenge@5.0.1: {} + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 @@ -14559,6 +14961,11 @@ snapshots: protocols@2.0.2: {} + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + proxy-from-env@1.1.0: {} psl@1.8.0: {} @@ -14598,6 +15005,10 @@ snapshots: dependencies: side-channel: 1.1.0 + qs@6.15.0: + dependencies: + side-channel: 1.1.0 + qs@6.5.3: {} quansync@1.0.0: {} @@ -14608,6 +15019,15 @@ snapshots: quick-lru@5.1.1: {} + range-parser@1.2.1: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + rc-config-loader@4.1.3: dependencies: debug: 4.4.3(supports-color@8.1.1) @@ -14858,6 +15278,16 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.3 '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.3 + router@2.2.0: + dependencies: + debug: 4.4.3(supports-color@8.1.1) + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.3.0 + transitivePeerDependencies: + - supports-color + rrweb-cssom@0.6.0: {} rrweb-cssom@0.7.1: {} @@ -14875,7 +15305,7 @@ snapshots: safe-array-concat@1.1.2: dependencies: call-bind: 1.0.7 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 has-symbols: 1.0.3 isarray: 2.0.5 @@ -15008,6 +15438,22 @@ snapshots: semver@7.7.4: {} + send@1.2.1: + dependencies: + debug: 4.4.3(supports-color@8.1.1) + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + sentence-case@3.0.4: dependencies: no-case: 3.0.4 @@ -15016,6 +15462,15 @@ snapshots: sequin@0.1.1: {} + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + set-blocking@2.0.0: {} set-function-length@1.2.2: @@ -15023,7 +15478,7 @@ snapshots: define-data-property: 1.1.4 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 gopd: 1.0.1 has-property-descriptors: 1.0.2 @@ -15042,6 +15497,8 @@ snapshots: setimmediate@1.0.5: {} + setprototypeof@1.2.0: {} + sha.js@2.4.12: dependencies: inherits: 2.0.4 @@ -15094,12 +15551,6 @@ snapshots: object-inspect: 1.13.4 side-channel-map: 1.0.1 - side-channel@1.0.4: - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - object-inspect: 1.13.1 - side-channel@1.1.0: dependencies: es-errors: 1.3.0 @@ -15249,6 +15700,8 @@ snapshots: dependencies: escape-string-regexp: 2.0.0 + statuses@2.0.2: {} + stdin-discarder@0.2.2: {} stdout-stderr@0.1.13: @@ -15536,6 +15989,8 @@ snapshots: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + tough-cookie@4.1.4: dependencies: psl: 1.8.0 @@ -15742,6 +16197,12 @@ snapshots: type-fest@4.41.0: {} + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + typed-array-buffer@1.0.2: dependencies: call-bind: 1.0.7 @@ -15899,6 +16360,8 @@ snapshots: universalify@2.0.0: {} + unpipe@1.0.0: {} + unplugin-unused@0.5.7: dependencies: empathic: 2.0.0 @@ -15980,6 +16443,8 @@ snapshots: validate-npm-package-name@7.0.2: {} + vary@1.1.2: {} + verror@1.10.0: dependencies: assert-plus: 1.0.0 @@ -16380,3 +16845,9 @@ snapshots: archiver-utils: 2.1.0 compress-commons: 4.1.1 readable-stream: 3.6.0 + + zod-to-json-schema@3.25.1(zod@4.3.6): + dependencies: + zod: 4.3.6 + + zod@4.3.6: {} diff --git a/tsconfig.json b/tsconfig.json index 4e99f413d..5aa18a0bb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -30,7 +30,8 @@ "@vlocode/salesforce": ["./packages/salesforce/src"], "@vlocode/vlocity": ["./packages/vlocity/src"], "@vlocode/vlocity-deploy": ["./packages/vlocity-deploy/src"], - "@vlocode/omniscript": ["./packages/omniscript/src"] + "@vlocode/omniscript": ["./packages/omniscript/src"], + "@vlocode/mcp": ["./packages/mcp/src"] } } } From a5d4ad15c9ab81c1f9e6d142221f36486553b6d3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Mar 2026 23:40:42 +0000 Subject: [PATCH 4/4] fix: address code review feedback for @vlocode/mcp package Co-authored-by: Codeneos <787686+Codeneos@users.noreply.github.com> --- packages/mcp/src/server.ts | 7 ++++--- packages/mcp/src/tools/schema.ts | 6 +++++- packages/mcp/tsdown.config.mts | 6 +----- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/mcp/src/server.ts b/packages/mcp/src/server.ts index 154239dc1..b14908e93 100644 --- a/packages/mcp/src/server.ts +++ b/packages/mcp/src/server.ts @@ -94,13 +94,14 @@ export async function startMcpServer(options: VlocodeMcpOptions = {}) { LogManager.get(receiver ?? 'vlocode-mcp') ); - // Register the Vlocity namespace service so namespace placeholders are resolved. - // Initialization is deferred to the first tool call so the server starts quickly. - const nsService = localContainer.get(VlocityNamespaceService); + // The Vlocity namespace service resolves namespace placeholders in queries + // and SObject type names. Initialization is deferred to the first tool call + // so the MCP server starts immediately without requiring a Salesforce connection. let nsInitialized = false; async function ensureNamespaceInitialized() { if (!nsInitialized) { + const nsService = new VlocityNamespaceService(); await nsService.initialize(localContainer.get(SalesforceConnectionProvider)); localContainer.add(nsService); nsInitialized = true; diff --git a/packages/mcp/src/tools/schema.ts b/packages/mcp/src/tools/schema.ts index e45233a22..fc556316d 100644 --- a/packages/mcp/src/tools/schema.ts +++ b/packages/mcp/src/tools/schema.ts @@ -188,7 +188,11 @@ async function describeSObjectField( if (field.picklistValues && field.picklistValues.length > 0) { lines.push('', 'Picklist values:'); for (const pv of field.picklistValues) { - lines.push(` ${pv.value}${pv.label !== pv.value ? ` (${pv.label})` : ''}${pv.defaultValue ? ' [default]' : ''}${!pv.active ? ' [inactive]' : ''}`); + const parts = [pv.value]; + if (pv.label !== pv.value) parts.push(`(${pv.label})`); + if (pv.defaultValue) parts.push('[default]'); + if (!pv.active) parts.push('[inactive]'); + lines.push(` ${parts.join(' ')}`); } } diff --git a/packages/mcp/tsdown.config.mts b/packages/mcp/tsdown.config.mts index 2843faee3..7ff4077ca 100644 --- a/packages/mcp/tsdown.config.mts +++ b/packages/mcp/tsdown.config.mts @@ -5,11 +5,7 @@ import vlocityPatch from '../../build/patches/vlocity.ts'; import dtracePatch from '../../build/patches/dtrace.ts'; import jsdomPatch from '../../build/patches/jsdom.ts'; -const packageExternals = [ - 'vscode', - 'vscode-languageclient', - 'electron' -]; +const packageExternals: string[] = []; export default defineConfig({ entry: {