@nolrm/contextkit 0.7.3

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.
@@ -0,0 +1,376 @@
1
+ const chalk = require('chalk');
2
+ const ora = require('ora');
3
+ const fs = require('fs-extra');
4
+ const path = require('path');
5
+
6
+ const DownloadManager = require('../utils/download');
7
+ const ProjectDetector = require('../utils/project-detector');
8
+ const GitHooksManager = require('../utils/git-hooks');
9
+
10
+ class UpdateCommand {
11
+ constructor() {
12
+ this.downloadManager = new DownloadManager();
13
+ this.projectDetector = new ProjectDetector();
14
+ this.gitHooksManager = new GitHooksManager();
15
+ this.repoUrl = 'https://raw.githubusercontent.com/nolrm/contextkit/main';
16
+ }
17
+
18
+ async update(options = {}) {
19
+ console.log(chalk.magenta('🔄 Updating ContextKit...'));
20
+
21
+ // Check if ContextKit is installed
22
+ if (!await fs.pathExists('.contextkit/config.yml')) {
23
+ console.log(chalk.red('❌ No ContextKit installation found in current directory'));
24
+ console.log(chalk.yellow('💡 Run: contextkit install'));
25
+ return;
26
+ }
27
+
28
+ // Check for updates
29
+ const updateInfo = await this.checkForUpdates();
30
+ if (!updateInfo.hasUpdate && !options.force) {
31
+ console.log(chalk.green('✅ ContextKit is already up to date!'));
32
+ return;
33
+ }
34
+
35
+ if (updateInfo.hasUpdate) {
36
+ console.log(chalk.blue(`📦 Updating from ${updateInfo.currentVersion} to ${updateInfo.latestVersion}`));
37
+ }
38
+
39
+ // Create backup
40
+ const backupPath = await this.createBackup();
41
+
42
+ try {
43
+ // Detect current configuration
44
+ const config = await this.parseConfig();
45
+ const projectType = this.projectDetector.detectProjectType();
46
+ const packageManager = this.projectDetector.detectPackageManager();
47
+
48
+ // Download latest files
49
+ await this.downloadFiles(projectType);
50
+
51
+ // Restore user configuration
52
+ await this.restoreUserConfig(config);
53
+
54
+ // Update Git hooks if they were enabled
55
+ if (config.features?.git_hooks) {
56
+ await this.gitHooksManager.installHooks(packageManager);
57
+ }
58
+
59
+ // Refresh installed platform integrations
60
+ await this.refreshIntegrations();
61
+
62
+ // Update version in config
63
+ await this.updateConfigVersion(updateInfo.latestVersion || '1.0.0');
64
+
65
+ console.log(chalk.green('✅ ContextKit updated successfully!'));
66
+
67
+ } catch (error) {
68
+ console.log(chalk.red('❌ Update failed, restoring from backup...'));
69
+ await this.restoreFromBackup(backupPath);
70
+ throw error;
71
+ } finally {
72
+ // Clean up backup
73
+ if (await fs.pathExists(backupPath)) {
74
+ await fs.remove(backupPath);
75
+ }
76
+ }
77
+ }
78
+
79
+ async checkForUpdates() {
80
+ try {
81
+ const axios = require('axios');
82
+ const response = await axios.get('https://api.github.com/repos/nolrm/contextkit/releases/latest', {
83
+ timeout: 5000
84
+ });
85
+
86
+ const latestVersion = response.data.tag_name.replace('v', '');
87
+ const currentVersion = await this.getCurrentVersion();
88
+ const hasUpdate = this.isNewerVersion(latestVersion, currentVersion);
89
+
90
+ return {
91
+ hasUpdate,
92
+ currentVersion,
93
+ latestVersion
94
+ };
95
+ } catch (error) {
96
+ return {
97
+ hasUpdate: true, // Assume update available if we can't check
98
+ currentVersion: await this.getCurrentVersion(),
99
+ latestVersion: 'latest',
100
+ error: error.message
101
+ };
102
+ }
103
+ }
104
+
105
+ async getCurrentVersion() {
106
+ try {
107
+ const config = await this.parseConfig();
108
+ return config.version || '1.0.0';
109
+ } catch {
110
+ return '1.0.0';
111
+ }
112
+ }
113
+
114
+ isNewerVersion(latest, current) {
115
+ const latestParts = latest.split('.').map(Number);
116
+ const currentParts = current.split('.').map(Number);
117
+
118
+ for (let i = 0; i < Math.max(latestParts.length, currentParts.length); i++) {
119
+ const latestPart = latestParts[i] || 0;
120
+ const currentPart = currentParts[i] || 0;
121
+
122
+ if (latestPart > currentPart) return true;
123
+ if (latestPart < currentPart) return false;
124
+ }
125
+
126
+ return false;
127
+ }
128
+
129
+ async createBackup() {
130
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
131
+ const backupPath = `.contextkit-backup-${timestamp}`;
132
+
133
+ await fs.copy('.contextkit', backupPath);
134
+ return backupPath;
135
+ }
136
+
137
+ async restoreFromBackup(backupPath) {
138
+ await fs.remove('.contextkit');
139
+ await fs.copy(backupPath, '.contextkit');
140
+ }
141
+
142
+ async parseConfig() {
143
+ const configContent = await fs.readFile('.contextkit/config.yml', 'utf8');
144
+ const config = {};
145
+
146
+ // Simple YAML parsing for our config format
147
+ const lines = configContent.split('\n');
148
+ for (const line of lines) {
149
+ const trimmed = line.trim();
150
+ if (trimmed.startsWith('version:')) {
151
+ config.version = trimmed.split('version:')[1].trim().replace(/"/g, '');
152
+ } else if (trimmed.startsWith('project_name:')) {
153
+ config.project_name = trimmed.split('project_name:')[1].trim().replace(/"/g, '');
154
+ } else if (trimmed.startsWith('project_type:')) {
155
+ config.project_type = trimmed.split('project_type:')[1].trim().replace(/"/g, '');
156
+ } else if (trimmed.startsWith('testing:')) {
157
+ config.features = config.features || {};
158
+ config.features.testing = trimmed.split('testing:')[1].trim() === 'true';
159
+ } else if (trimmed.startsWith('documentation:')) {
160
+ config.features = config.features || {};
161
+ config.features.documentation = trimmed.split('documentation:')[1].trim() === 'true';
162
+ } else if (trimmed.startsWith('code_review:')) {
163
+ config.features = config.features || {};
164
+ config.features.code_review = trimmed.split('code_review:')[1].trim() === 'true';
165
+ } else if (trimmed.startsWith('linting:')) {
166
+ config.features = config.features || {};
167
+ config.features.linting = trimmed.split('linting:')[1].trim() === 'true';
168
+ } else if (trimmed.startsWith('type_safety:')) {
169
+ config.features = config.features || {};
170
+ config.features.type_safety = trimmed.split('type_safety:')[1].trim() === 'true';
171
+ } else if (trimmed.startsWith('git_hooks:')) {
172
+ config.features = config.features || {};
173
+ config.features.git_hooks = trimmed.split('git_hooks:')[1].trim() === 'true';
174
+ }
175
+ }
176
+
177
+ return config;
178
+ }
179
+
180
+ async downloadFiles(projectType) {
181
+ const spinner = ora('Downloading latest files...').start();
182
+
183
+ try {
184
+ // Download only the real files (not skeleton files - those come from install)
185
+ await this.downloadManager.downloadFile(
186
+ `${this.repoUrl}/standards/README.md`,
187
+ '.contextkit/standards/README.md'
188
+ );
189
+
190
+ // Keep glossary updated (universal file)
191
+ await this.downloadManager.downloadFile(
192
+ `${this.repoUrl}/standards/glossary.md`,
193
+ '.contextkit/standards/glossary.md'
194
+ );
195
+
196
+ // Download commands
197
+ await this.downloadManager.downloadFile(
198
+ `${this.repoUrl}/commands/create-feature.md`,
199
+ '.contextkit/commands/create-feature.md'
200
+ );
201
+ await this.downloadManager.downloadFile(
202
+ `${this.repoUrl}/commands/create-component.md`,
203
+ '.contextkit/commands/create-component.md'
204
+ );
205
+ await this.downloadManager.downloadFile(
206
+ `${this.repoUrl}/commands/run-tests.md`,
207
+ '.contextkit/commands/run-tests.md'
208
+ );
209
+ await this.downloadManager.downloadFile(
210
+ `${this.repoUrl}/commands/add-documentation.md`,
211
+ '.contextkit/commands/add-documentation.md'
212
+ );
213
+ await this.downloadManager.downloadFile(
214
+ `${this.repoUrl}/commands/quality-check.md`,
215
+ '.contextkit/commands/quality-check.md'
216
+ );
217
+ await this.downloadManager.downloadFile(
218
+ `${this.repoUrl}/commands/analyze.md`,
219
+ '.contextkit/commands/analyze.md'
220
+ );
221
+
222
+ // Download hooks
223
+ await this.downloadManager.downloadFile(
224
+ `${this.repoUrl}/hooks/pre-commit.sh`,
225
+ '.contextkit/hooks/pre-commit.sh'
226
+ );
227
+ await this.downloadManager.downloadFile(
228
+ `${this.repoUrl}/hooks/pre-push.sh`,
229
+ '.contextkit/hooks/pre-push.sh'
230
+ );
231
+ await this.downloadManager.downloadFile(
232
+ `${this.repoUrl}/hooks/commit-msg.sh`,
233
+ '.contextkit/hooks/commit-msg.sh'
234
+ );
235
+ await this.downloadManager.downloadFile(
236
+ `${this.repoUrl}/hooks/setup-hooks.sh`,
237
+ '.contextkit/hooks/setup-hooks.sh'
238
+ );
239
+
240
+ // Download types
241
+ await this.downloadManager.downloadFile(
242
+ `${this.repoUrl}/types/strict.tsconfig.json`,
243
+ '.contextkit/types/strict.tsconfig.json'
244
+ );
245
+ await this.downloadManager.downloadFile(
246
+ `${this.repoUrl}/types/global.d.ts`,
247
+ '.contextkit/types/global.d.ts'
248
+ );
249
+ await this.downloadManager.downloadFile(
250
+ `${this.repoUrl}/types/type-check.sh`,
251
+ '.contextkit/types/type-check.sh'
252
+ );
253
+ await this.downloadManager.downloadFile(
254
+ `${this.repoUrl}/types/typescript-strict.json`,
255
+ '.contextkit/types/typescript-strict.json'
256
+ );
257
+
258
+ // Download templates
259
+ await this.downloadManager.downloadFile(
260
+ `${this.repoUrl}/templates/component.tsx`,
261
+ '.contextkit/templates/component.tsx'
262
+ );
263
+ await this.downloadManager.downloadFile(
264
+ `${this.repoUrl}/templates/test.tsx`,
265
+ '.contextkit/templates/test.tsx'
266
+ );
267
+ await this.downloadManager.downloadFile(
268
+ `${this.repoUrl}/templates/story.tsx`,
269
+ '.contextkit/templates/story.tsx'
270
+ );
271
+ await this.downloadManager.downloadFile(
272
+ `${this.repoUrl}/templates/hook.ts`,
273
+ '.contextkit/templates/hook.ts'
274
+ );
275
+ await this.downloadManager.downloadFile(
276
+ `${this.repoUrl}/templates/api.ts`,
277
+ '.contextkit/templates/api.ts'
278
+ );
279
+
280
+ // Download scripts
281
+ await this.downloadManager.downloadFile(
282
+ `${this.repoUrl}/legacy/update.sh`,
283
+ '.contextkit/scripts/update.sh'
284
+ );
285
+
286
+ // Make scripts executable
287
+ await fs.chmod('.contextkit/hooks/pre-commit.sh', '755');
288
+ await fs.chmod('.contextkit/hooks/pre-push.sh', '755');
289
+ await fs.chmod('.contextkit/hooks/commit-msg.sh', '755');
290
+ await fs.chmod('.contextkit/hooks/setup-hooks.sh', '755');
291
+ await fs.chmod('.contextkit/types/type-check.sh', '755');
292
+ await fs.chmod('.contextkit/scripts/update.sh', '755');
293
+
294
+ spinner.succeed('Files updated successfully');
295
+ } catch (error) {
296
+ spinner.fail('Failed to download files');
297
+ throw error;
298
+ }
299
+ }
300
+
301
+ async restoreUserConfig(config) {
302
+ // Restore user's project-specific configuration
303
+ const configContent = `# ContextKit Configuration
304
+ version: "${config.version}"
305
+ project_name: "${config.project_name}"
306
+ project_type: "${config.project_type}"
307
+
308
+ # Features
309
+ features:
310
+ testing: ${config.features?.testing || true}
311
+ documentation: ${config.features?.documentation || true}
312
+ code_review: ${config.features?.code_review || true}
313
+ linting: ${config.features?.linting || true}
314
+ type_safety: ${config.features?.type_safety || true}
315
+ git_hooks: ${config.features?.git_hooks || false}
316
+
317
+ # Paths (customize for your project)
318
+ paths:
319
+ components: "${config.paths?.components || 'src/components'}"
320
+ tests: "${config.paths?.tests || 'src/__tests__'}"
321
+ stories: "${config.paths?.stories || 'src/stories'}"
322
+ docs: "${config.paths?.docs || 'docs'}"
323
+
324
+ # Commands
325
+ commands:
326
+ create_component: "${config.commands?.create_component || '@.contextkit/commands/create-component.md'}"
327
+ create_feature: "${config.commands?.create_feature || '@.contextkit/commands/create-feature.md'}"
328
+ run_tests: "${config.commands?.run_tests || '@.contextkit/commands/run-tests.md'}"
329
+ add_docs: "${config.commands?.add_docs || '@.contextkit/commands/add-documentation.md'}"
330
+ quality_check: "${config.commands?.quality_check || '@.contextkit/commands/quality-check.md'}"
331
+ analyze: "${config.commands?.analyze || '@.contextkit/commands/analyze.md'}"
332
+ `;
333
+
334
+ await fs.writeFile('.contextkit/config.yml', configContent);
335
+ }
336
+
337
+ async refreshIntegrations() {
338
+ const { getAllIntegrationNames, getIntegration } = require('../integrations');
339
+
340
+ let refreshed = 0;
341
+ for (const name of getAllIntegrationNames()) {
342
+ const integration = getIntegration(name);
343
+ const result = await integration.validate();
344
+
345
+ // Only refresh integrations that already have files installed
346
+ if (result.present.length > 0) {
347
+ try {
348
+ await integration.install();
349
+ refreshed++;
350
+ } catch {
351
+ // Skip failed refreshes silently
352
+ }
353
+ }
354
+ }
355
+
356
+ if (refreshed > 0) {
357
+ console.log(chalk.green(` ✅ Refreshed ${refreshed} platform integration(s)`));
358
+ }
359
+ }
360
+
361
+ async updateConfigVersion(version) {
362
+ const configContent = await fs.readFile('.contextkit/config.yml', 'utf8');
363
+ const updatedContent = configContent.replace(
364
+ /version: "[^"]*"/,
365
+ `version: "${version}"`
366
+ );
367
+ await fs.writeFile('.contextkit/config.yml', updatedContent);
368
+ }
369
+ }
370
+
371
+ async function update(options) {
372
+ const updater = new UpdateCommand();
373
+ await updater.update(options);
374
+ }
375
+
376
+ module.exports = update;
package/lib/index.js ADDED
@@ -0,0 +1,9 @@
1
+ const install = require('./commands/install');
2
+ const update = require('./commands/update');
3
+ const status = require('./commands/status');
4
+
5
+ module.exports = {
6
+ install,
7
+ update,
8
+ status
9
+ };
@@ -0,0 +1,93 @@
1
+ const chalk = require('chalk');
2
+ const fs = require('fs-extra');
3
+ const path = require('path');
4
+ const BaseIntegration = require('./base-integration');
5
+
6
+ class AiderIntegration extends BaseIntegration {
7
+ constructor() {
8
+ super();
9
+ this.name = 'aider';
10
+ this.displayName = 'Aider';
11
+ this.bridgeFiles = ['CONVENTIONS.md'];
12
+ this.generatedFiles = ['.aider/rules.md', '.aiderignore'];
13
+ this.platformDir = '.aider';
14
+ }
15
+
16
+ async generateFiles() {
17
+ // Bridge file: CONVENTIONS.md (auto-loaded by Aider)
18
+ const bridgeContent = `# Project Conventions (ContextKit)
19
+
20
+ This project uses [ContextKit](https://github.com/nolrm/contextkit) for AI development standards.
21
+
22
+ ${this.getStandardsBlock()}
23
+
24
+ ## Key Rules
25
+
26
+ - Follow coding conventions in \`.contextkit/standards/code-style.md\`
27
+ - Use numbered test cases as defined in \`.contextkit/standards/testing.md\`
28
+ - Check \`.contextkit/standards/glossary.md\` for project-specific terminology
29
+ - Reference \`.contextkit/templates/\` for code generation patterns`;
30
+
31
+ await this.writeBridgeFile('CONVENTIONS.md', bridgeContent);
32
+
33
+ // .aider/rules.md — backward compat rules file
34
+ const rulesPath = path.join(__dirname, '../../integrations/aider.rules.md');
35
+ if (await fs.pathExists(rulesPath)) {
36
+ await fs.copy(rulesPath, '.aider/rules.md');
37
+ } else {
38
+ const rules = `# ContextKit Rules
39
+
40
+ ## Standards Reference
41
+
42
+ - @.contextkit/standards/code-style.md — Coding conventions
43
+ - @.contextkit/standards/testing.md — Testing patterns (numbered test cases required)
44
+ - @.contextkit/standards/architecture.md — Architecture patterns
45
+ - @.contextkit/standards/ai-guidelines.md — AI behavior rules
46
+ - @.contextkit/standards/glossary.md — Project terminology
47
+
48
+ ## Templates
49
+
50
+ - @.contextkit/templates/component.tsx — Component template
51
+ - @.contextkit/templates/test.tsx — Test template
52
+ - @.contextkit/templates/hook.ts — Custom hook template
53
+ - @.contextkit/templates/api.ts — API service template
54
+
55
+ ## Always Include
56
+
57
+ 1. Follow project coding standards
58
+ 2. Use numbered test cases
59
+ 3. Include TypeScript types
60
+ 4. Follow established patterns
61
+ 5. Check glossary for domain terms
62
+ `;
63
+ await fs.writeFile('.aider/rules.md', rules);
64
+ }
65
+
66
+ // .aiderignore — exclude contextkit internals from edits
67
+ const aiderignore = `.contextkit/hooks/
68
+ .contextkit/types/
69
+ .contextkit/scripts/
70
+ .contextkit/policies/
71
+ .contextkit/instructions/meta/
72
+ `;
73
+ // Only create if doesn't exist (don't overwrite user customizations)
74
+ if (!await fs.pathExists('.aiderignore')) {
75
+ await fs.writeFile('.aiderignore', aiderignore);
76
+ }
77
+ }
78
+
79
+ showUsage() {
80
+ console.log('');
81
+ console.log(chalk.bold(' Aider Usage:'));
82
+ console.log(' CONVENTIONS.md is auto-loaded by Aider');
83
+ console.log(' .aider/rules.md provides additional context');
84
+ console.log(' Just run: aider "create a button component"');
85
+ console.log('');
86
+ console.log(chalk.dim(' Files created:'));
87
+ console.log(chalk.dim(' CONVENTIONS.md (bridge - auto-loaded)'));
88
+ console.log(chalk.dim(' .aider/rules.md (rules)'));
89
+ console.log(chalk.dim(' .aiderignore (exclude internals)'));
90
+ }
91
+ }
92
+
93
+ module.exports = AiderIntegration;
@@ -0,0 +1,123 @@
1
+ const chalk = require('chalk');
2
+ const fs = require('fs-extra');
3
+ const path = require('path');
4
+
5
+ const MARKER = '<!-- Generated by ContextKit -->';
6
+ const MARKER_END = '<!-- End ContextKit -->';
7
+ const LEGACY_MARKER = '<!-- Generated by Vibe Kit -->';
8
+ const LEGACY_MARKER_END = '<!-- End Vibe Kit -->';
9
+
10
+ class BaseIntegration {
11
+ constructor() {
12
+ if (new.target === BaseIntegration) {
13
+ throw new Error('BaseIntegration is abstract and cannot be instantiated directly');
14
+ }
15
+ this.name = '';
16
+ this.displayName = '';
17
+ this.generatedFiles = [];
18
+ this.bridgeFiles = [];
19
+ this.platformDir = '';
20
+ }
21
+
22
+ async install() {
23
+ if (this.platformDir) {
24
+ await fs.ensureDir(this.platformDir);
25
+ }
26
+ await this.generateFiles();
27
+ }
28
+
29
+ async generateFiles() {
30
+ throw new Error('generateFiles() must be implemented by subclass');
31
+ }
32
+
33
+ async validate() {
34
+ const results = { valid: true, missing: [], present: [] };
35
+
36
+ const allFiles = [...this.generatedFiles, ...this.bridgeFiles];
37
+ for (const file of allFiles) {
38
+ if (await fs.pathExists(file)) {
39
+ results.present.push(file);
40
+ } else {
41
+ results.missing.push(file);
42
+ results.valid = false;
43
+ }
44
+ }
45
+
46
+ return results;
47
+ }
48
+
49
+ async writeBridgeFile(filePath, content) {
50
+ const dir = path.dirname(filePath);
51
+ if (dir !== '.') {
52
+ await fs.ensureDir(dir);
53
+ }
54
+
55
+ const markedContent = `${MARKER}\n${content}\n${MARKER_END}`;
56
+
57
+ if (await fs.pathExists(filePath)) {
58
+ const existing = await fs.readFile(filePath, 'utf-8');
59
+
60
+ // Check for current or legacy markers
61
+ const hasCurrentMarker = existing.includes(MARKER);
62
+ const hasLegacyMarker = existing.includes(LEGACY_MARKER);
63
+
64
+ if (hasCurrentMarker || hasLegacyMarker) {
65
+ const activeMarker = hasCurrentMarker ? MARKER : LEGACY_MARKER;
66
+ const activeMarkerEnd = hasCurrentMarker ? MARKER_END : LEGACY_MARKER_END;
67
+ const before = existing.substring(0, existing.indexOf(activeMarker));
68
+ const afterMarkerEnd = existing.indexOf(activeMarkerEnd);
69
+ const after = afterMarkerEnd !== -1
70
+ ? existing.substring(afterMarkerEnd + activeMarkerEnd.length)
71
+ : '';
72
+ await fs.writeFile(filePath, before + markedContent + after);
73
+ } else {
74
+ // Append below existing content
75
+ await fs.writeFile(filePath, existing.trimEnd() + '\n\n' + markedContent + '\n');
76
+ }
77
+ } else {
78
+ await fs.writeFile(filePath, markedContent + '\n');
79
+ }
80
+ }
81
+
82
+ async writeGeneratedFile(filePath, content) {
83
+ const dir = path.dirname(filePath);
84
+ if (dir !== '.') {
85
+ await fs.ensureDir(dir);
86
+ }
87
+ await fs.writeFile(filePath, content);
88
+ }
89
+
90
+ getStandardsBlock() {
91
+ return `## Project Standards
92
+
93
+ The following standards files define this project's conventions:
94
+
95
+ - \`.contextkit/standards/code-style.md\` — Coding conventions and style rules
96
+ - \`.contextkit/standards/testing.md\` — Testing patterns and requirements
97
+ - \`.contextkit/standards/architecture.md\` — Architecture decisions and patterns
98
+ - \`.contextkit/standards/ai-guidelines.md\` — AI behavior and usage guidelines
99
+ - \`.contextkit/standards/workflows.md\` — Development workflows and processes
100
+ - \`.contextkit/standards/glossary.md\` — Project terminology and shortcuts
101
+
102
+ ## Product Context
103
+
104
+ - \`.contextkit/product/mission-lite.md\` — Product mission (condensed)
105
+ - \`.contextkit/product/decisions.md\` — Architecture Decision Records
106
+ - \`.contextkit/product/roadmap.md\` — Development roadmap
107
+
108
+ ## Commands
109
+
110
+ - \`.contextkit/commands/analyze.md\` — Analyze and customize standards
111
+ - \`.contextkit/commands/create-component.md\` — Create components
112
+ - \`.contextkit/commands/create-feature.md\` — Create features
113
+ - \`.contextkit/commands/run-tests.md\` — Run tests
114
+ - \`.contextkit/commands/quality-check.md\` — Quality checks`;
115
+ }
116
+
117
+ showUsage() {
118
+ console.log('');
119
+ console.log(chalk.dim(` See .contextkit/standards/ for project standards`));
120
+ }
121
+ }
122
+
123
+ module.exports = BaseIntegration;