@boltic/cli 1.0.6-beta.7 → 1.0.6

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,24 +52,226 @@ const findResourceFieldsWithOptions = (schema) => {
32
52
  }
33
53
  return resourceFields;
34
54
  };
35
-
36
- const findOperationFieldsWithOptions = (schema) => {
55
+ const findOperationFieldsWithOptions = (
56
+ schema,
57
+ fileLabel,
58
+ errors,
59
+ expectedResourceName
60
+ ) => {
37
61
  const operationFields = [];
62
+
38
63
  if (Array.isArray(schema?.parameters)) {
39
64
  schema.parameters.forEach((param) => {
40
65
  if (
41
66
  param.name === "operation" &&
42
67
  Array.isArray(param.meta?.options)
43
68
  ) {
44
- operationFields.push(
45
- ...param.meta.options.map((opt) => opt.value)
69
+ validateOptionObject(
70
+ param.meta.options,
71
+ "operation",
72
+ fileLabel,
73
+ errors
46
74
  );
75
+ param.meta.options.forEach((opt, index) => {
76
+ if (typeof opt.value === "string") {
77
+ const parts = opt.value.split(".");
78
+ if (parts.length < 2) {
79
+ errors.add(
80
+ `"operation" field in "${fileLabel}" has an invalid option at index ${index} with value "${opt.value}". Expected format "resource.operation".`
81
+ );
82
+ } else {
83
+ const resource = parts[0];
84
+ if (resource !== expectedResourceName) {
85
+ errors.add(
86
+ `"operation" field in "${fileLabel}" has an inconsistent resource prefix at index ${index}. Found "${resource}" but expected "${expectedResourceName}".`
87
+ );
88
+ }
89
+ operationFields.push(opt.value);
90
+ }
91
+ }
92
+ });
47
93
  }
48
94
  });
49
95
  }
96
+
50
97
  return operationFields;
51
98
  };
52
99
 
100
+ // ─────────────────────────────────────────────────────────────────────────────
101
+ // VALIDATE COMPONENT SCHEMAS
102
+ // ─────────────────────────────────────────────────────────────────────────────
103
+
104
+ /**
105
+ * Extract all possible keys from a component schema structure recursively
106
+ * @param {Object} obj - The object to extract keys from
107
+ * @param {string} prefix - Current key prefix for nested objects
108
+ * @returns {Set<string>} Set of all allowed keys with dot notation for nested paths
109
+ */
110
+ const extractAllowedKeys = (obj, prefix = "") => {
111
+ const allowedKeys = new Set();
112
+
113
+ Object.keys(obj).forEach((key) => {
114
+ const fullKey = prefix ? `${prefix}.${key}` : key;
115
+ allowedKeys.add(fullKey);
116
+
117
+ if (
118
+ typeof obj[key] === "object" &&
119
+ obj[key] !== null &&
120
+ !Array.isArray(obj[key])
121
+ ) {
122
+ const nestedKeys = extractAllowedKeys(obj[key], fullKey);
123
+ nestedKeys.forEach((nestedKey) => allowedKeys.add(nestedKey));
124
+ }
125
+ });
126
+
127
+ return allowedKeys;
128
+ };
129
+
130
+ /**
131
+ * Validate that a schema object doesn't contain any extra keys
132
+ * @param {Object} schemaObj - The schema object to validate
133
+ * @param {Set<string>} allowedKeys - Set of allowed keys
134
+ * @param {string} schemaName - Name of the schema for error messages
135
+ * @param {string} displayType - The display type for error messages
136
+ * @param {Set} errors - Error collection
137
+ * @param {string} prefix - Current key prefix for nested objects
138
+ */
139
+ const validateSchemaKeys = (
140
+ schemaObj,
141
+ allowedKeys,
142
+ schemaName,
143
+ displayType,
144
+ errors,
145
+ prefix = ""
146
+ ) => {
147
+ Object.keys(schemaObj).forEach((key) => {
148
+ const fullKey = prefix ? `${prefix}.${key}` : key;
149
+
150
+ if (!allowedKeys.has(fullKey)) {
151
+ errors.add(
152
+ `"${schemaName}" has an invalid key "${fullKey}" for displayType "${displayType}".`
153
+ );
154
+ }
155
+
156
+ if (
157
+ typeof schemaObj[key] === "object" &&
158
+ schemaObj[key] !== null &&
159
+ !Array.isArray(schemaObj[key])
160
+ ) {
161
+ validateSchemaKeys(
162
+ schemaObj[key],
163
+ allowedKeys,
164
+ schemaName,
165
+ displayType,
166
+ errors,
167
+ fullKey
168
+ );
169
+ }
170
+ });
171
+ };
172
+
173
+ /**
174
+ * Validate a single component schema against its component type definition
175
+ * @param {Object} schema - The schema to validate
176
+ * @param {string} displayType - The display type to validate against
177
+ * @param {Set} errors - Error collection
178
+ */
179
+ const validateComponentByType = (schema, displayType, errors) => {
180
+ // Get the component schema definition for this display type
181
+ const componentSchema = componentSchemas[displayType];
182
+
183
+ if (!componentSchema) {
184
+ errors.add(
185
+ `"${schema.name}" has an unsupported displayType "${displayType}".`
186
+ );
187
+ return;
188
+ }
189
+
190
+ if (!componentSchema.meta) {
191
+ errors.add(
192
+ `Component schema for "${displayType}" is missing meta definition.`
193
+ );
194
+ return;
195
+ }
196
+
197
+ // Extract allowed keys from the component schema
198
+ const allowedKeys = extractAllowedKeys(componentSchema.meta);
199
+
200
+ // Validate the schema meta object (excluding displayType which we already handled)
201
+ const { displayType: currentDisplayType, ...restMeta } = schema.meta;
202
+ validateSchemaKeys(
203
+ restMeta,
204
+ allowedKeys,
205
+ schema.name,
206
+ currentDisplayType,
207
+ errors
208
+ );
209
+ };
210
+
211
+ const validateComponentSchemas = (schemas, errors) => {
212
+ schemas.forEach((schema) => {
213
+ // Basic required field validation
214
+ if (!schema.name) {
215
+ errors.add(`Schema is missing a name.`);
216
+ return; // Can't continue without a name
217
+ }
218
+ if (!schema.meta) {
219
+ errors.add(`"${schema.name}" is missing a meta object.`);
220
+ return; // Can't continue without meta
221
+ }
222
+ if (!schema.meta.displayType) {
223
+ errors.add(`"${schema.name}" is missing a displayType.`);
224
+ return; // Can't continue without displayType
225
+ }
226
+
227
+ // Optional field validation (these are warnings, not blocking)
228
+ if (!schema.meta.displayName) {
229
+ errors.add(`"${schema.name}" is missing a displayName.`);
230
+ }
231
+
232
+ // Only require placeholder if the component schema defines it
233
+ const componentSchema = componentSchemas[schema.meta.displayType];
234
+ if (
235
+ componentSchema &&
236
+ componentSchema.meta &&
237
+ "placeholder" in componentSchema.meta &&
238
+ !schema.meta.placeholder
239
+ ) {
240
+ errors.add(`"${schema.name}" is missing a placeholder.`);
241
+ }
242
+
243
+ // Only require description if the component schema defines it
244
+ if (
245
+ componentSchema &&
246
+ componentSchema.meta &&
247
+ "description" in componentSchema.meta &&
248
+ !schema.meta.description
249
+ ) {
250
+ errors.add(`"${schema.name}" is missing a description.`);
251
+ }
252
+
253
+ // 🚨 Validate for duplicate options with same label and value
254
+ if (Array.isArray(schema.meta.options)) {
255
+ const seen = new Set();
256
+ schema.meta.options.forEach((option, index) => {
257
+ if (option && typeof option === "object") {
258
+ const key = `${option.label}::${option.value}`;
259
+ if (seen.has(key)) {
260
+ errors.add(
261
+ `"${schema.name}" contains duplicate option at index ${index} with label "${option.label}" and value "${option.value}".`
262
+ );
263
+ } else {
264
+ seen.add(key);
265
+ }
266
+ }
267
+ });
268
+ }
269
+
270
+ // Validate against the specific component type schema
271
+ validateComponentByType(schema, schema.meta.displayType, errors);
272
+ });
273
+ };
274
+
53
275
  // ─────────────────────────────────────────────────────────────────────────────
54
276
  // INDIVIDUAL VALIDATORS
55
277
  // ─────────────────────────────────────────────────────────────────────────────
@@ -83,6 +305,18 @@ const validateWebhook = (webhookPath, spec, errors) => {
83
305
  `"webhook.json" exists but trigger_type is not defined in spec.json.`
84
306
  );
85
307
  }
308
+
309
+ // Validate webhook schema parameters if webhook exists
310
+ if (hasWebhook) {
311
+ const webhookSchema = readAndParseJson(
312
+ webhookPath,
313
+ "webhook.json",
314
+ errors
315
+ );
316
+ if (webhookSchema && Array.isArray(webhookSchema.parameters)) {
317
+ validateComponentSchemas(webhookSchema.parameters, errors);
318
+ }
319
+ }
86
320
  };
