decoupled-cli 2.4.0 → 2.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # Decoupled Drupal CLI (decoupled-cli)
2
2
 
3
- A command-line interface for managing Decoupled Drupal spaces, monitoring usage, and interacting with the Decoupled Drupal API using personal access tokens.
3
+ A command-line interface for managing Decoupled Drupal spaces, monitoring usage, and enabling AI assistants to interact with your platform through the Model Context Protocol (MCP).
4
+
5
+ ## Features
6
+
7
+ - 🔐 **Secure Authentication** - OAuth (Google/GitHub) and Personal Access Tokens
8
+ - 🤖 **AI Integration** - Model Context Protocol support for Claude Code and Cursor
9
+ - 📦 **Space Management** - Create, clone, delete, and monitor Drupal spaces
10
+ - 📊 **Usage Monitoring** - Track storage, bandwidth, and API requests
11
+ - 🚀 **Quick Start** - AI-powered space creation with generated content
12
+ - 📥 **Content Import** - Import content models and data to Drupal
4
13
 
5
14
  ## Installation
6
15
 
@@ -128,6 +137,72 @@ The CLI stores configuration in `~/.decoupled-cli/config.json`:
128
137
 
129
138
  Actual tokens are stored securely using the system keychain (macOS Keychain, Windows Credential Manager, or Linux Secret Service).
130
139
 
140
+ ## AI Integration with MCP
141
+
142
+ The CLI supports the Model Context Protocol (MCP), enabling AI assistants in **Claude Code** and **Cursor** to manage your Drupal spaces using natural language.
143
+
144
+ ### Setup
145
+
146
+ ```bash
147
+ # Log in first (if not already)
148
+ decoupled-cli auth login
149
+
150
+ # Configure MCP for Claude Code
151
+ decoupled-cli mcp configure --ide claude-code
152
+
153
+ # Or configure for Cursor
154
+ decoupled-cli mcp configure --ide cursor
155
+ ```
156
+
157
+ After configuration, restart your IDE and you can interact with your platform naturally:
158
+
159
+ **Example conversations:**
160
+ ```
161
+ You: "Show me all my Drupal spaces"
162
+ AI: Lists all your spaces with status and URLs
163
+
164
+ You: "Create a blog space called Tech News"
165
+ AI: Creates the space and returns the ID and URL
166
+
167
+ You: "What's my current storage usage?"
168
+ AI: Shows organization-wide usage statistics
169
+
170
+ You: "Clone space 5 and name it Staging"
171
+ AI: Clones the space with all content
172
+ ```
173
+
174
+ ### Available MCP Commands
175
+
176
+ ```bash
177
+ # Configure MCP for an IDE
178
+ decoupled-cli mcp configure [--ide <claude-code|cursor>]
179
+
180
+ # Show configuration status
181
+ decoupled-cli mcp status
182
+
183
+ # Remove MCP configuration
184
+ decoupled-cli mcp remove
185
+
186
+ # Show config without writing (for manual setup)
187
+ decoupled-cli mcp configure --show-only
188
+ ```
189
+
190
+ ### What AI Can Do
191
+
192
+ - **Read Operations:**
193
+ - List all spaces with details
194
+ - Get space information
195
+ - View usage statistics
196
+ - Check organization details
197
+
198
+ - **Write Operations:**
199
+ - Create new spaces
200
+ - Clone existing spaces
201
+ - Delete spaces
202
+ - Import content models and data
203
+
204
+ All operations use your existing authentication and permissions.
205
+
131
206
  ## Commands
132
207
 
133
208
  ### Spaces Management
@@ -289,6 +364,58 @@ decoupled-cli spaces retry 123
289
364
  decoupled-cli spaces refresh-usage 123
