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 +242 -10
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/commands/download.d.ts +0 -4
- package/dist/commands/download.d.ts.map +0 -1
- package/dist/commands/download.js +0 -127
- package/dist/commands/download.js.map +0 -1
- package/examples/.cursorrules +0 -189
- package/examples/CLAUDE.md +0 -1184
- package/examples/GEMINI.md +0 -1160
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
|
|
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
|
-
-
|
|
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
|
|
525
|
-
-
|
|
526
|
-
-
|
|
527
|
-
-
|
|
528
|
-
-
|
|
529
|
-
|
|
530
|
-
|
|
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,
|
|
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.
|
|
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 +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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"}
|
package/examples/.cursorrules
DELETED
|
@@ -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.
|