87
321
 
88
322
  const validateBaseSchema = (baseSchemaPath, errors) => {
@@ -90,7 +324,49 @@ const validateBaseSchema = (baseSchemaPath, errors) => {
90
324
  errors.add(`"base.json" not found in the "schemas" directory.`);
91
325
  return null;
92
326
  }
93
- return readAndParseJson(baseSchemaPath, "base.json", errors);
327
+
328
+ const baseSchema = readAndParseJson(baseSchemaPath, "base.json", errors);
329
+
330
+ // Validate base schema parameters
331
+ if (baseSchema && Array.isArray(baseSchema.parameters)) {
332
+ validateComponentSchemas(baseSchema.parameters, errors);
333
+ }
334
+
335
+ return baseSchema;
336
+ };
337
+
338
+ const validateAuthentication = (authPath, errors) => {
339
+ // Authentication is optional, so only validate if it exists
340
+ if (fs.existsSync(authPath)) {
341
+ const authSchema = readAndParseJson(
342
+ authPath,
343
+ "authentication.json",
344
+ errors
345
+ );
346
+
347
+ // Validate authentication schema parameters
348
+ if (authSchema && Array.isArray(authSchema.parameters)) {
349
+ validateComponentSchemas(authSchema.parameters, errors);
350
+ }
351
+
352
+ // Validate authentication type-specific parameters (like api_key, oauth, etc.)
353
+ if (authSchema) {
354
+ Object.keys(authSchema).forEach((key) => {
355
+ if (
356
+ key !== "parameters" &&
357
+ typeof authSchema[key] === "object" &&
358
+ authSchema[key] !== null
359
+ ) {
360
+ if (Array.isArray(authSchema[key].parameters)) {
361
+ validateComponentSchemas(
362
+ authSchema[key].parameters,
363
+ errors
364
+ );
365
+ }
366
+ }
367
+ });
368
+ }
369
+ }
94
370
  };