290
365
  ```
291
366
 
367
+ ### Content Management
368
+
369
+ #### Import Content
370
+ ```bash
371
+ # Import content model and data from JSON file
372
+ decoupled-cli content import --file content-import.json
373
+
374
+ # Preview import without applying changes
375
+ decoupled-cli content import --file content-import.json --preview
376
+
377
+ # Show example import JSON structure
378
+ decoupled-cli content import --example
379
+ ```
380
+
381
+ **Import JSON Format:**
382
+ ```json
383
+ {
384
+ "model": [
385
+ {
386
+ "bundle": "blog_post",
387
+ "label": "Blog Post",
388
+ "description": "Blog article content type",
389
+ "body": true,
390
+ "fields": [
391
+ {
392
+ "id": "subtitle",
393
+ "label": "Subtitle",
394
+ "type": "string"
395
+ },
396
+ {
397
+ "id": "featured_image",
398
+ "label": "Featured Image",
399
+ "type": "image"
400
+ }
401
+ ]
402
+ }
403
+ ],
404
+ "content": [
405
+ {
406
+ "id": "post1",
407
+ "type": "node.blog_post",
408
+ "path": "/blog/my-first-post",
409
+ "values": {
410
+ "title": "My First Post",
411
+ "body": "<p>Post content here</p>",
412
+ "subtitle": "An introduction"
413
+ }
414
+ }
415
+ ]
416
+ }
417
+ ```
418
+
292
419
  ### Usage Monitoring
293
420
 
294
421
  #### Organization Usage
@@ -506,6 +633,7 @@ decoupled-cli auth test --permissions
506
633
 
507
634
  The CLI directly uses the Decoupled Drupal API with these endpoints:
508
635
 
636
+ **Space Management:**
509
637
  - `GET /api/spaces` - List spaces
510
638
  - `POST /api/spaces` - Create space
511
639
  - `GET /api/spaces/{id}` - Get space details
@@ -514,17 +642,121 @@ The CLI directly uses the Decoupled Drupal API with these endpoints:
514
642
  - `POST /api/spaces/{id}/clone` - Clone space
515
643
  - `POST /api/spaces/{id}/archive` - Archive space
516
644
  - `POST /api/spaces/{id}/unarchive` - Unarchive space
645
+
646
+ **Content Operations:**
647
+ - `POST /api/spaces/{id}/content-import` - Import content model and data
648
+
649
+ **Usage & Monitoring:**
517
650
  - `GET /api/usage` - Get usage data
518
- - Token management endpoints (web interface only)
651
+ - `GET /api/organization` - Get organization details
652
+
653
+ **MCP (Model Context Protocol):**
654
+ - `GET /api/mcp/sse` - SSE connection for MCP clients
655
+ - `POST /api/mcp/messages` - JSON-RPC 2.0 message handler
656
+
657
+ **Authentication:**
658
+ - Token management endpoints (web interface only at `/organization/tokens`)
519
659
 
520
660
  ## Contributing
521
661
 
522
662
  The CLI is built with:
523
- - Node.js/TypeScript
524
- - Commander.js for CLI framework
525
- - Axios for HTTP requests
526
- - Keytar for secure credential storage
527
- - Chalk for colored output
528
- - CLI-table3 for formatted tables
529
-
530
- For development and contribution guidelines, see the CLI repository.
663
+ - **Node.js/TypeScript** - Core runtime and type safety
664
+ - **Commander.js** - CLI framework and command parsing
665
+ - **Inquirer** - Interactive prompts
666
+ - **Axios** - HTTP requests for API calls
667
+ - **Keytar** - Secure credential storage (system keychain)
668
+ - **Chalk** - Colored terminal output
669
+ - **CLI-table3** - Formatted table output
670
+ - **Open** - Cross-platform browser opening
671
+
672
+ ### Development
673
+
674
+ ```bash
675
+ # Clone repository
676
+ git clone https://github.com/nextagencyio/decoupled-dashboard.git
677
+ cd decoupled-dashboard/cli
678
+
679
+ # Install dependencies
680
+ npm install
681
+
682
+ # Build TypeScript
683
+ npm run build
684
+
685
+ # Run locally
686
+ npm start -- [command]
687
+
688
+ # Watch mode for development
689
+ npm run dev
690
+ ```
691
+
692
+ ### Project Structure
693
+
694
+ ```
695
+ cli/
696
+ ├── src/
697
+ │ ├── commands/ # CLI command implementations
698
+ │ │ ├── auth.ts # Authentication commands
699
+ │ │ ├── auth-interactive.ts # OAuth flow
700
+ │ │ ├── spaces.ts # Space management
701
+ │ │ ├── content.ts # Content import
702
+ │ │ ├── mcp.ts # MCP configuration
703
+ │ │ ├── usage.ts # Usage statistics
704
+ │ │ ├── org.ts # Organization management
705
+ │ │ ├── health.ts # Health checks
706
+ │ │ └── config.ts # CLI configuration
707
+ │ ├── lib/ # Shared utilities
708
+ │ │ ├── api.ts # API client
709
+ │ │ └── config.ts # Config management
710
+ │ └── index.ts # CLI entry point
711
+ ├── examples/ # Example files
712
+ │ └── content-import-sample.json
713
+ └── package.json
714
+ ```
715
+
716
+ ## Version & Updates
717
+
718
+ ```bash
719
+ # Check current version
720
+ decoupled-cli --version
721
+
722
+ # Update to latest
723
+ npm install -g decoupled-cli@latest
724
+
725
+ # View changelog
726
+ npm view decoupled-cli versions
727
+ ```
728
+
729
+ **Current Version:** 2.4.1
730
+
731
+ **Recent Changes:**
732
+ - Added Model Context Protocol (MCP) support
733
+ - Implemented OAuth authentication flow
734
+ - Added content import functionality
735
+ - Removed legacy AI configuration files
736
+
737
+ ## Getting Help
738
+
739
+ ```bash
740
+ # General help
741
+ decoupled-cli --help
742
+
743
+ # Command-specific help
744
+ decoupled-cli [command] --help
745
+
746
+ # Examples
747
+ decoupled-cli spaces --help
748
+ decoupled-cli mcp configure --help
749
+ ```
750
+
751
+ **Additional Resources:**
752
+ - Documentation: Check the main repository docs
753
+ - Issues: Report bugs on GitHub
754
+ - Support: Contact through the dashboard
755
+
756
+ ## License
757
+
758
+ MIT
759
+
760
+ ---
761
+
762
+ Made with ❤️ by the Decoupled.io team
package/dist/index.js CHANGED
@@ -14,7 +14,6 @@ const usage_1 = require("./commands/usage");
14
14
  const org_1 = require("./commands/org");
15
15
  const health_1 = require("./commands/health");
16
16
  const config_1 = require("./commands/config");
17
- const download_1 = require("./commands/download");
18
17
  const content_1 = require("./commands/content");
19
18
  const mcp_1 = require("./commands/mcp");
20
19
  // Read version from package.json
@@ -37,7 +36,6 @@ program.addCommand(usage_1.usageCommand);
37
36
  program.addCommand(org_1.orgCommand);
38
37
  program.addCommand(health_1.healthCommand);
39
38
  program.addCommand(config_1.configCommand);
40
- program.addCommand(download_1.downloadCommand);
41
39
  program.addCommand(content_1.contentCommand);
42
40
  program.addCommand(mcp_1.mcpCommand);
43
41
  // Handle unknown commands
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAEA,yCAAoC;AACpC,kDAA0B;AAC1B,2BAAkC;AAClC,+BAA4B;AAC5B,0CAA8C;AAC9C,8CAAkD;AAClD,4CAAgD;AAChD,wCAA4C;AAC5C,8CAAkD;AAClD,8CAAkD;AAClD,kDAAsD;AACtD,gDAAoD;AACpD,wCAA4C;AAE5C,iCAAiC;AACjC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAC1D,CAAC;AAEF,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,eAAe,CAAC;KACrB,WAAW,CAAC,yCAAyC,CAAC;KACtD,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;KAC5B,MAAM,CAAC,kBAAkB,EAAE,sBAAsB,CAAC;KAClD,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KAClC,MAAM,CAAC,SAAS,EAAE,+BAA+B,CAAC;KAClD,MAAM,CAAC,WAAW,EAAE,sBAAsB,CAAC;KAC3C,MAAM,CAAC,YAAY,EAAE,wBAAwB,CAAC;KAC9C,MAAM,CAAC,qBAAqB,EAAE,iBAAiB,EAAE,IAAI,CAAC,CAAC;AAE1D,eAAe;AACf,OAAO,CAAC,UAAU,CAAC,kBAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,sBAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,oBAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,gBAAU,CAAC,CAAC;AAC/B,OAAO,CAAC,UAAU,CAAC,sBAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,sBAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,0BAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,wBAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,gBAAU,CAAC,CAAC;AAE/B,0BAA0B;AAC1B,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;IAC3B,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,oBAAoB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACvE,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;IAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,+BAA+B;AAC/B,OAAO,CAAC,KAAK,EAAE,CAAC;AAEhB,oCAAoC;AACpC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAClC,OAAO,CAAC,UAAU,EAAE,CAAC;AACvB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAEA,yCAAoC;AACpC,kDAA0B;AAC1B,2BAAkC;AAClC,+BAA4B;AAC5B,0CAA8C;AAC9C,8CAAkD;AAClD,4CAAgD;AAChD,wCAA4C;AAC5C,8CAAkD;AAClD,8CAAkD;AAClD,gDAAoD;AACpD,wCAA4C;AAE5C,iCAAiC;AACjC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAC1D,CAAC;AAEF,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,eAAe,CAAC;KACrB,WAAW,CAAC,yCAAyC,CAAC;KACtD,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;KAC5B,MAAM,CAAC,kBAAkB,EAAE,sBAAsB,CAAC;KAClD,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KAClC,MAAM,CAAC,SAAS,EAAE,+BAA+B,CAAC;KAClD,MAAM,CAAC,WAAW,EAAE,sBAAsB,CAAC;KAC3C,MAAM,CAAC,YAAY,EAAE,wBAAwB,CAAC;KAC9C,MAAM,CAAC,qBAAqB,EAAE,iBAAiB,EAAE,IAAI,CAAC,CAAC;AAE1D,eAAe;AACf,OAAO,CAAC,UAAU,CAAC,kBAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,sBAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,oBAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,gBAAU,CAAC,CAAC;AAC/B,OAAO,CAAC,UAAU,CAAC,sBAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,sBAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,wBAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,gBAAU,CAAC,CAAC;AAE/B,0BAA0B;AAC1B,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;IAC3B,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,oBAAoB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACvE,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;IAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,+BAA+B;AAC/B,OAAO,CAAC,KAAK,EAAE,CAAC;AAEhB,oCAAoC;AACpC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAClC,OAAO,CAAC,UAAU,EAAE,CAAC;AACvB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "decoupled-cli",
3
- "version": "2.4.0",
3
+ "version": "2.4.2",
4
4
  "description": "Command-line interface for managing Decoupled Drupal spaces, deploying content, and automating workflows. Features AI-powered quick-start, content import, and CI/CD integration.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -1,4 +0,0 @@
1
- import { Command } from 'commander';
2
- declare const downloadCommand: Command;
3
- export { downloadCommand };
4
- //# sourceMappingURL=download.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/commands/download.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,QAAA,MAAM,eAAe,SAA0B,CAAC;AAiGhD,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -1,127 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.downloadCommand = void 0;
40
- const commander_1 = require("commander");
41
- const chalk_1 = __importDefault(require("chalk"));
42
- const fs = __importStar(require("fs"));
43
- const path = __importStar(require("path"));
44
- const downloadCommand = new commander_1.Command('download');
45
- exports.downloadCommand = downloadCommand;
46
- downloadCommand
47
- .description('Download AI configuration files')
48
- .argument('<file>', 'AI config file to download (cursorrules, claude, gemini)')
49
- .action(async (file) => {
50
- try {
51
- // Normalize the file argument
52
- const availableFiles = {
53
- 'cursorrules': { filename: '.cursorrules', displayName: 'Cursor Rules' },
54
- 'cursor': { filename: '.cursorrules', displayName: 'Cursor Rules' },
55
- 'claude': { filename: 'CLAUDE.md', displayName: 'Claude Code Configuration' },
56
- 'gemini': { filename: 'GEMINI.md', displayName: 'Google Gemini Configuration' }
57
- };
58
- const normalizedFile = file.toLowerCase();
59
- if (!availableFiles[normalizedFile]) {
60
- console.error(chalk_1.default.red(`❌ Unknown file: ${file}`));
61
- console.log(chalk_1.default.gray('\nAvailable files:'));
62
- Object.entries(availableFiles).forEach(([key, config]) => {
63
- console.log(chalk_1.default.gray(` • ${key} → ${config.filename} (${config.displayName})`));
64
- });
65
- process.exit(1);
66
- }
67
- const fileConfig = availableFiles[normalizedFile];
68
- const sourceFileName = fileConfig.filename;
69
- const displayName = fileConfig.displayName;
70
- // Get the directory where the CLI is installed
71
- const cliDir = path.resolve(__dirname, '../..');
72
- const examplesDir = path.join(cliDir, 'examples');
73
- const sourcePath = path.join(examplesDir, sourceFileName);
74
- // Check if source file exists
75
- if (!fs.existsSync(sourcePath)) {
76
- console.error(chalk_1.default.red(`❌ Source file not found: ${sourcePath}`));
77
- process.exit(1);
78
- }
79
- // Destination path (current working directory)
80
- const destPath = path.join(process.cwd(), sourceFileName);
81
- // Check if destination file already exists
82
- if (fs.existsSync(destPath)) {
83
- const { default: inquirer } = await Promise.resolve().then(() => __importStar(require('inquirer')));
84
- const answers = await inquirer.prompt([
85
- {
86
- type: 'confirm',
87
- name: 'overwrite',
88
- message: `File ${sourceFileName} already exists. Overwrite?`,
89
- default: false
90
- }
91
- ]);
92
- if (!answers.overwrite) {
93
- console.log(chalk_1.default.yellow('Operation cancelled.'));
94
- return;
95
- }
96
- }
97
- // Read and write the file
98
- const content = fs.readFileSync(sourcePath, 'utf8');
99
- fs.writeFileSync(destPath, content, 'utf8');
100
- console.log(chalk_1.default.green(`✅ Downloaded ${displayName}`));
101
- console.log(chalk_1.default.gray(`📁 Saved to: ${destPath}`));
102
- // Show file size and first few lines as preview
103
- const stats = fs.statSync(destPath);
104
- const lines = content.split('\n');
105
- const previewLines = lines.slice(0, 3).join('\n');
106
- console.log(chalk_1.default.gray(`📊 Size: ${stats.size} bytes`));
107
- console.log(chalk_1.default.gray('📄 Preview:'));
108
- console.log(chalk_1.default.dim(previewLines + (lines.length > 3 ? '\n...' : '')));
109
- }
110
- catch (error) {
111
- console.error(chalk_1.default.red('❌ Failed to download file:'), error instanceof Error ? error.message : String(error));
112
- process.exit(1);
113
- }
114
- });
115
- // Add help examples
116
- downloadCommand.addHelpText('after', `
117
- Examples:
118
- decoupled-cli download cursorrules Download .cursorrules file for Cursor AI
119
- decoupled-cli download claude Download CLAUDE.md configuration
120
- decoupled-cli download gemini Download GEMINI.md configuration
121
-
122
- Available Files:
123
- • cursorrules/.cursor → .cursorrules (Cursor AI configuration)
124
- • claude → CLAUDE.md (Claude Code configuration)
125
- • gemini → GEMINI.md (Google Gemini configuration)
126
- `);
127
- //# sourceMappingURL=download.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"download.js","sourceRoot":"","sources":["../../src/commands/download.ts"],"names":[],"mappings":"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"}
@@ -1,189 +0,0 @@
1
- You are the Cursor AI working in a Next.js + Drupal monorepo. Follow these rules to deliver complete, working features end-to-end.
2
-
3
- # Project Overview
4
- - Architecture: Headless Drupal backend with Next.js frontend
5
- - Backend: Drupal 11 with GraphQL Compose and DC Import API
6
- - Frontend: Next.js 15 with TypeScript, Tailwind CSS, Apollo GraphQL
7
- - Environment: DDEV local development
8
-
9
- # Environment Configuration
10
- - Environment variables in `.env.local`:
11
- - `NEXT_PUBLIC_DRUPAL_BASE_URL` – Drupal base URL
12
- - `DRUPAL_CLIENT_ID` / `DRUPAL_CLIENT_SECRET` – OAuth credentials
13
- - `DRUPAL_REVALIDATE_SECRET` – On-demand revalidation secret
14
- - `NODE_TLS_REJECT_UNAUTHORIZED=0` – Allow self-signed certs (dev)
15
-
16
- # DC CLI Usage
17
- **CRITICAL**: Use DC CLI instead of direct API calls.
18
-
19
- First-time setup:
20
- ```bash
21
- decoupled-cli auth login # Authenticate with platform
22
- decoupled-cli spaces use <id> # Set default space (optional)
23
- decoupled-cli spaces current # Verify setup
24
- ```
25
-
26
- # End-to-End Workflow
27
- When asked to implement a new content type (e.g., “create a product page”), complete all steps:
28
-
29
- 1) Verify CLI authentication
30
- ```bash
31
- decoupled-cli auth status # Check if authenticated
32
- decoupled-cli spaces list # List available spaces
33
- decoupled-cli spaces use <id> # Set default space if needed
34
- ```
35
-
36
- 2) Plan content type
37
- - Define name + machine name
38
- - List fields and types
39
- - Determine components, routes, display needs
40
-
41
- 3) Create DC Import JSON
42
- - Get example format: `decoupled-cli spaces content-import --example`
43
- - Include model definition and sample content
44
- - Important: In `values`, use field ID directly, never with `field_` prefix
45
- - For image fields: Use full URLs with Drupal domain from `.env.local`, not relative paths
46
-
47
- Template:
48
- ```json
49
- {
50
- "model": [
51
- {
52
- "bundle": "content_type_name",
53
- "description": "Description",
54
- "label": "Content Type Label",
55
- "body": true,
56
- "fields": [
57
- { "id": "field_name", "label": "Field Label", "type": "text|string|image|datetime|bool|text[]" }
58
- ]
59
- }
60
- ],
61
- "content": [
62
- {
63
- "id": "item1",
64
- "type": "node.content_type_name",
65
- "path": "/content-type/item-slug",
66
- "values": {
67
- "title": "Item Title",
68
- "body": "<p>Body content</p>",
69
- "field_name": "field_value",
70
- "image_field": {
71
- "uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
72
- "alt": "Image description",
73
- "title": "Image title"
74
- }
75
- }
76
- }
77
- ]
78
- }
79
- ```
80
-
81
- 4) Import via DC CLI
82
- ```bash
83
- # Import content type and sample content
84
- decoupled-cli spaces content-import --file content-type-import.json --preview # Preview first
85
- decoupled-cli spaces content-import --file content-type-import.json # Apply changes
86
-
87
- # Generate example if needed
88
- decoupled-cli spaces content-import --example > content-type-import.json
89
- ```
90
- - **CRITICAL**: Immediately run schema generation:
91
- ```bash
92
- npm run generate-schema
93
- ```
94
- - Verify: machine names, created nodes, and GraphQL schema updates
95
-
96
- 4) Implement frontend
97
- - Files:
98
- ```
99
- app/
100
- components/
101
- [ContentType]Card.tsx
102
- [ContentType]Renderer.tsx
103
- DynamicIcon.tsx (optional)
104
- [content-type]/page.tsx
105
- [...slug]/page.tsx (update)
106
- lib/
107
- queries.ts (update)
108
- types.ts (update)
109
- ```
110
- - GraphQL: add list query and update `GET_NODE_BY_PATH` cases
111
- - Types: add `Drupal[ContentType]` and `[...]Data` interfaces
112
- - Components: card + renderer; use `dangerouslySetInnerHTML` for processed HTML
113
- - Routing: handle in dynamic route switch by `__typename`
114
- - Navigation: add link in `app/components/Header.tsx`; update `navigationItems` and active detection with `pathname.startsWith('/route/')`
115
- - DC GraphQL fields return simple types (`string`, `string[]`, `bool`, etc.), not `{ processed }` objects — probe schema with a quick query before typing components
116
-
117
- 5) Build and test
118
- - `npm run build` → fix TypeScript/build errors
119
- - `npm run dev` → verify listing and detail views
120
- - Check URLs: `/[content-type]`, `/[content-type]/[slug]`
121
-
122
- Checklist:
123
- - [ ] DC import succeeds
124
- - [ ] **Schema generation runs (`npm run generate-schema`)**
125
- - [ ] GraphQL schema exposes fields
126
- - [ ] Types compile
127
- - [ ] Build passes
128
- - [ ] Listing and detail pages render
129
- - [ ] Navigation works, responsive design verified
130
-
131
- # Component Architecture
132
- - Per type, create `[ContentType]Card.tsx` (listing) and `[ContentType]Renderer.tsx` (detail)
133
- - Cards: preview data + CTA; Renderers: full display, responsive layout
134
- - Place components in `app/components/`; listing in `app/[content-type]/page.tsx`; update `app/[...slug]/page.tsx` to route by `__typename`
135
-
136
- # Field Types Reference
137
- - `text` – Rich HTML field
138
- - `string` – Short text (≤255 chars)
139
- - `image` – Single image upload
140
- - `image[]` – Multiple image uploads
141
- - `datetime` – Date/time
142
- - `bool` – Boolean
143
- - `text[]` – Rich HTML list
144
- - `string[]` – Plain text list (recommended for features/specs)
145
-
146
- # Common Patterns
147
- - Product: `price (string)`, `product_images (image[])`, `in_stock (bool)`, `features (string[])`
148
- - Image URI: `{"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png", "alt": "Product image", "title": "Product"}`
149
- - Event: `event_date (datetime)`, `location (string)`, `speakers (string[])`
150
- - Team: `position (string)`, `profile_image (image)`, `bio (text)`
151
- - Image URI: `{"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png", "alt": "Team member photo", "title": "Profile"}`
152
- - Case Study: `project_url (string)`, `technologies (string[])`, `project_images (image[])`
153
- - Image URI: `{"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png", "alt": "Project screenshot", "title": "Interface"}`
154
-
155
- # Troubleshooting
156
- - DC import fails: check OAuth, JSON structure, no `field_` in values
157
- - **Schema not updated**: ALWAYS run `npm run generate-schema` after DC imports
158
- - GraphQL errors: confirm content type exists, clear GraphQL cache, regenerate schema
159
- - Build errors: verify types, imports, query syntax
160
- - Content not showing: confirm field names match GraphQL schema; for HTML use `dangerouslySetInnerHTML={{ __html: field.processed }}`
161
- - **Field name mismatches**: DC field IDs may transform (e.g., `in_stock` → `inStock` in GraphQL)
162
-
163
- Debug commands:
164
- ```bash
165
- decoupled-cli auth status # Check authentication
166
- decoupled-cli spaces list # List available spaces
167
- decoupled-cli spaces current # Show default space
168
- decoupled-cli health check # Platform status
169
- decoupled-cli spaces content-import --file test.json --preview # Preview import
170
- # MOST IMPORTANT: Generate fresh schema after any import
171
- npm run generate-schema
172
- # Check schema includes your content type
173
- grep -i [content_type] schema/schema.graphql
174
- ```
175
- ```
176
-
177
- # Best Practices
178
- 1. **ALWAYS run `npm run generate-schema` immediately after DC imports**
179
- 2. Create sample content for immediate testing
180
- 3. Prefer `string[]` for simple lists; use `text[]` only when necessary
181
- 4. Verify GraphQL field names against the actual schema (may differ from DC field IDs)
182
- 5. Handle empty/missing data gracefully
183
- 6. Keep TypeScript types accurate and complete
184
- 7. Use semantic HTML and ensure responsive design
185
- 8. **Navigation integration**: Update `navigationItems` array and use `.startsWith()` for active detection
186
- 9. **Component architecture**: Create Card + Renderer components per content type
187
-
188
- # Success Criteria
189
- - Builds without errors; routes render correctly; navigation works; responsive; proper fallbacks; follows design patterns; integrates with existing auth and routing.