Cursor rule
.cursor/rules/contentstack-core.mdcContentstack core CLI package patterns — plugin aggregation, hooks, and entry point
Cursor rules
Quality
69/100
Scores the file, not the repository.Length
1,336 words
31 headings · 14 code blocksRepository
14
— · pushed 0 days agoLast changed
3 days ago
First indexed 3 days ago.1234567# Contentstack Core Package Standards89## Overview1011The `@contentstack/cli` core package is the entry point for the entire CLI. Unlike plugin packages (auth, config), it:12- **Aggregates all plugins** — declared in `oclif.plugins` array in `package.json`13- **Implements hooks** — `init` and `prerun` hooks in `src/hooks/` for global behaviors14- **Shares interfaces** — Core types used across all plugins in `src/interfaces/`15- **Provides utilities** — Helper classes like `CsdxContext` in `src/utils/`16- **Has no command files** — Commands are provided by plugin packages1718## Architecture1920### Entry Point2122```typescript23// ✅ GOOD - bin/run.js (CommonJS)24// This is the executable entry point referenced in package.json "bin"25// Standard OCLIF entry point pattern26```2728### Package Configuration2930The `oclif` configuration in `package.json`:31```json32{33 "oclif": {34 "bin": "csdx",35 "topicSeparator": ":",36 "helpClass": "./lib/help.js",37 "plugins": [38 "@oclif/plugin-help",39 "@oclif/plugin-not-found",40 "@oclif/plugin-plugins",41 "@contentstack/cli-config",42 "@contentstack/cli-auth"43 // ... more plugins44 ],45 "hooks": {46 "init": [47 "./lib/hooks/init/context-init",48 "./lib/hooks/init/utils-init"49 ],50 "prerun": [51 "./lib/hooks/prerun/init-context-for-command",52 "./lib/hooks/prerun/command-deprecation-check",53 "./lib/hooks/prerun/default-rate-limit-check",54 "./lib/hooks/prerun/latest-version-warning"55 ]56 },57 "topics": {58 "auth": { "description": "Perform authentication-related activities" },59 "config": { "description": "Perform configuration related activities" },60 "cm": { "description": "Perform content management activities" }61 }62 }63}64```6566## Hook Lifecycle6768### OCLIF Hook Execution Order69701. **CLI initialization** → Node process starts712. **`init` hooks** → Set up global context and utilities (executed once)723. **Command detection** → OCLIF matches command name to plugin734. **`prerun` hooks** → Validate state, check auth, prepare for command execution (per command)745. **Command execution** → Plugin command's `run()` method executes7576### Init Hooks7778Init hooks run once during CLI startup. Use them for expensive setup operations.7980```typescript81// ✅ GOOD - src/hooks/init/context-init.ts82// Initialize CLI context that commands depend on83import { CsdxContext } from '../../utils';84import { configHandler } from '@contentstack/cli-utilities';8586export default function (opts): void {87 // Store command ID for session-based log organization88 if (opts.id) {89 configHandler.set('currentCommandId', opts.id);90 }91 // Make context available to all commands via this.config.context92 this.config.context = new CsdxContext(opts, this.config);93}94```9596### Prerun Hooks9798Prerun hooks run before each command. Use them for validation and state checks.99100```typescript101// ✅ GOOD - src/hooks/prerun/auth-guard.ts102// Validate authentication before running protected commands103104import { cliux, isAuthenticated, managementSDKClient } from '@contentstack/cli-utilities';105106export default async function (opts): Promise<void> {107 const { context: { region = null } = {} } = this.config;108109 // Validate region is set (required for all non-region commands)110 if (opts.Command.id !== 'config:set:region') {111 if (!region) {112 cliux.error('No region found, please set a region via config:set:region');113 this.exit();114 return;115 }116 }117118 // Example: Validate auth for protected commands119 if (isProtectedCommand(opts.Command.id)) {120 if (!isAuthenticated()) {121 cliux.error('Please log in to execute this command');122 this.exit();123 }124 }125}126```127128### Hook Patterns129130#### Accessing Configuration131```typescript132// ✅ GOOD - Access global config in hooks133export default function (opts): void {134 const { config } = this; // OCLIF Config object135 const { context, region } = config; // Custom properties set by other hooks136}137```138139#### Async Hooks140```typescript141// ✅ GOOD - Async hooks for operations requiring I/O142export default async function (opts): Promise<void> {143 const client = await managementSDKClient({ host: this.config.region.cma });144 const user = await client.getUser();145 // Hook runs to completion before command starts146}147```148149#### Early Exit150```typescript151// ✅ GOOD - Exit hook execution when validation fails152export default function (opts): void {153 if (!isValid()) {154 cliux.error('Validation failed');155 this.exit(); // Stops command from executing156 return;157 }158}159```160161## Context Object162163The `CsdxContext` class wraps OCLIF config and adds CLI-specific state.164165```typescript166// ✅ GOOD - Accessing context in commands167import { CLIConfig } from '../interfaces';168169export default class MyCommand extends Command {170 async run(): Promise<void> {171 const config: CLIConfig = this.config;172 const { context } = config;173174 // Available context properties:175 // - context.id: unique session identifier176 // - context.user: authenticated user info (authtoken, email)177 // - context.region: current region configuration178 // - context.config: regional configuration179 // - context.plugin: current plugin metadata180 }181}182```183184## Shared Interfaces185186Interfaces in `src/interfaces/index.ts` are exported and consumed by all plugins.187188```typescript189// ✅ GOOD - Define shared types190export interface Context {191 id: string;192 user: {193 authtoken: string;194 email: string;195 };196 region: Region;197 plugin: Plugin;198 config: any;199}200201export interface CLIConfig extends Config {202 context: Context;203}204205export interface Region {206 name: string;207 cma: string; // Content Management API endpoint208 cda: string; // Content Delivery API endpoint209}210```211212## Utilities213214Core utilities in `src/utils/` provide shared functionality.215216```typescript217// ✅ GOOD - src/utils/context-handler.ts218// Wrapper around context initialization and access219export class CsdxContext {220 constructor(opts: any, config: any) {221 this.id = opts.id || generateId();222 this.region = config.region;223 this.user = extractUserFromToken();224 }225}226227// Export utilities for use in hooks and contexts228export { CsdxContext };229```230231## Plugin Registration232233Plugins are registered via `oclif.plugins` in `package.json`. Each plugin package must:2342351. **Provide commands** — via `oclif.commands` in its `package.json`2362. **Be installed** — as a dependency in the core package2373. **Be listed** — in `oclif.plugins` array for auto-discovery238239```json240{241 "dependencies": {242 "@contentstack/cli-config": "~1.20.0-beta.1",243 "@contentstack/cli-auth": "~1.8.0-beta.1"244 },245 "oclif": {246 "plugins": [247 "@contentstack/cli-config",248 "@contentstack/cli-auth"249 ]250 }251}252```253254### Plugin Discovery255256OCLIF automatically discovers commands in:2571. Built-in plugins (`@oclif/plugin-help`, etc.)2582. Core package commands (none in contentstack core)2593. Registered plugins (listed in `oclif.plugins`)260261## Differences from Plugin Packages262263| Aspect | Core Package | Plugin Package |264|--------|--------------|----------------|265| **OCLIF config** | No `commands` field | Has `oclif.commands: "./lib/commands"` |266| **Source structure** | `src/hooks/`, `src/interfaces/`, `src/utils/` | `src/commands/`, `src/services/` |267| **Entry point** | `bin/run.js` | None |268| **Dependencies** | References all plugins | Depends on `@contentstack/cli-command` |269| **Execution role** | Aggregates and initializes | Implements business logic |270271## Build Process272273The core package build includes hook compilation and OCLIF manifest generation.274275```bash276# In package.json scripts277"build": "pnpm compile && oclif manifest && oclif readme"278```279280### Build Steps2812821. **compile** — TypeScript → JavaScript in `lib/`2832. **oclif manifest** — Generate `oclif.manifest.json` for plugin discovery2843. **oclif readme** — Generate README with available commands285286### Build Artifacts287288- `lib/` — Compiled hooks, utilities, interfaces289- `oclif.manifest.json` — Plugin and command registry290- `bin/run.js` — Executable entry point291- `README.md` — Generated command documentation292293## Testing Hooks294295Hooks cannot be tested with standard command testing. Test hook behavior by:2962971. **Unit test hook functions** — Import and invoke directly2982. **Integration test via CLI** — Run commands that trigger hooks2993. **Mock OCLIF config** — Provide mocked `this.config` object300301```typescript302// ✅ GOOD - Test hook function directly303import contextInit from '../src/hooks/init/context-init';304305describe('context-init hook', () => {306 it('should set context on config', () => {307 const mockConfig = { context: null };308 const hookContext = { config: mockConfig };309 const opts = { id: 'test-command' };310311 contextInit.call(hookContext, opts);312313 expect(mockConfig.context).to.exist;314 });315});316```317318## Error Handling in Hooks319320Hooks should fail fast and provide clear error messages to users.321322```typescript323// ✅ GOOD - Clear error messages with user guidance324export default function (opts): void {325 if (!isRegionSet()) {326 cliux.error('No region configured');327 cliux.print('Run: csdx config:set:region --region us', { color: 'blue' });328 this.exit();329 }330}331```332333## Best Practices334335### Hook Organization336- Keep hooks focused on a single concern (validation, initialization, etc.)337- Use descriptive names that indicate when they run (`prerun-`, `init-`)338- Initialize dependencies in `init` hooks, not in `prerun` hooks339340### Performance341- Minimize work in `init` hooks (they run once per CLI session)342- Cache expensive operations in context for reuse343- Avoid repeated API calls across hooks344345### Ordering346- Place hooks that prepare data before hooks that consume it347- Auth validation (`auth-guard`) should run after region validation348- Version warnings can run last (non-critical)349350### Context Usage351- Store computed values in context to avoid recalculation352- Make context available to all commands via `this.config.context`353- Document context properties that plugins should expect354355### Plugin Development356- Ensure plugins depend on `@contentstack/cli-command`, not the core package357- Commands should extend the shared Command base class358- Plugins should not modify or depend on core hooks directly359
Also in contentstack/cli
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| contentstack/cli.cursor/rules/oclif-commands.mdc · 14 | Cursor rules | setupteststylearch | 74/100 | 3 days ago | |
| contentstack/cli.cursor/rules/testing.mdc · 14 | Cursor rules | setupteststylearch+3 | 89/100 | 3 days ago | |
| contentstack/cli.cursor/rules/typescript.mdc · 14 | Cursor rules | stylearchtypessecurity+1 | 70/100 | 3 days ago |
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 45 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 3 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 3 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 45 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 3 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 3 days ago |