95
371
 
96
372
  const validateResources = (resourcesDir, resourceFields, errors) => {
@@ -121,7 +397,17 @@ const validateResources = (resourcesDir, resourceFields, errors) => {
121
397
  );
122
398
  if (!schema) return;
123
399
 
124
- const operationFields = findOperationFieldsWithOptions(schema);
400
+ // Validate resource file parameters
401
+ if (Array.isArray(schema.parameters)) {
402
+ validateComponentSchemas(schema.parameters, errors);
403
+ }
404
+
405
+ const operationFields = findOperationFieldsWithOptions(
406
+ schema,
407
+ `${resourceFile}.json`,
408
+ errors,
409
+ resourceFile
410
+ );
125
411
 
126
412
  operationFields.forEach((operation) => {
127
413
  const operationMethod = operation.split(".")[1];
@@ -144,6 +430,11 @@ const validateResources = (resourcesDir, resourceFields, errors) => {
144
430
  errors.add(
145
431
  `Operation "${operationMethod}" in "${resourceFile}.json" is missing parameters.`
146
432
  );
433
+ } else {
434
+ // Validate operation parameters using component schemas
435
+ if (Array.isArray(methodDef.parameters)) {
436
+ validateComponentSchemas(methodDef.parameters, errors);
437
+ }
147
438
  }
148
439
  if (!methodDef.definition) {
149
440
  errors.add(
@@ -154,23 +445,6 @@ const validateResources = (resourcesDir, resourceFields, errors) => {
154
445
  });
155
446
  };
156
447
 
157
- // const validateParametersScema = (schema, errors) => {
158
- // if (!schema || !Array.isArray(schema.parameters)) {
159
- // errors.add(
160
- // `Schema is missing or parameters are not defined as an array.`
161
- // );
162
- // return;
163
- // }
164
- // schema.parameters.forEach((param) => {
165
- // const { meta } = param;
166
- // if (!param.name) {
167
- // errors.add(
168
- // `Parameter in schema is missing a name. Ensure all parameters have a "name" field.`
169
- // );
170
- // }
171
- // });
172
- // };
173
-
174
448
  // ─────────────────────────────────────────────────────────────────────────────
175
449
  // MAIN FUNCTION
176
450
  // ─────────────────────────────────────────────────────────────────────────────
@@ -184,6 +458,7 @@ export const validateIntegrationSchemas = (currentDir) => {
184
458
  resources: path.join(currentDir, "schemas", "resources"),
185
459
  spec: path.join(currentDir, "spec.json"),
186
460
  webhook: path.join(currentDir, "schemas", "webhook.json"),
461
+ authentication: path.join(currentDir, "schemas", "authentication.json"),
187
462
  documentation: path.join(currentDir, "Documentation.mdx"),
188
463
  };
189
464
 
@@ -192,10 +467,11 @@ export const validateIntegrationSchemas = (currentDir) => {
192
467
 
193
468
  const spec = validateSpec(paths.spec, errors);
194
469
  validateWebhook(paths.webhook, spec, errors);
470
+ validateAuthentication(paths.authentication, errors);
195
471
 
196
472
  const baseSchema = validateBaseSchema(paths.base, errors);
197
473
  const resourceFields = baseSchema
198
- ? findResourceFieldsWithOptions(baseSchema)
474
+ ? findResourceFieldsWithOptions(baseSchema, "base.json", errors)
199
475
  : [];
200
476
 
201
477
  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.