create-universal-ai-context 2.5.0 → 2.6.0-final
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/LICENSE +21 -21
- package/README.md +331 -294
- package/bin/create-ai-context.js +1507 -775
- package/lib/adapters/aider.js +131 -131
- package/lib/adapters/antigravity.js +205 -205
- package/lib/adapters/claude.js +397 -397
- package/lib/adapters/cline.js +125 -125
- package/lib/adapters/continue.js +138 -138
- package/lib/adapters/copilot.js +131 -131
- package/lib/adapters/index.js +78 -78
- package/lib/adapters/windsurf.js +138 -138
- package/lib/ai-context-generator.js +234 -234
- package/lib/ai-orchestrator.js +432 -432
- package/lib/call-tracer.js +444 -444
- package/lib/content-preservation.js +243 -243
- package/lib/cross-tool-sync/file-watcher.js +274 -274
- package/lib/cross-tool-sync/index.js +41 -40
- package/lib/cross-tool-sync/sync-manager.js +540 -512
- package/lib/cross-tool-sync/sync-service.js +297 -297
- package/lib/detector.js +726 -726
- package/lib/doc-discovery.js +741 -741
- package/lib/drift-checker.js +920 -920
- package/lib/environment-detector.js +239 -239
- package/lib/index.js +399 -399
- package/lib/install-hooks.js +82 -82
- package/lib/installer.js +419 -419
- package/lib/migrate.js +328 -328
- package/lib/placeholder.js +632 -632
- package/lib/prompts.js +341 -341
- package/lib/smart-merge.js +540 -540
- package/lib/spinner.js +60 -60
- package/lib/static-analyzer.js +729 -729
- package/lib/template-coordination.js +148 -148
- package/lib/template-populator.js +843 -843
- package/lib/template-renderer.js +392 -392
- package/lib/utils/fs-wrapper.js +79 -79
- package/lib/utils/path-utils.js +60 -60
- package/lib/validate.js +155 -155
- package/package.json +1 -1
- package/templates/AI_CONTEXT.md.template +245 -245
- package/templates/base/README.md +260 -257
- package/templates/base/RPI_WORKFLOW_PLAN.md +325 -320
- package/templates/base/agents/api-developer.md +76 -76
- package/templates/base/agents/context-engineer.md +525 -525
- package/templates/base/agents/core-architect.md +76 -76
- package/templates/base/agents/database-ops.md +76 -76
- package/templates/base/agents/deployment-ops.md +76 -76
- package/templates/base/agents/integration-hub.md +76 -76
- package/templates/base/analytics/README.md +114 -114
- package/templates/base/automation/config.json +58 -58
- package/templates/base/automation/generators/code-mapper.js +308 -308
- package/templates/base/automation/generators/index-builder.js +321 -321
- package/templates/base/automation/hooks/post-commit.sh +83 -83
- package/templates/base/automation/hooks/pre-commit.sh +103 -103
- package/templates/base/ci-templates/README.md +108 -108
- package/templates/base/ci-templates/github-actions/context-check.yml +144 -144
- package/templates/base/ci-templates/github-actions/validate-docs.yml +105 -105
- package/templates/base/commands/analytics.md +238 -238
- package/templates/base/commands/auto-sync.md +172 -172
- package/templates/base/commands/collab.md +194 -194
- package/templates/base/commands/context-optimize.md +226 -0
- package/templates/base/commands/help.md +485 -450
- package/templates/base/commands/rpi-implement.md +164 -115
- package/templates/base/commands/rpi-plan.md +147 -93
- package/templates/base/commands/rpi-research.md +145 -88
- package/templates/base/commands/session-resume.md +144 -144
- package/templates/base/commands/session-save.md +112 -112
- package/templates/base/commands/validate-all.md +77 -77
- package/templates/base/commands/verify-docs-current.md +86 -86
- package/templates/base/config/base.json +57 -57
- package/templates/base/config/environments/development.json +13 -13
- package/templates/base/config/environments/production.json +17 -17
- package/templates/base/config/environments/staging.json +13 -13
- package/templates/base/config/local.json.example +21 -21
- package/templates/base/context/.meta/generated-at.json +18 -18
- package/templates/base/context/ARCHITECTURE_SNAPSHOT.md +156 -156
- package/templates/base/context/CODE_TO_WORKFLOW_MAP.md +94 -94
- package/templates/base/context/FILE_OWNERSHIP.md +57 -57
- package/templates/base/context/INTEGRATION_POINTS.md +92 -92
- package/templates/base/context/KNOWN_GOTCHAS.md +195 -195
- package/templates/base/context/TESTING_MAP.md +95 -95
- package/templates/base/context/WORKFLOW_INDEX.md +129 -129
- package/templates/base/context/workflows/WORKFLOW_TEMPLATE.md +294 -294
- package/templates/base/indexes/agents/CAPABILITY_MATRIX.md +255 -255
- package/templates/base/indexes/agents/CATEGORY_INDEX.md +44 -44
- package/templates/base/indexes/code/CATEGORY_INDEX.md +38 -38
- package/templates/base/indexes/routing/CATEGORY_INDEX.md +39 -39
- package/templates/base/indexes/search/CATEGORY_INDEX.md +39 -39
- package/templates/base/indexes/workflows/CATEGORY_INDEX.md +38 -38
- package/templates/base/knowledge/README.md +98 -98
- package/templates/base/knowledge/sessions/README.md +88 -88
- package/templates/base/knowledge/sessions/TEMPLATE.md +150 -150
- package/templates/base/knowledge/shared/decisions/0001-adopt-context-engineering.md +144 -144
- package/templates/base/knowledge/shared/decisions/README.md +49 -49
- package/templates/base/knowledge/shared/decisions/TEMPLATE.md +123 -123
- package/templates/base/knowledge/shared/patterns/README.md +62 -62
- package/templates/base/knowledge/shared/patterns/TEMPLATE.md +120 -120
- package/templates/base/plans/PLAN_TEMPLATE.md +316 -250
- package/templates/base/research/RESEARCH_TEMPLATE.md +245 -153
- package/templates/base/schemas/agent.schema.json +141 -141
- package/templates/base/schemas/anchors.schema.json +54 -54
- package/templates/base/schemas/automation.schema.json +93 -93
- package/templates/base/schemas/command.schema.json +134 -134
- package/templates/base/schemas/hashes.schema.json +40 -40
- package/templates/base/schemas/manifest.schema.json +117 -117
- package/templates/base/schemas/plan.schema.json +136 -136
- package/templates/base/schemas/research.schema.json +115 -115
- package/templates/base/schemas/roles.schema.json +34 -34
- package/templates/base/schemas/session.schema.json +77 -77
- package/templates/base/schemas/settings.schema.json +244 -244
- package/templates/base/schemas/staleness.schema.json +53 -53
- package/templates/base/schemas/team-config.schema.json +42 -42
- package/templates/base/schemas/workflow.schema.json +126 -126
- package/templates/base/session/checkpoints/.gitkeep +2 -2
- package/templates/base/session/current/state.json +20 -20
- package/templates/base/session/history/.gitkeep +2 -2
- package/templates/base/settings.json +3 -3
- package/templates/base/standards/COMPATIBILITY.md +219 -219
- package/templates/base/standards/EXTENSION_GUIDELINES.md +280 -280
- package/templates/base/standards/QUALITY_CHECKLIST.md +211 -211
- package/templates/base/standards/README.md +66 -66
- package/templates/base/sync/anchors.json +6 -6
- package/templates/base/sync/hashes.json +6 -6
- package/templates/base/sync/staleness.json +10 -10
- package/templates/base/team/README.md +168 -168
- package/templates/base/team/config.json +79 -79
- package/templates/base/team/roles.json +145 -145
- package/templates/base/tools/bin/claude-context.js +151 -151
- package/templates/base/tools/lib/anchor-resolver.js +276 -276
- package/templates/base/tools/lib/config-loader.js +363 -363
- package/templates/base/tools/lib/detector.js +350 -350
- package/templates/base/tools/lib/diagnose.js +206 -206
- package/templates/base/tools/lib/drift-detector.js +373 -373
- package/templates/base/tools/lib/errors.js +199 -199
- package/templates/base/tools/lib/index.js +36 -36
- package/templates/base/tools/lib/init.js +192 -192
- package/templates/base/tools/lib/logger.js +230 -230
- package/templates/base/tools/lib/placeholder.js +201 -201
- package/templates/base/tools/lib/session-manager.js +354 -354
- package/templates/base/tools/lib/validate.js +521 -521
- package/templates/base/tools/package.json +49 -49
- package/templates/handlebars/aider-config.hbs +146 -80
- package/templates/handlebars/antigravity.hbs +377 -377
- package/templates/handlebars/claude.hbs +183 -183
- package/templates/handlebars/cline.hbs +62 -62
- package/templates/handlebars/continue-config.hbs +116 -116
- package/templates/handlebars/copilot.hbs +130 -130
- package/templates/handlebars/partials/gotcha-list.hbs +11 -11
- package/templates/handlebars/partials/header.hbs +3 -3
- package/templates/handlebars/partials/workflow-summary.hbs +16 -16
- package/templates/handlebars/windsurf-rules.hbs +69 -69
- package/templates/hooks/post-commit.hbs +28 -29
- package/templates/hooks/pre-commit.hbs +46 -46
package/lib/adapters/aider.js
CHANGED
|
@@ -1,131 +1,131 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Aider Adapter
|
|
3
|
-
*
|
|
4
|
-
* Generates .aider.conf.yml file for Aider AI pair-programmer
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const { renderTemplateByName, buildContext } = require('../template-renderer');
|
|
10
|
-
const { isManagedFile } = require('../template-coordination');
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Adapter metadata
|
|
14
|
-
*/
|
|
15
|
-
const adapter = {
|
|
16
|
-
name: 'aider',
|
|
17
|
-
displayName: 'Aider',
|
|
18
|
-
description: 'Configuration file for Aider AI pair-programmer',
|
|
19
|
-
outputType: 'single-file',
|
|
20
|
-
outputPath: '.aider.conf.yml'
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Get output path for Aider config file
|
|
25
|
-
* @param {string} projectRoot - Project root directory
|
|
26
|
-
* @returns {string} Output file path
|
|
27
|
-
*/
|
|
28
|
-
function getOutputPath(projectRoot) {
|
|
29
|
-
return path.join(projectRoot, '.aider.conf.yml');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Check if Aider output already exists
|
|
34
|
-
* @param {string} projectRoot - Project root directory
|
|
35
|
-
* @returns {boolean}
|
|
36
|
-
*/
|
|
37
|
-
function exists(projectRoot) {
|
|
38
|
-
const configPath = getOutputPath(projectRoot);
|
|
39
|
-
return fs.existsSync(configPath);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Generate Aider config file
|
|
44
|
-
* @param {object} analysis - Analysis results from static analyzer
|
|
45
|
-
* @param {object} config - Configuration from CLI
|
|
46
|
-
* @param {string} projectRoot - Project root directory
|
|
47
|
-
* @returns {object} Generation result
|
|
48
|
-
*/
|
|
49
|
-
async function generate(analysis, config, projectRoot) {
|
|
50
|
-
const result = {
|
|
51
|
-
success: false,
|
|
52
|
-
adapter: adapter.name,
|
|
53
|
-
files: [],
|
|
54
|
-
errors: []
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
const configPath = getOutputPath(projectRoot);
|
|
59
|
-
|
|
60
|
-
// Check if file exists and is custom (not managed by us)
|
|
61
|
-
if (fs.existsSync(configPath) && !config.force) {
|
|
62
|
-
if (!isManagedFile(configPath)) {
|
|
63
|
-
result.errors.push({
|
|
64
|
-
message: '.aider.conf.yml exists and appears to be custom. Use --force to overwrite.',
|
|
65
|
-
code: 'EXISTS_CUSTOM',
|
|
66
|
-
severity: 'error'
|
|
67
|
-
});
|
|
68
|
-
return result;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Build context from analysis
|
|
73
|
-
const context = buildContext(analysis, config, 'aider');
|
|
74
|
-
|
|
75
|
-
// Render template
|
|
76
|
-
const content = renderTemplateByName('aider-config', context);
|
|
77
|
-
|
|
78
|
-
// Write output file
|
|
79
|
-
fs.writeFileSync(configPath, content, 'utf-8');
|
|
80
|
-
|
|
81
|
-
result.success = true;
|
|
82
|
-
result.files.push({
|
|
83
|
-
path: configPath,
|
|
84
|
-
relativePath: '.aider.conf.yml',
|
|
85
|
-
size: content.length
|
|
86
|
-
});
|
|
87
|
-
} catch (error) {
|
|
88
|
-
result.errors.push({
|
|
89
|
-
message: error.message,
|
|
90
|
-
stack: error.stack
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return result;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Validate Aider output
|
|
99
|
-
* @param {string} projectRoot - Project root directory
|
|
100
|
-
* @returns {object} Validation result
|
|
101
|
-
*/
|
|
102
|
-
function validate(projectRoot) {
|
|
103
|
-
const issues = [];
|
|
104
|
-
const configPath = getOutputPath(projectRoot);
|
|
105
|
-
|
|
106
|
-
if (!fs.existsSync(configPath)) {
|
|
107
|
-
issues.push({ file: '.aider.conf.yml', error: 'not found' });
|
|
108
|
-
} else {
|
|
109
|
-
const content = fs.readFileSync(configPath, 'utf-8');
|
|
110
|
-
const placeholderMatch = content.match(/\{\{[A-Z_]+\}\}/g);
|
|
111
|
-
if (placeholderMatch && placeholderMatch.length > 0) {
|
|
112
|
-
issues.push({
|
|
113
|
-
file: '.aider.conf.yml',
|
|
114
|
-
error: `Found ${placeholderMatch.length} unreplaced placeholders`
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
valid: issues.filter(i => i.severity !== 'warning').length === 0,
|
|
121
|
-
issues
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
module.exports = {
|
|
126
|
-
...adapter,
|
|
127
|
-
getOutputPath,
|
|
128
|
-
exists,
|
|
129
|
-
generate,
|
|
130
|
-
validate
|
|
131
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Aider Adapter
|
|
3
|
+
*
|
|
4
|
+
* Generates .aider.conf.yml file for Aider AI pair-programmer
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { renderTemplateByName, buildContext } = require('../template-renderer');
|
|
10
|
+
const { isManagedFile } = require('../template-coordination');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Adapter metadata
|
|
14
|
+
*/
|
|
15
|
+
const adapter = {
|
|
16
|
+
name: 'aider',
|
|
17
|
+
displayName: 'Aider',
|
|
18
|
+
description: 'Configuration file for Aider AI pair-programmer',
|
|
19
|
+
outputType: 'single-file',
|
|
20
|
+
outputPath: '.aider.conf.yml'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get output path for Aider config file
|
|
25
|
+
* @param {string} projectRoot - Project root directory
|
|
26
|
+
* @returns {string} Output file path
|
|
27
|
+
*/
|
|
28
|
+
function getOutputPath(projectRoot) {
|
|
29
|
+
return path.join(projectRoot, '.aider.conf.yml');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Check if Aider output already exists
|
|
34
|
+
* @param {string} projectRoot - Project root directory
|
|
35
|
+
* @returns {boolean}
|
|
36
|
+
*/
|
|
37
|
+
function exists(projectRoot) {
|
|
38
|
+
const configPath = getOutputPath(projectRoot);
|
|
39
|
+
return fs.existsSync(configPath);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Generate Aider config file
|
|
44
|
+
* @param {object} analysis - Analysis results from static analyzer
|
|
45
|
+
* @param {object} config - Configuration from CLI
|
|
46
|
+
* @param {string} projectRoot - Project root directory
|
|
47
|
+
* @returns {object} Generation result
|
|
48
|
+
*/
|
|
49
|
+
async function generate(analysis, config, projectRoot) {
|
|
50
|
+
const result = {
|
|
51
|
+
success: false,
|
|
52
|
+
adapter: adapter.name,
|
|
53
|
+
files: [],
|
|
54
|
+
errors: []
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const configPath = getOutputPath(projectRoot);
|
|
59
|
+
|
|
60
|
+
// Check if file exists and is custom (not managed by us)
|
|
61
|
+
if (fs.existsSync(configPath) && !config.force) {
|
|
62
|
+
if (!isManagedFile(configPath)) {
|
|
63
|
+
result.errors.push({
|
|
64
|
+
message: '.aider.conf.yml exists and appears to be custom. Use --force to overwrite.',
|
|
65
|
+
code: 'EXISTS_CUSTOM',
|
|
66
|
+
severity: 'error'
|
|
67
|
+
});
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Build context from analysis
|
|
73
|
+
const context = buildContext(analysis, config, 'aider');
|
|
74
|
+
|
|
75
|
+
// Render template
|
|
76
|
+
const content = renderTemplateByName('aider-config', context);
|
|
77
|
+
|
|
78
|
+
// Write output file
|
|
79
|
+
fs.writeFileSync(configPath, content, 'utf-8');
|
|
80
|
+
|
|
81
|
+
result.success = true;
|
|
82
|
+
result.files.push({
|
|
83
|
+
path: configPath,
|
|
84
|
+
relativePath: '.aider.conf.yml',
|
|
85
|
+
size: content.length
|
|
86
|
+
});
|
|
87
|
+
} catch (error) {
|
|
88
|
+
result.errors.push({
|
|
89
|
+
message: error.message,
|
|
90
|
+
stack: error.stack
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Validate Aider output
|
|
99
|
+
* @param {string} projectRoot - Project root directory
|
|
100
|
+
* @returns {object} Validation result
|
|
101
|
+
*/
|
|
102
|
+
function validate(projectRoot) {
|
|
103
|
+
const issues = [];
|
|
104
|
+
const configPath = getOutputPath(projectRoot);
|
|
105
|
+
|
|
106
|
+
if (!fs.existsSync(configPath)) {
|
|
107
|
+
issues.push({ file: '.aider.conf.yml', error: 'not found' });
|
|
108
|
+
} else {
|
|
109
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
110
|
+
const placeholderMatch = content.match(/\{\{[A-Z_]+\}\}/g);
|
|
111
|
+
if (placeholderMatch && placeholderMatch.length > 0) {
|
|
112
|
+
issues.push({
|
|
113
|
+
file: '.aider.conf.yml',
|
|
114
|
+
error: `Found ${placeholderMatch.length} unreplaced placeholders`
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
valid: issues.filter(i => i.severity !== 'warning').length === 0,
|
|
121
|
+
issues
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = {
|
|
126
|
+
...adapter,
|
|
127
|
+
getOutputPath,
|
|
128
|
+
exists,
|
|
129
|
+
generate,
|
|
130
|
+
validate
|
|
131
|
+
};
|
|
@@ -1,205 +1,205 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Antigravity Adapter
|
|
3
|
-
*
|
|
4
|
-
* Generates .agent/ directory with multiple files for Google Antigravity.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const { renderMultiFileTemplate, buildContext } = require('../template-renderer');
|
|
10
|
-
const { isManagedFile } = require('../template-coordination');
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Adapter metadata
|
|
14
|
-
*/
|
|
15
|
-
const adapter = {
|
|
16
|
-
name: 'antigravity',
|
|
17
|
-
displayName: 'Antigravity',
|
|
18
|
-
description: 'Multi-file context for Google Antigravity',
|
|
19
|
-
outputType: 'multi-file',
|
|
20
|
-
outputPath: '.agent/'
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Get output directory for Antigravity files
|
|
25
|
-
* @param {string} projectRoot - Project root directory
|
|
26
|
-
* @returns {string} Output directory path
|
|
27
|
-
*/
|
|
28
|
-
function getOutputPath(projectRoot) {
|
|
29
|
-
return path.join(projectRoot, '.agent');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Check if Antigravity output already exists
|
|
34
|
-
* @param {string} projectRoot - Project root directory
|
|
35
|
-
* @returns {boolean}
|
|
36
|
-
*/
|
|
37
|
-
function exists(projectRoot) {
|
|
38
|
-
return fs.existsSync(getOutputPath(projectRoot));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Generate Antigravity context files
|
|
43
|
-
* @param {object} analysis - Analysis results from static analyzer
|
|
44
|
-
* @param {object} config - Configuration from CLI
|
|
45
|
-
* @param {string} projectRoot - Project root directory
|
|
46
|
-
* @returns {object} Generation result
|
|
47
|
-
*/
|
|
48
|
-
async function generate(analysis, config, projectRoot) {
|
|
49
|
-
const result = {
|
|
50
|
-
success: false,
|
|
51
|
-
adapter: adapter.name,
|
|
52
|
-
files: [],
|
|
53
|
-
errors: []
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
try {
|
|
57
|
-
const outputDir = getOutputPath(projectRoot);
|
|
58
|
-
|
|
59
|
-
// Check if .agent/ directory exists and contains custom files
|
|
60
|
-
if (fs.existsSync(outputDir) && !config.force) {
|
|
61
|
-
const hasCustomFiles = checkForCustomFiles(outputDir);
|
|
62
|
-
if (hasCustomFiles) {
|
|
63
|
-
result.errors.push({
|
|
64
|
-
message: '.agent/ directory exists and contains custom files. Use --force to overwrite.',
|
|
65
|
-
code: 'EXISTS_CUSTOM',
|
|
66
|
-
severity: 'error'
|
|
67
|
-
});
|
|
68
|
-
return result;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Build context from analysis
|
|
73
|
-
const context = buildContext(analysis, config, 'antigravity');
|
|
74
|
-
|
|
75
|
-
// Get template path
|
|
76
|
-
const templatePath = path.join(__dirname, '..', '..', 'templates', 'handlebars', 'antigravity.hbs');
|
|
77
|
-
|
|
78
|
-
// Render multi-file template
|
|
79
|
-
const files = renderMultiFileTemplate(templatePath, context);
|
|
80
|
-
|
|
81
|
-
// Create output directory
|
|
82
|
-
if (!fs.existsSync(outputDir)) {
|
|
83
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Write each file
|
|
87
|
-
for (const file of files) {
|
|
88
|
-
const filePath = path.join(outputDir, file.filename);
|
|
89
|
-
const fileDir = path.dirname(filePath);
|
|
90
|
-
|
|
91
|
-
// Ensure directory exists
|
|
92
|
-
if (!fs.existsSync(fileDir)) {
|
|
93
|
-
fs.mkdirSync(fileDir, { recursive: true });
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Write file
|
|
97
|
-
fs.writeFileSync(filePath, file.content, 'utf-8');
|
|
98
|
-
|
|
99
|
-
result.files.push({
|
|
100
|
-
path: filePath,
|
|
101
|
-
relativePath: `.agent/${file.filename}`,
|
|
102
|
-
size: file.content.length
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
result.success = true;
|
|
107
|
-
} catch (error) {
|
|
108
|
-
result.errors.push({
|
|
109
|
-
message: error.message,
|
|
110
|
-
stack: error.stack
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return result;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Check if directory contains custom (non-managed) files
|
|
119
|
-
* @param {string} dir - Directory to check
|
|
120
|
-
* @returns {boolean} True if custom files found
|
|
121
|
-
*/
|
|
122
|
-
function checkForCustomFiles(dir) {
|
|
123
|
-
const walkDir = (currentDir, depth = 0) => {
|
|
124
|
-
if (depth > 10) return false;
|
|
125
|
-
|
|
126
|
-
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
127
|
-
for (const entry of entries) {
|
|
128
|
-
if (entry.isDirectory()) {
|
|
129
|
-
if (entry.name !== 'node_modules' && entry.name !== '.git') {
|
|
130
|
-
if (walkDir(path.join(currentDir, entry.name), depth + 1)) {
|
|
131
|
-
return true;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
} else if (entry.name.endsWith('.md')) {
|
|
135
|
-
const filePath = path.join(currentDir, entry.name);
|
|
136
|
-
if (!isManagedFile(filePath)) {
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return false;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
return walkDir(dir);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Validate Antigravity output
|
|
149
|
-
* @param {string} projectRoot - Project root directory
|
|
150
|
-
* @returns {object} Validation result
|
|
151
|
-
*/
|
|
152
|
-
function validate(projectRoot) {
|
|
153
|
-
const outputDir = getOutputPath(projectRoot);
|
|
154
|
-
|
|
155
|
-
if (!fs.existsSync(outputDir)) {
|
|
156
|
-
return {
|
|
157
|
-
valid: false,
|
|
158
|
-
error: '.agent/ directory not found'
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Check for required subdirectories
|
|
163
|
-
const requiredDirs = ['rules', 'workflows', 'skills'];
|
|
164
|
-
const missingDirs = [];
|
|
165
|
-
|
|
166
|
-
for (const dir of requiredDirs) {
|
|
167
|
-
if (!fs.existsSync(path.join(outputDir, dir))) {
|
|
168
|
-
missingDirs.push(dir);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (missingDirs.length > 0) {
|
|
173
|
-
return {
|
|
174
|
-
valid: false,
|
|
175
|
-
error: `Missing directories: ${missingDirs.join(', ')}`
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Count files
|
|
180
|
-
let fileCount = 0;
|
|
181
|
-
const countFiles = (dir) => {
|
|
182
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
183
|
-
for (const entry of entries) {
|
|
184
|
-
if (entry.isDirectory()) {
|
|
185
|
-
countFiles(path.join(dir, entry.name));
|
|
186
|
-
} else {
|
|
187
|
-
fileCount++;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
|
-
countFiles(outputDir);
|
|
192
|
-
|
|
193
|
-
return {
|
|
194
|
-
valid: true,
|
|
195
|
-
fileCount
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
module.exports = {
|
|
200
|
-
...adapter,
|
|
201
|
-
getOutputPath,
|
|
202
|
-
exists,
|
|
203
|
-
generate,
|
|
204
|
-
validate
|
|
205
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity Adapter
|
|
3
|
+
*
|
|
4
|
+
* Generates .agent/ directory with multiple files for Google Antigravity.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { renderMultiFileTemplate, buildContext } = require('../template-renderer');
|
|
10
|
+
const { isManagedFile } = require('../template-coordination');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Adapter metadata
|
|
14
|
+
*/
|
|
15
|
+
const adapter = {
|
|
16
|
+
name: 'antigravity',
|
|
17
|
+
displayName: 'Antigravity',
|
|
18
|
+
description: 'Multi-file context for Google Antigravity',
|
|
19
|
+
outputType: 'multi-file',
|
|
20
|
+
outputPath: '.agent/'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get output directory for Antigravity files
|
|
25
|
+
* @param {string} projectRoot - Project root directory
|
|
26
|
+
* @returns {string} Output directory path
|
|
27
|
+
*/
|
|
28
|
+
function getOutputPath(projectRoot) {
|
|
29
|
+
return path.join(projectRoot, '.agent');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Check if Antigravity output already exists
|
|
34
|
+
* @param {string} projectRoot - Project root directory
|
|
35
|
+
* @returns {boolean}
|
|
36
|
+
*/
|
|
37
|
+
function exists(projectRoot) {
|
|
38
|
+
return fs.existsSync(getOutputPath(projectRoot));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Generate Antigravity context files
|
|
43
|
+
* @param {object} analysis - Analysis results from static analyzer
|
|
44
|
+
* @param {object} config - Configuration from CLI
|
|
45
|
+
* @param {string} projectRoot - Project root directory
|
|
46
|
+
* @returns {object} Generation result
|
|
47
|
+
*/
|
|
48
|
+
async function generate(analysis, config, projectRoot) {
|
|
49
|
+
const result = {
|
|
50
|
+
success: false,
|
|
51
|
+
adapter: adapter.name,
|
|
52
|
+
files: [],
|
|
53
|
+
errors: []
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
const outputDir = getOutputPath(projectRoot);
|
|
58
|
+
|
|
59
|
+
// Check if .agent/ directory exists and contains custom files
|
|
60
|
+
if (fs.existsSync(outputDir) && !config.force) {
|
|
61
|
+
const hasCustomFiles = checkForCustomFiles(outputDir);
|
|
62
|
+
if (hasCustomFiles) {
|
|
63
|
+
result.errors.push({
|
|
64
|
+
message: '.agent/ directory exists and contains custom files. Use --force to overwrite.',
|
|
65
|
+
code: 'EXISTS_CUSTOM',
|
|
66
|
+
severity: 'error'
|
|
67
|
+
});
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Build context from analysis
|
|
73
|
+
const context = buildContext(analysis, config, 'antigravity');
|
|
74
|
+
|
|
75
|
+
// Get template path
|
|
76
|
+
const templatePath = path.join(__dirname, '..', '..', 'templates', 'handlebars', 'antigravity.hbs');
|
|
77
|
+
|
|
78
|
+
// Render multi-file template
|
|
79
|
+
const files = renderMultiFileTemplate(templatePath, context);
|
|
80
|
+
|
|
81
|
+
// Create output directory
|
|
82
|
+
if (!fs.existsSync(outputDir)) {
|
|
83
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Write each file
|
|
87
|
+
for (const file of files) {
|
|
88
|
+
const filePath = path.join(outputDir, file.filename);
|
|
89
|
+
const fileDir = path.dirname(filePath);
|
|
90
|
+
|
|
91
|
+
// Ensure directory exists
|
|
92
|
+
if (!fs.existsSync(fileDir)) {
|
|
93
|
+
fs.mkdirSync(fileDir, { recursive: true });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Write file
|
|
97
|
+
fs.writeFileSync(filePath, file.content, 'utf-8');
|
|
98
|
+
|
|
99
|
+
result.files.push({
|
|
100
|
+
path: filePath,
|
|
101
|
+
relativePath: `.agent/${file.filename}`,
|
|
102
|
+
size: file.content.length
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
result.success = true;
|
|
107
|
+
} catch (error) {
|
|
108
|
+
result.errors.push({
|
|
109
|
+
message: error.message,
|
|
110
|
+
stack: error.stack
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check if directory contains custom (non-managed) files
|
|
119
|
+
* @param {string} dir - Directory to check
|
|
120
|
+
* @returns {boolean} True if custom files found
|
|
121
|
+
*/
|
|
122
|
+
function checkForCustomFiles(dir) {
|
|
123
|
+
const walkDir = (currentDir, depth = 0) => {
|
|
124
|
+
if (depth > 10) return false;
|
|
125
|
+
|
|
126
|
+
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
127
|
+
for (const entry of entries) {
|
|
128
|
+
if (entry.isDirectory()) {
|
|
129
|
+
if (entry.name !== 'node_modules' && entry.name !== '.git') {
|
|
130
|
+
if (walkDir(path.join(currentDir, entry.name), depth + 1)) {
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
} else if (entry.name.endsWith('.md')) {
|
|
135
|
+
const filePath = path.join(currentDir, entry.name);
|
|
136
|
+
if (!isManagedFile(filePath)) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
return walkDir(dir);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Validate Antigravity output
|
|
149
|
+
* @param {string} projectRoot - Project root directory
|
|
150
|
+
* @returns {object} Validation result
|
|
151
|
+
*/
|
|
152
|
+
function validate(projectRoot) {
|
|
153
|
+
const outputDir = getOutputPath(projectRoot);
|
|
154
|
+
|
|
155
|
+
if (!fs.existsSync(outputDir)) {
|
|
156
|
+
return {
|
|
157
|
+
valid: false,
|
|
158
|
+
error: '.agent/ directory not found'
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Check for required subdirectories
|
|
163
|
+
const requiredDirs = ['rules', 'workflows', 'skills'];
|
|
164
|
+
const missingDirs = [];
|
|
165
|
+
|
|
166
|
+
for (const dir of requiredDirs) {
|
|
167
|
+
if (!fs.existsSync(path.join(outputDir, dir))) {
|
|
168
|
+
missingDirs.push(dir);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (missingDirs.length > 0) {
|
|
173
|
+
return {
|
|
174
|
+
valid: false,
|
|
175
|
+
error: `Missing directories: ${missingDirs.join(', ')}`
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Count files
|
|
180
|
+
let fileCount = 0;
|
|
181
|
+
const countFiles = (dir) => {
|
|
182
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
183
|
+
for (const entry of entries) {
|
|
184
|
+
if (entry.isDirectory()) {
|
|
185
|
+
countFiles(path.join(dir, entry.name));
|
|
186
|
+
} else {
|
|
187
|
+
fileCount++;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
countFiles(outputDir);
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
valid: true,
|
|
195
|
+
fileCount
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
module.exports = {
|
|
200
|
+
...adapter,
|
|
201
|
+
getOutputPath,
|
|
202
|
+
exists,
|
|
203
|
+
generate,
|
|
204
|
+
validate
|
|
205
|
+
};
|