@boltic/cli 1.0.6-beta.1 → 1.0.6-beta.12

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.
@@ -1,6 +1,21 @@
1
1
  import fs from "fs";
2
2
  import isEmpty from "lodash.isempty";
3
3
  import path from "path";
4
+ import * as componentSchemas from "../templates/component-schemas.js";
5
+
6
+ const validateOptionObject = (options, fieldName, fileLabel, errors) => {
7
+ options.forEach((opt, index) => {
8
+ const missingKeys = ["label", "value", "description"].filter(
9
+ (key) => !(key in opt)
10
+ );
11
+
12
+ if (missingKeys.length > 0) {
13
+ errors.add(
14
+ `"${fieldName}" field in "${fileLabel}" has an option at index ${index} missing keys: ${missingKeys.join(", ")}.`
15
+ );
16
+ }
17
+ });
18
+ };
4
19
 
5
20
  const readAndParseJson = (filePath, fileLabel, errors) => {
6
21
  try {
@@ -15,8 +30,7 @@ const readAndParseJson = (filePath, fileLabel, errors) => {
15
30
  return null;
16
31
  }
17
32
  };
18
-
19
- const findResourceFieldsWithOptions = (schema) => {
33
+ const findResourceFieldsWithOptions = (schema, fileLabel, errors) => {
20
34
  const resourceFields = [];
21
35
  if (Array.isArray(schema?.parameters)) {
22
36
  schema.parameters.forEach((param) => {
@@ -24,6 +38,12 @@ const findResourceFieldsWithOptions = (schema) => {
24
38
  param.name === "resource" &&
25
39
  Array.isArray(param.meta?.options)
26
40
  ) {
41
+ validateOptionObject(
42
+ param.meta.options,
43
+ "resource",
44
+ fileLabel,
45
+ errors
46
+ );
27
47
  resourceFields.push(
28
48
  ...param.meta.options.map((opt) => opt.value)
29
49
  );
@@ -32,8 +52,7 @@ const findResourceFieldsWithOptions = (schema) => {
32
52
  }
33
53
  return resourceFields;
34
54
  };
35
-
36
- const findOperationFieldsWithOptions = (schema) => {
55
+ const findOperationFieldsWithOptions = (schema, fileLabel, errors) => {
37
56
  const operationFields = [];
38
57
  if (Array.isArray(schema?.parameters)) {
39
58
  schema.parameters.forEach((param) => {
@@ -41,6 +60,12 @@ const findOperationFieldsWithOptions = (schema) => {
41
60
  param.name === "operation" &&
42
61
  Array.isArray(param.meta?.options)
43
62
  ) {
63
+ validateOptionObject(
64
+ param.meta.options,
65
+ "operation",
66
+ fileLabel,
67
+ errors
68
+ );
44
69
  operationFields.push(
45
70
  ...param.meta.options.map((opt) => opt.value)
46
71
  );
@@ -50,6 +75,164 @@ const findOperationFieldsWithOptions = (schema) => {
50
75
  return operationFields;
51
76
  };
52
77
 
78
+ // ─────────────────────────────────────────────────────────────────────────────
79
+ // VALIDATE COMPONENT SCHEMAS
80
+ // ─────────────────────────────────────────────────────────────────────────────
81
+
82
+ /**
83
+ * Extract all possible keys from a component schema structure recursively
84
+ * @param {Object} obj - The object to extract keys from
85
+ * @param {string} prefix - Current key prefix for nested objects
86
+ * @returns {Set<string>} Set of all allowed keys with dot notation for nested paths
87
+ */
88
+ const extractAllowedKeys = (obj, prefix = "") => {
89
+ const allowedKeys = new Set();
90
+
91
+ Object.keys(obj).forEach((key) => {
92
+ const fullKey = prefix ? `${prefix}.${key}` : key;
93
+ allowedKeys.add(fullKey);
94
+
95
+ if (
96
+ typeof obj[key] === "object" &&
97
+ obj[key] !== null &&
98
+ !Array.isArray(obj[key])
99
+ ) {
100
+ const nestedKeys = extractAllowedKeys(obj[key], fullKey);
101
+ nestedKeys.forEach((nestedKey) => allowedKeys.add(nestedKey));
102
+ }
103
+ });
104
+
105
+ return allowedKeys;
106
+ };
107
+
108
+ /**
109
+ * Validate that a schema object doesn't contain any extra keys
110
+ * @param {Object} schemaObj - The schema object to validate
111
+ * @param {Set<string>} allowedKeys - Set of allowed keys
112
+ * @param {string} schemaName - Name of the schema for error messages
113
+ * @param {string} displayType - The display type for error messages
114
+ * @param {Set} errors - Error collection
115
+ * @param {string} prefix - Current key prefix for nested objects
116
+ */
117
+ const validateSchemaKeys = (
118
+ schemaObj,
119
+ allowedKeys,
120
+ schemaName,
121
+ displayType,
122
+ errors,
123
+ prefix = ""
124
+ ) => {
125
+ Object.keys(schemaObj).forEach((key) => {
126
+ const fullKey = prefix ? `${prefix}.${key}` : key;
127
+
128
+ if (!allowedKeys.has(fullKey)) {
129
+ errors.add(
130
+ `"${schemaName}" has an invalid key "${fullKey}" for displayType "${displayType}".`
131
+ );
132
+ }
133
+
134
+ if (
135
+ typeof schemaObj[key] === "object" &&
136
+ schemaObj[key] !== null &&
137
+ !Array.isArray(schemaObj[key])
138
+ ) {
139
+ validateSchemaKeys(
140
+ schemaObj[key],
141
+ allowedKeys,
142
+ schemaName,
143
+ displayType,
144
+ errors,
145
+ fullKey
146
+ );
147
+ }
148
+ });
149
+ };
150
+
151
+ /**
152
+ * Validate a single component schema against its component type definition
153
+ * @param {Object} schema - The schema to validate
154
+ * @param {string} displayType - The display type to validate against
155
+ * @param {Set} errors - Error collection
156
+ */
157
+ const validateComponentByType = (schema, displayType, errors) => {
158
+ // Get the component schema definition for this display type
159
+ const componentSchema = componentSchemas[displayType];
160
+
161
+ if (!componentSchema) {
162
+ errors.add(
163
+ `"${schema.name}" has an unsupported displayType "${displayType}".`
164
+ );
165
+ return;
166
+ }
167
+
168
+ if (!componentSchema.meta) {
169
+ errors.add(
170
+ `Component schema for "${displayType}" is missing meta definition.`
171
+ );
172
+ return;
173
+ }
174
+
175
+ // Extract allowed keys from the component schema
176
+ const allowedKeys = extractAllowedKeys(componentSchema.meta);
177
+
178
+ // Validate the schema meta object (excluding displayType which we already handled)
179
+ const { displayType: currentDisplayType, ...restMeta } = schema.meta;
180
+ validateSchemaKeys(
181
+ restMeta,
182
+ allowedKeys,
183
+ schema.name,
184
+ currentDisplayType,
185
+ errors
186
+ );
187
+ };
188
+
189
+ const validateComponentSchemas = (schemas, errors) => {
190
+ schemas.forEach((schema) => {
191
+ // Basic required field validation
192
+ if (!schema.name) {
193
+ errors.add(`Schema is missing a name.`);
194
+ return; // Can't continue without a name
195
+ }
196
+ if (!schema.meta) {
197
+ errors.add(`"${schema.name}" is missing a meta object.`);
198
+ return; // Can't continue without meta
199
+ }
200
+ if (!schema.meta.displayType) {
201
+ errors.add(`"${schema.name}" is missing a displayType.`);
202
+ return; // Can't continue without displayType
203
+ }
204
+
205
+ // Optional field validation (these are warnings, not blocking)
206
+ if (!schema.meta.displayName) {
207
+ errors.add(`"${schema.name}" is missing a displayName.`);
208
+ }
209
+
210
+ // Only require placeholder if the component schema defines it
211
+ const componentSchema = componentSchemas[schema.meta.displayType];
212
+ if (
213
+ componentSchema &&
214
+ componentSchema.meta &&
215
+ "placeholder" in componentSchema.meta &&
216
+ !schema.meta.placeholder
217
+ ) {
218
+ errors.add(`"${schema.name}" is missing a placeholder.`);
219
+ }
220
+
221
+ // Only require description if the component schema defines it
222
+ if (
223
+ componentSchema &&
224
+ componentSchema.meta &&
225
+ "description" in componentSchema.meta &&
226
+ !schema.meta.description
227
+ ) {
228
+ errors.add(`"${schema.name}" is missing a description.`);
229
+ }
230
+
231
+ // Validate against the specific component type schema
232
+ validateComponentByType(schema, schema.meta.displayType, errors);
233
+ });
234
+ };
235
+
53
236
  // ─────────────────────────────────────────────────────────────────────────────
54
237
  // INDIVIDUAL VALIDATORS
55
238
  // ─────────────────────────────────────────────────────────────────────────────
@@ -83,6 +266,18 @@ const validateWebhook = (webhookPath, spec, errors) => {
83
266
  `"webhook.json" exists but trigger_type is not defined in spec.json.`
84
267
  );
85
268
  }
269
+
270
+ // Validate webhook schema parameters if webhook exists
271
+ if (hasWebhook) {
272
+ const webhookSchema = readAndParseJson(
273
+ webhookPath,
274
+ "webhook.json",
275
+ errors
276
+ );
277
+ if (webhookSchema && Array.isArray(webhookSchema.parameters)) {
278
+ validateComponentSchemas(webhookSchema.parameters, errors);
279
+ }
280
+ }
86
281
  };
87
282
 
88
283
  const validateBaseSchema = (baseSchemaPath, errors) => {
@@ -90,7 +285,49 @@ const validateBaseSchema = (baseSchemaPath, errors) => {
90
285
  errors.add(`"base.json" not found in the "schemas" directory.`);
91
286
  return null;
92
287
  }
93
- return readAndParseJson(baseSchemaPath, "base.json", errors);
288
+
289
+ const baseSchema = readAndParseJson(baseSchemaPath, "base.json", errors);
290
+
291
+ // Validate base schema parameters
292
+ if (baseSchema && Array.isArray(baseSchema.parameters)) {
293
+ validateComponentSchemas(baseSchema.parameters, errors);
294
+ }
295
+
296
+ return baseSchema;
297
+ };
298
+
299
+ const validateAuthentication = (authPath, errors) => {
300
+ // Authentication is optional, so only validate if it exists
301
+ if (fs.existsSync(authPath)) {
302
+ const authSchema = readAndParseJson(
303
+ authPath,
304
+ "authentication.json",
305
+ errors
306
+ );
307
+
308
+ // Validate authentication schema parameters
309
+ if (authSchema && Array.isArray(authSchema.parameters)) {
310
+ validateComponentSchemas(authSchema.parameters, errors);
311
+ }
312
+
313
+ // Validate authentication type-specific parameters (like api_key, oauth, etc.)
314
+ if (authSchema) {
315
+ Object.keys(authSchema).forEach((key) => {
316
+ if (
317
+ key !== "parameters" &&
318
+ typeof authSchema[key] === "object" &&
319
+ authSchema[key] !== null
320
+ ) {
321
+ if (Array.isArray(authSchema[key].parameters)) {
322
+ validateComponentSchemas(
323
+ authSchema[key].parameters,
324
+ errors
325
+ );
326
+ }
327
+ }
328
+ });
329
+ }
330
+ }
94
331
  };
95
332
 
96
333
  const validateResources = (resourcesDir, resourceFields, errors) => {
@@ -121,7 +358,16 @@ const validateResources = (resourcesDir, resourceFields, errors) => {
121
358
  );
122
359
  if (!schema) return;
123
360
 
124
- const operationFields = findOperationFieldsWithOptions(schema);
361
+ // Validate resource file parameters
362
+ if (Array.isArray(schema.parameters)) {
363
+ validateComponentSchemas(schema.parameters, errors);
364
+ }
365
+
366
+ const operationFields = findOperationFieldsWithOptions(
367
+ schema,
368
+ `${resourceFile}.json`,
369
+ errors
370
+ );
125
371
 
126
372
  operationFields.forEach((operation) => {
127
373
  const operationMethod = operation.split(".")[1];
@@ -144,6 +390,11 @@ const validateResources = (resourcesDir, resourceFields, errors) => {
144
390
  errors.add(
145
391
  `Operation "${operationMethod}" in "${resourceFile}.json" is missing parameters.`
146
392
  );
393
+ } else {
394
+ // Validate operation parameters using component schemas
395
+ if (Array.isArray(methodDef.parameters)) {
396
+ validateComponentSchemas(methodDef.parameters, errors);
397
+ }
147
398
  }
148
399
  if (!methodDef.definition) {
149
400
  errors.add(
@@ -167,6 +418,7 @@ export const validateIntegrationSchemas = (currentDir) => {
167
418
  resources: path.join(currentDir, "schemas", "resources"),
168
419
  spec: path.join(currentDir, "spec.json"),
169
420
  webhook: path.join(currentDir, "schemas", "webhook.json"),
421
+ authentication: path.join(currentDir, "schemas", "authentication.json"),
170
422
  documentation: path.join(currentDir, "Documentation.mdx"),
171
423
  };
172
424
 
@@ -175,10 +427,11 @@ export const validateIntegrationSchemas = (currentDir) => {
175
427
 
176
428
  const spec = validateSpec(paths.spec, errors);
177
429
  validateWebhook(paths.webhook, spec, errors);
430
+ validateAuthentication(paths.authentication, errors);
178
431
 
179
432
  const baseSchema = validateBaseSchema(paths.base, errors);
180
433
  const resourceFields = baseSchema
181
- ? findResourceFieldsWithOptions(baseSchema)
434
+ ? findResourceFieldsWithOptions(baseSchema, "base.json", errors)
182
435
  : [];
183
436
 
184
437
  validateResources(paths.resources, resourceFields, errors);
package/llm.txt ADDED
@@ -0,0 +1,295 @@
1
+ # Boltic CLI - Developer Documentation for AI Assistants
2
+
3
+ ## Overview
4
+ The Boltic CLI is a Node.js command-line interface for managing Boltic Workflow integrations. It provides tools for creating, editing, syncing, and publishing integrations to the Boltic platform.
5
+
6
+ **Package**: @boltic/cli
7
+ **Repository**: https://github.com/bolticio/cli
8
+ **License**: ISC
9
+
10
+ ## Core Architecture
11
+
12
+ ### Entry Point
13
+ - `index.js` - Main entry point and binary executable
14
+ - `cli.js` - Core CLI module with command routing and execution
15
+
16
+ ### Command Structure
17
+ The CLI follows a modular command structure:
18
+
19
+ ```
20
+ boltic [command] [subcommand] [options]
21
+ ```
22
+
23
+ ### Main Commands
24
+
25
+ #### Authentication Commands (`commands/login.js`)
26
+ - `boltic login` - Authenticate with Boltic platform
27
+ - `boltic logout` - Clear authentication tokens
28
+
29
+ #### Integration Commands (`commands/integration.js`)
30
+ - `boltic integration create` - Create new integration
31
+ - `boltic integration edit` - Edit existing integration
32
+ - `boltic integration sync` - Sync changes to draft
33
+ - `boltic integration submit` - Submit for review
34
+ - `boltic integration publish` - Submit for review (deprecated, use submit)
35
+ - `boltic integration pull` - Pull latest changes
36
+ - `boltic integration status` - Show integration details
37
+
38
+ #### Environment Commands (`commands/env.js`)
39
+ - `boltic env list` - List available environments
40
+ - `boltic env set` - Set current environment
41
+ - `boltic env show` - Show current environment
42
+
43
+ ### API Layer (`api/`)
44
+ - `integration.js` - Integration management API calls
45
+ - `login.js` - Authentication API calls
46
+ - `environment.js` - Environment management API calls
47
+
48
+ ### Helper Modules (`helper/`)
49
+ - `validation.js` - Schema validation for integrations
50
+ - `folder.js` - File system operations for integration folders
51
+ - `secure-storage.js` - Secure credential storage using keytar
52
+ - `env.js` - Environment configuration management
53
+ - `error.js` - Error handling and formatting
54
+ - `command-suggestions.js` - Command similarity suggestions
55
+ - `verbose.js` - Verbose logging control
56
+
57
+ ### Templates (`templates/`)
58
+ - `schemas.js` - Schema templates for integrations
59
+
60
+ ### Utilities (`utils/`)
61
+ - `integration.js` - Integration utility functions
62
+
63
+ ## Key Features
64
+
65
+ ### Authentication
66
+ - OAuth-based authentication with secure token storage
67
+ - Multiple environment support (bolt, fcz0, fcz5)
68
+ - Automatic token refresh and session management
69
+
70
+ ### Integration Management
71
+ - **Create**: Interactive creation wizard with prompts for:
72
+ - Integration name (letters and underscores only)
73
+ - SVG icon upload
74
+ - Integration type (Activity, Trigger, or both)
75
+ - Descriptions (human and AI-generated)
76
+ - Integration group selection
77
+ - **Edit**: Modify existing integrations
78
+ - **Sync**: Upload changes to draft version
79
+ - **Submit**: Submit integration for review
80
+ - **Publish**: Submit integration for review (deprecated, use submit)
81
+ - **Pull**: Download latest changes from cloud
82
+ - **Status**: View integration details and metadata
83
+
84
+ ### Validation System
85
+ The validation system (`helper/validation.js`) ensures integration schemas are correct:
86
+
87
+ #### Required Files
88
+ - `Documentation.mdx` - Integration documentation
89
+ - `spec.json` - Integration specification
90
+ - `schemas/base.json` - Base schema configuration
91
+ - `schemas/resources/*.json` - Resource-specific schemas
92
+ - `schemas/webhook.json` - Webhook configuration (if trigger_type defined)
93
+
94
+ #### Schema Structure
95
+ All option objects must include:
96
+ - `label` - Human-readable label
97
+ - `value` - Machine-readable value
98
+ - `description` - Detailed description
99
+
100
+ #### Validation Rules
101
+ - Resource fields must reference existing resource files
102
+ - Operation fields must reference valid operations in resource files
103
+ - Operations must have both `parameters` and `definition` properties
104
+ - Webhook configuration must match trigger_type in spec.json
105
+
106
+ ### Environment Configuration
107
+ Three supported environments defined in `config/environments.js`:
108
+ - **bolt** (production): console.boltic.io
109
+ - **fcz0** (staging): fcz0.de
110
+ - **fcz5** (UAT): uat.fcz0.de
111
+
112
+ ### File System Operations
113
+ - Automatic folder structure creation
114
+ - JSON file parsing and validation
115
+ - SVG file handling for icons
116
+ - Resource file management
117
+
118
+ ## Development Workflow
119
+
120
+ ### Testing
121
+ - **Framework**: Jest with comprehensive test coverage
122
+ - **Coverage**: 96.45% statement coverage, 91.68% branch coverage
123
+ - **Test Files**: Located in `__tests__/` directory
124
+ - **Run Tests**: `npm test`
125
+
126
+ ### Code Quality
127
+ - **Linting**: ESLint with Prettier integration
128
+ - **Pre-commit**: Husky hooks with lint-staged
129
+ - **Standards**: ES6+ modules, async/await patterns
130
+
131
+ ### Dependencies
132
+ **Production**:
133
+ - `@inquirer/prompts` - Interactive CLI prompts
134
+ - `axios` - HTTP client for API calls
135
+ - `chalk` - Terminal string styling
136
+ - `keytar` - Secure credential storage
137
+ - `open` - Browser launching
138
+ - `uuid` - Unique identifier generation
139
+ - `lodash.isempty` - Empty value checking
140
+
141
+ **Development**:
142
+ - `jest` - Testing framework
143
+ - `eslint` - Code linting
144
+ - `prettier` - Code formatting
145
+ - `husky` - Git hooks
146
+ - `nodemon` - Development server
147
+
148
+ ## Common Patterns
149
+
150
+ ### Error Handling
151
+ - Centralized error handling in `helper/error.js`
152
+ - Axios error interception and formatting
153
+ - User-friendly error messages with suggestions
154
+
155
+ ### Async Operations
156
+ - Consistent async/await usage
157
+ - Promise-based API calls
158
+ - Proper error propagation
159
+
160
+ ### User Interaction
161
+ - Interactive prompts using @inquirer/prompts
162
+ - Progress indicators for long operations
163
+ - Color-coded output using chalk
164
+
165
+ ### File Operations
166
+ - Safe JSON parsing with error handling
167
+ - Atomic file operations
168
+ - Directory existence checking
169
+
170
+ ## Configuration
171
+
172
+ ### Schema Templates
173
+ Integration schemas are generated from templates in `templates/schemas.js`:
174
+ - **Authentication**: API key-based authentication
175
+ - **Base**: Core integration configuration
176
+ - **Webhook**: Trigger configuration
177
+ - **Resource**: Resource-specific operations
178
+
179
+ ### Environment Variables
180
+ - Environment selection stored in secure storage
181
+ - API endpoints configured per environment
182
+ - OAuth client IDs per environment
183
+
184
+ ## Security Considerations
185
+
186
+ ### Credential Storage
187
+ - Secure token storage using keytar (OS keychain)
188
+ - No plaintext credential storage
189
+ - Automatic token cleanup on logout
190
+
191
+ ### API Security
192
+ - OAuth 2.0 authentication flow
193
+ - Bearer token authentication
194
+ - Environment-specific API endpoints
195
+
196
+ ### Input Validation
197
+ - Schema validation for all integration files
198
+ - SVG file validation for icons
199
+ - Input sanitization for user prompts
200
+
201
+ ## Troubleshooting
202
+
203
+ ### Common Issues
204
+ 1. **Authentication Errors**: Check network connectivity and credentials
205
+ 2. **Validation Errors**: Ensure all required schema fields are present
206
+ 3. **File System Errors**: Verify file permissions and paths
207
+ 4. **API Errors**: Check environment configuration and network
208
+
209
+ ### Debug Mode
210
+ Use `--verbose` flag for detailed logging:
211
+ ```bash
212
+ boltic --verbose integration create
213
+ ```
214
+
215
+ ### Log Files
216
+ - API calls logged in verbose mode
217
+ - Error stack traces available in debug mode
218
+ - Progress indicators for long operations
219
+
220
+ ## Contributing
221
+
222
+ ### Code Style
223
+ - ES6+ modules with import/export
224
+ - Async/await for asynchronous operations
225
+ - Functional programming patterns where applicable
226
+ - Comprehensive error handling
227
+
228
+ ### Testing Requirements
229
+ - Unit tests for all new features
230
+ - Integration tests for API calls
231
+ - Mocking external dependencies
232
+ - Minimum 95% code coverage
233
+
234
+ ### Documentation
235
+ - JSDoc comments for complex functions
236
+ - README updates for new features
237
+ - Schema documentation for integration formats
238
+ - API documentation for external integrations
239
+
240
+ ## Integration Schema Format
241
+
242
+ ### Base Schema Structure
243
+ ```json
244
+ {
245
+ "parameters": [
246
+ {
247
+ "name": "resource",
248
+ "meta": {
249
+ "options": [
250
+ {
251
+ "value": "users",
252
+ "label": "Users",
253
+ "description": "Manage users"
254
+ }
255
+ ]
256
+ }
257
+ }
258
+ ]
259
+ }
260
+ ```
261
+
262
+ ### Resource Schema Structure
263
+ ```json
264
+ {
265
+ "parameters": [
266
+ {
267
+ "name": "operation",
268
+ "meta": {
269
+ "options": [
270
+ {
271
+ "value": "users.list",
272
+ "label": "List Users",
273
+ "description": "List all users"
274
+ }
275
+ ]
276
+ }
277
+ }
278
+ ],
279
+ "list": {
280
+ "parameters": [],
281
+ "definition": {}
282
+ }
283
+ }
284
+ ```
285
+
286
+ ### Spec.json Format
287
+ ```json
288
+ {
289
+ "name": "Integration Name",
290
+ "activity_type": "customActivity",
291
+ "trigger_type": "webhook" // optional
292
+ }
293
+ ```
294
+
295
+ This documentation provides a comprehensive guide for AI assistants working with the Boltic CLI codebase, covering architecture, features, development practices, and troubleshooting procedures.
package/package.json CHANGED
@@ -1,18 +1,26 @@
1
1
  {
2
2
  "name": "@boltic/cli",
3
- "version": "1.0.6-beta.1",
3
+ "version": "1.0.6-beta.12",
4
4
  "description": "A powerful CLI tool for managing Boltic Workflow integrations",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "boltic": "index.js"
8
8
  },
9
9
  "author": "Ahmed Sakri <ahmedsakri@gofynd.com>",
10
- "homepage": "https://www.boltic.io",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/bolticio/cli.git"
13
+ },
14
+ "homepage": "https://github.com/bolticio/cli#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/bolticio/cli/issues"
17
+ },
11
18
  "scripts": {
12
19
  "start": "node index.js",
13
20
  "dev": "nodemon index.js",
14
21
  "test": "jest",
15
- "prepare": "husky"
22
+ "prepare": "husky",
23
+ "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
16
24
  },
17
25
  "keywords": [
18
26
  "cli",