aios-core 3.1.0 ā 3.3.0
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/.aios-core/core-config.yaml +44 -0
- package/.aios-core/infrastructure/scripts/ide-sync/agent-parser.js +251 -0
- package/.aios-core/infrastructure/scripts/ide-sync/index.js +480 -0
- package/.aios-core/infrastructure/scripts/ide-sync/redirect-generator.js +200 -0
- package/.aios-core/infrastructure/scripts/ide-sync/transformers/antigravity.js +105 -0
- package/.aios-core/infrastructure/scripts/ide-sync/transformers/claude-code.js +84 -0
- package/.aios-core/infrastructure/scripts/ide-sync/transformers/cursor.js +93 -0
- package/.aios-core/infrastructure/scripts/ide-sync/transformers/trae.js +125 -0
- package/.aios-core/infrastructure/scripts/ide-sync/transformers/windsurf.js +106 -0
- package/.aios-core/infrastructure/scripts/ide-sync/validator.js +273 -0
- package/.aios-core/install-manifest.yaml +2269 -349
- package/bin/aios-init.js +126 -0
- package/package.json +13 -1
- package/scripts/generate-install-manifest.js +337 -0
- package/scripts/validate-manifest.js +265 -0
- package/src/installer/brownfield-upgrader.js +438 -0
- package/src/installer/file-hasher.js +137 -0
package/bin/aios-init.js
CHANGED
|
@@ -60,6 +60,15 @@ const { detectRepositoryContext } = resolveAiosCoreModule('scripts/repository-de
|
|
|
60
60
|
// const { GitHubProjectsAdapter } = resolveAiosCoreModule('utils/pm-adapters/github-adapter');
|
|
61
61
|
// const { JiraAdapter } = resolveAiosCoreModule('utils/pm-adapters/jira-adapter');
|
|
62
62
|
|
|
63
|
+
// Brownfield upgrade module (Story 6.18)
|
|
64
|
+
let brownfieldUpgrader;
|
|
65
|
+
try {
|
|
66
|
+
brownfieldUpgrader = require('../src/installer/brownfield-upgrader');
|
|
67
|
+
} catch (_err) {
|
|
68
|
+
// Module may not be available in older installations
|
|
69
|
+
brownfieldUpgrader = null;
|
|
70
|
+
}
|
|
71
|
+
|
|
63
72
|
async function main() {
|
|
64
73
|
console.clear();
|
|
65
74
|
|
|
@@ -142,6 +151,108 @@ async function main() {
|
|
|
142
151
|
console.log(chalk.cyan('š¦ Package:') + ` ${context.packageName}`);
|
|
143
152
|
console.log('');
|
|
144
153
|
|
|
154
|
+
// Check for existing installation (Story 6.18 - Brownfield Upgrade)
|
|
155
|
+
const installedManifestPath = path.join(projectRoot, '.aios-core', '.installed-manifest.yaml');
|
|
156
|
+
const hasExistingInstall = fs.existsSync(installedManifestPath);
|
|
157
|
+
|
|
158
|
+
if (hasExistingInstall && brownfieldUpgrader) {
|
|
159
|
+
console.log(chalk.yellow('š Existing AIOS installation detected!'));
|
|
160
|
+
console.log('');
|
|
161
|
+
|
|
162
|
+
const sourceDir = path.join(context.frameworkLocation, '.aios-core');
|
|
163
|
+
const upgradeCheck = brownfieldUpgrader.checkUpgradeAvailable(sourceDir, projectRoot);
|
|
164
|
+
|
|
165
|
+
if (upgradeCheck.available) {
|
|
166
|
+
console.log(chalk.green(` Upgrade available: ${upgradeCheck.from} ā ${upgradeCheck.to}`));
|
|
167
|
+
console.log('');
|
|
168
|
+
|
|
169
|
+
// Generate upgrade report for display
|
|
170
|
+
const sourceManifest = brownfieldUpgrader.loadSourceManifest(sourceDir);
|
|
171
|
+
const installedManifest = brownfieldUpgrader.loadInstalledManifest(projectRoot);
|
|
172
|
+
const report = brownfieldUpgrader.generateUpgradeReport(sourceManifest, installedManifest, projectRoot);
|
|
173
|
+
|
|
174
|
+
console.log(chalk.gray('ā'.repeat(80)));
|
|
175
|
+
const { upgradeChoice } = await inquirer.prompt([
|
|
176
|
+
{
|
|
177
|
+
type: 'list',
|
|
178
|
+
name: 'upgradeChoice',
|
|
179
|
+
message: chalk.white('What would you like to do?'),
|
|
180
|
+
choices: [
|
|
181
|
+
{
|
|
182
|
+
name: ` Upgrade to ${upgradeCheck.to} ` + chalk.gray(`(${report.newFiles.length} new, ${report.modifiedFiles.length} updated files)`),
|
|
183
|
+
value: 'upgrade',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: ' Dry Run ' + chalk.gray('(Show what would be changed without applying)'),
|
|
187
|
+
value: 'dry-run',
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: ' Fresh Install ' + chalk.gray('(Reinstall everything, overwrite all files)'),
|
|
191
|
+
value: 'fresh',
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
name: ' Cancel ' + chalk.gray('(Exit without changes)'),
|
|
195
|
+
value: 'cancel',
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
},
|
|
199
|
+
]);
|
|
200
|
+
|
|
201
|
+
if (upgradeChoice === 'cancel') {
|
|
202
|
+
console.log(chalk.yellow('\nInstallation cancelled.'));
|
|
203
|
+
process.exit(0);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (upgradeChoice === 'dry-run') {
|
|
207
|
+
console.log('');
|
|
208
|
+
console.log(brownfieldUpgrader.formatUpgradeReport(report));
|
|
209
|
+
console.log('');
|
|
210
|
+
console.log(chalk.yellow('This was a dry run. No files were changed.'));
|
|
211
|
+
console.log(chalk.gray('Run again and select "Upgrade" to apply changes.'));
|
|
212
|
+
process.exit(0);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (upgradeChoice === 'upgrade') {
|
|
216
|
+
console.log('');
|
|
217
|
+
console.log(chalk.blue('š¦ Applying upgrade...'));
|
|
218
|
+
|
|
219
|
+
const result = await brownfieldUpgrader.applyUpgrade(report, sourceDir, projectRoot, { dryRun: false });
|
|
220
|
+
|
|
221
|
+
if (result.success) {
|
|
222
|
+
// Update installed manifest
|
|
223
|
+
const packageJson = require(path.join(context.frameworkLocation, 'package.json'));
|
|
224
|
+
brownfieldUpgrader.updateInstalledManifest(projectRoot, sourceManifest, `aios-core@${packageJson.version}`);
|
|
225
|
+
|
|
226
|
+
console.log(chalk.green('ā') + ` Upgraded ${result.filesInstalled.length} files`);
|
|
227
|
+
if (result.filesSkipped.length > 0) {
|
|
228
|
+
console.log(chalk.yellow('ā ') + ` Preserved ${result.filesSkipped.length} user-modified files`);
|
|
229
|
+
}
|
|
230
|
+
console.log('');
|
|
231
|
+
console.log(chalk.green('ā
Upgrade complete!'));
|
|
232
|
+
console.log(chalk.gray(` From: ${upgradeCheck.from}`));
|
|
233
|
+
console.log(chalk.gray(` To: ${upgradeCheck.to}`));
|
|
234
|
+
process.exit(0);
|
|
235
|
+
} else {
|
|
236
|
+
console.error(chalk.red('ā') + ' Upgrade failed with errors:');
|
|
237
|
+
for (const err of result.errors) {
|
|
238
|
+
console.error(chalk.red(` - ${err.path}: ${err.error}`));
|
|
239
|
+
}
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// If 'fresh' was selected, continue with normal installation flow below
|
|
245
|
+
if (upgradeChoice === 'fresh') {
|
|
246
|
+
console.log(chalk.yellow('\nProceeding with fresh installation...'));
|
|
247
|
+
console.log('');
|
|
248
|
+
}
|
|
249
|
+
} else {
|
|
250
|
+
console.log(chalk.green(` Current version: ${upgradeCheck.from || 'unknown'}`));
|
|
251
|
+
console.log(chalk.gray(' No upgrade available. You can proceed with fresh install if needed.'));
|
|
252
|
+
console.log('');
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
145
256
|
// Step 1: Installation Mode
|
|
146
257
|
console.log(chalk.gray('ā'.repeat(80)));
|
|
147
258
|
const { installMode } = await inquirer.prompt([
|
|
@@ -251,6 +362,21 @@ async function main() {
|
|
|
251
362
|
if (fs.existsSync(sourceCoreDir)) {
|
|
252
363
|
await fse.copy(sourceCoreDir, targetCoreDir);
|
|
253
364
|
console.log(chalk.green('ā') + ' AIOS Core files installed ' + chalk.gray('(11 agents, 68 tasks, 23 templates)'));
|
|
365
|
+
|
|
366
|
+
// Create installed manifest for brownfield upgrades (Story 6.18)
|
|
367
|
+
if (brownfieldUpgrader) {
|
|
368
|
+
try {
|
|
369
|
+
const sourceManifest = brownfieldUpgrader.loadSourceManifest(sourceCoreDir);
|
|
370
|
+
if (sourceManifest) {
|
|
371
|
+
const packageJson = require(path.join(context.frameworkLocation, 'package.json'));
|
|
372
|
+
brownfieldUpgrader.updateInstalledManifest(context.projectRoot, sourceManifest, `aios-core@${packageJson.version}`);
|
|
373
|
+
console.log(chalk.green('ā') + ' Installation manifest created ' + chalk.gray('(enables future upgrades)'));
|
|
374
|
+
}
|
|
375
|
+
} catch (manifestErr) {
|
|
376
|
+
// Non-critical - just log warning
|
|
377
|
+
console.log(chalk.yellow('ā ') + ' Could not create installation manifest ' + chalk.gray('(brownfield upgrades may not work)'));
|
|
378
|
+
}
|
|
379
|
+
}
|
|
254
380
|
} else {
|
|
255
381
|
console.error(chalk.red('ā') + ' AIOS Core files not found');
|
|
256
382
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aios-core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.esm.js",
|
|
@@ -78,6 +78,15 @@
|
|
|
78
78
|
"version:expansion:all:patch": "node tools/bump-all-versions.js patch",
|
|
79
79
|
"release": "semantic-release",
|
|
80
80
|
"release:test": "semantic-release --dry-run --no-ci || echo 'Config test complete - authentication errors are expected locally'",
|
|
81
|
+
"generate:manifest": "node scripts/generate-install-manifest.js",
|
|
82
|
+
"validate:manifest": "node scripts/validate-manifest.js",
|
|
83
|
+
"sync:ide": "node .aios-core/infrastructure/scripts/ide-sync/index.js sync",
|
|
84
|
+
"sync:ide:validate": "node .aios-core/infrastructure/scripts/ide-sync/index.js validate",
|
|
85
|
+
"sync:ide:check": "node .aios-core/infrastructure/scripts/ide-sync/index.js validate --strict",
|
|
86
|
+
"sync:ide:cursor": "node .aios-core/infrastructure/scripts/ide-sync/index.js sync --ide cursor",
|
|
87
|
+
"sync:ide:windsurf": "node .aios-core/infrastructure/scripts/ide-sync/index.js sync --ide windsurf",
|
|
88
|
+
"sync:ide:trae": "node .aios-core/infrastructure/scripts/ide-sync/index.js sync --ide trae",
|
|
89
|
+
"prepublishOnly": "npm run generate:manifest && npm run validate:manifest",
|
|
81
90
|
"prepare": "echo 'Skipping husky - not needed for NPM publish'"
|
|
82
91
|
},
|
|
83
92
|
"dependencies": {
|
|
@@ -153,6 +162,9 @@
|
|
|
153
162
|
],
|
|
154
163
|
"*.md": [
|
|
155
164
|
"prettier --write"
|
|
165
|
+
],
|
|
166
|
+
".aios-core/development/agents/*.md": [
|
|
167
|
+
"npm run sync:ide"
|
|
156
168
|
]
|
|
157
169
|
}
|
|
158
170
|
}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Generate Install Manifest
|
|
4
|
+
* Dynamically generates install-manifest.yaml with file hashes for brownfield upgrades
|
|
5
|
+
*
|
|
6
|
+
* @script scripts/generate-install-manifest.js
|
|
7
|
+
* @story 6.18 - Dynamic Manifest & Brownfield Upgrade System
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node scripts/generate-install-manifest.js
|
|
11
|
+
* npm run generate:manifest
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const fs = require('fs-extra');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const yaml = require('js-yaml');
|
|
17
|
+
const { hashFile, hashString } = require('../src/installer/file-hasher');
|
|
18
|
+
|
|
19
|
+
// Import FOLDERS_TO_COPY from installer (same source of truth)
|
|
20
|
+
const FOLDERS_TO_COPY = [
|
|
21
|
+
// v2.1 Modular Structure
|
|
22
|
+
'core',
|
|
23
|
+
'development',
|
|
24
|
+
'product',
|
|
25
|
+
'infrastructure',
|
|
26
|
+
// v2.0 Legacy Flat Structure (backwards compatibility)
|
|
27
|
+
'agents',
|
|
28
|
+
'agent-teams',
|
|
29
|
+
'checklists',
|
|
30
|
+
'data',
|
|
31
|
+
'docs',
|
|
32
|
+
'elicitation',
|
|
33
|
+
'scripts',
|
|
34
|
+
'tasks',
|
|
35
|
+
'templates',
|
|
36
|
+
'tools',
|
|
37
|
+
'workflows',
|
|
38
|
+
// Additional directories
|
|
39
|
+
'cli',
|
|
40
|
+
'manifests',
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
const ROOT_FILES_TO_COPY = [
|
|
44
|
+
'index.js',
|
|
45
|
+
'index.esm.js',
|
|
46
|
+
'index.d.ts',
|
|
47
|
+
'core-config.yaml',
|
|
48
|
+
'package.json',
|
|
49
|
+
'user-guide.md',
|
|
50
|
+
'working-in-the-brownfield.md',
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
// Files/folders to exclude from manifest
|
|
54
|
+
const EXCLUDE_PATTERNS = [
|
|
55
|
+
/node_modules/,
|
|
56
|
+
/\.git/,
|
|
57
|
+
/\.DS_Store/,
|
|
58
|
+
/Thumbs\.db/,
|
|
59
|
+
/\.installed-manifest\.yaml$/, // Don't include installed manifest
|
|
60
|
+
/\.bak$/,
|
|
61
|
+
/\.tmp$/,
|
|
62
|
+
/~$/,
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Check if a path should be excluded
|
|
67
|
+
* @param {string} filePath - Path to check
|
|
68
|
+
* @returns {boolean} - True if should be excluded
|
|
69
|
+
*/
|
|
70
|
+
function shouldExclude(filePath) {
|
|
71
|
+
return EXCLUDE_PATTERNS.some(pattern => pattern.test(filePath));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Determine file type based on path
|
|
76
|
+
* @param {string} relativePath - Relative file path
|
|
77
|
+
* @returns {string} - File type identifier
|
|
78
|
+
*/
|
|
79
|
+
function getFileType(relativePath) {
|
|
80
|
+
const normalized = relativePath.replace(/\\/g, '/');
|
|
81
|
+
|
|
82
|
+
if (normalized.includes('/agents/') || normalized.startsWith('agents/')) {
|
|
83
|
+
return 'agent';
|
|
84
|
+
}
|
|
85
|
+
if (normalized.includes('/tasks/') || normalized.startsWith('tasks/')) {
|
|
86
|
+
return 'task';
|
|
87
|
+
}
|
|
88
|
+
if (normalized.includes('/workflows/') || normalized.startsWith('workflows/')) {
|
|
89
|
+
return 'workflow';
|
|
90
|
+
}
|
|
91
|
+
if (normalized.includes('/templates/') || normalized.startsWith('templates/')) {
|
|
92
|
+
return 'template';
|
|
93
|
+
}
|
|
94
|
+
if (normalized.includes('/checklists/') || normalized.startsWith('checklists/')) {
|
|
95
|
+
return 'checklist';
|
|
96
|
+
}
|
|
97
|
+
if (normalized.includes('/scripts/') || normalized.startsWith('scripts/')) {
|
|
98
|
+
return 'script';
|
|
99
|
+
}
|
|
100
|
+
if (normalized.includes('/tools/') || normalized.startsWith('tools/')) {
|
|
101
|
+
return 'tool';
|
|
102
|
+
}
|
|
103
|
+
if (normalized.includes('/data/') || normalized.startsWith('data/')) {
|
|
104
|
+
return 'data';
|
|
105
|
+
}
|
|
106
|
+
if (normalized.includes('/docs/') || normalized.startsWith('docs/')) {
|
|
107
|
+
return 'documentation';
|
|
108
|
+
}
|
|
109
|
+
if (normalized.includes('/elicitation/') || normalized.startsWith('elicitation/')) {
|
|
110
|
+
return 'elicitation';
|
|
111
|
+
}
|
|
112
|
+
if (normalized.includes('/manifests/') || normalized.startsWith('manifests/')) {
|
|
113
|
+
return 'manifest';
|
|
114
|
+
}
|
|
115
|
+
if (normalized.includes('/cli/') || normalized.startsWith('cli/')) {
|
|
116
|
+
return 'cli';
|
|
117
|
+
}
|
|
118
|
+
if (normalized.includes('/core/') || normalized.startsWith('core/')) {
|
|
119
|
+
return 'core';
|
|
120
|
+
}
|
|
121
|
+
if (normalized.includes('/infrastructure/') || normalized.startsWith('infrastructure/')) {
|
|
122
|
+
return 'infrastructure';
|
|
123
|
+
}
|
|
124
|
+
if (normalized.includes('/product/') || normalized.startsWith('product/')) {
|
|
125
|
+
return 'product';
|
|
126
|
+
}
|
|
127
|
+
if (normalized.includes('/development/') || normalized.startsWith('development/')) {
|
|
128
|
+
return 'development';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Root files
|
|
132
|
+
if (normalized.endsWith('.js') || normalized.endsWith('.ts')) {
|
|
133
|
+
return 'code';
|
|
134
|
+
}
|
|
135
|
+
if (normalized.endsWith('.yaml') || normalized.endsWith('.yml')) {
|
|
136
|
+
return 'config';
|
|
137
|
+
}
|
|
138
|
+
if (normalized.endsWith('.md')) {
|
|
139
|
+
return 'documentation';
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return 'other';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Recursively scan directory and collect file metadata
|
|
147
|
+
* @param {string} dirPath - Directory to scan
|
|
148
|
+
* @param {string} basePath - Base path for relative paths
|
|
149
|
+
* @param {string[]} files - Array to collect files
|
|
150
|
+
*/
|
|
151
|
+
function scanDirectory(dirPath, basePath, files = []) {
|
|
152
|
+
if (!fs.existsSync(dirPath)) {
|
|
153
|
+
return files;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
157
|
+
|
|
158
|
+
for (const entry of entries) {
|
|
159
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
160
|
+
const relativePath = path.relative(basePath, fullPath).replace(/\\/g, '/');
|
|
161
|
+
|
|
162
|
+
if (shouldExclude(relativePath)) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (entry.isDirectory()) {
|
|
167
|
+
scanDirectory(fullPath, basePath, files);
|
|
168
|
+
} else if (entry.isFile()) {
|
|
169
|
+
files.push(fullPath);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return files;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Generate the install manifest
|
|
178
|
+
* @returns {Object} - Manifest object
|
|
179
|
+
*/
|
|
180
|
+
async function generateManifest() {
|
|
181
|
+
const aiosCoreDir = path.join(__dirname, '..', '.aios-core');
|
|
182
|
+
const packageJsonPath = path.join(__dirname, '..', 'package.json');
|
|
183
|
+
|
|
184
|
+
if (!fs.existsSync(aiosCoreDir)) {
|
|
185
|
+
throw new Error(`.aios-core directory not found at ${aiosCoreDir}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Get version from package.json
|
|
189
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
190
|
+
const version = packageJson.version;
|
|
191
|
+
|
|
192
|
+
console.log(`Generating manifest for aios-core v${version}...`);
|
|
193
|
+
|
|
194
|
+
const allFiles = [];
|
|
195
|
+
|
|
196
|
+
// Scan folders
|
|
197
|
+
for (const folder of FOLDERS_TO_COPY) {
|
|
198
|
+
const folderPath = path.join(aiosCoreDir, folder);
|
|
199
|
+
if (fs.existsSync(folderPath)) {
|
|
200
|
+
scanDirectory(folderPath, aiosCoreDir, allFiles);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Add root files
|
|
205
|
+
for (const file of ROOT_FILES_TO_COPY) {
|
|
206
|
+
const filePath = path.join(aiosCoreDir, file);
|
|
207
|
+
if (fs.existsSync(filePath)) {
|
|
208
|
+
allFiles.push(filePath);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Note: install-manifest.yaml itself is not included in the manifest
|
|
213
|
+
// as it would create a circular dependency during validation
|
|
214
|
+
|
|
215
|
+
console.log(`Found ${allFiles.length} files to include in manifest`);
|
|
216
|
+
|
|
217
|
+
// Generate file entries with metadata
|
|
218
|
+
const fileEntries = [];
|
|
219
|
+
let processedCount = 0;
|
|
220
|
+
|
|
221
|
+
for (const fullPath of allFiles) {
|
|
222
|
+
try {
|
|
223
|
+
const relativePath = path.relative(aiosCoreDir, fullPath).replace(/\\/g, '/');
|
|
224
|
+
const stats = fs.statSync(fullPath);
|
|
225
|
+
const hash = hashFile(fullPath);
|
|
226
|
+
const fileType = getFileType(relativePath);
|
|
227
|
+
|
|
228
|
+
fileEntries.push({
|
|
229
|
+
path: relativePath,
|
|
230
|
+
hash: `sha256:${hash}`,
|
|
231
|
+
type: fileType,
|
|
232
|
+
size: stats.size,
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
processedCount++;
|
|
236
|
+
if (processedCount % 50 === 0) {
|
|
237
|
+
console.log(` Processed ${processedCount}/${allFiles.length} files...`);
|
|
238
|
+
}
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.warn(` Warning: Could not process ${fullPath}: ${error.message}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Sort files by path for consistent output
|
|
245
|
+
fileEntries.sort((a, b) => a.path.localeCompare(b.path));
|
|
246
|
+
|
|
247
|
+
// Build manifest object
|
|
248
|
+
const manifest = {
|
|
249
|
+
version: version,
|
|
250
|
+
generated_at: new Date().toISOString(),
|
|
251
|
+
generator: 'scripts/generate-install-manifest.js',
|
|
252
|
+
file_count: fileEntries.length,
|
|
253
|
+
files: fileEntries,
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
return manifest;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Write manifest to file
|
|
261
|
+
* @param {Object} manifest - Manifest object
|
|
262
|
+
*/
|
|
263
|
+
async function writeManifest(manifest) {
|
|
264
|
+
const manifestPath = path.join(__dirname, '..', '.aios-core', 'install-manifest.yaml');
|
|
265
|
+
|
|
266
|
+
// Generate YAML with custom options for readability
|
|
267
|
+
const yamlContent = yaml.dump(manifest, {
|
|
268
|
+
indent: 2,
|
|
269
|
+
lineWidth: 120,
|
|
270
|
+
noRefs: true,
|
|
271
|
+
sortKeys: false,
|
|
272
|
+
quotingType: '"',
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// Add header comment
|
|
276
|
+
const header = `# AIOS-Core Install Manifest
|
|
277
|
+
# Auto-generated by scripts/generate-install-manifest.js
|
|
278
|
+
# DO NOT EDIT MANUALLY - regenerate with: npm run generate:manifest
|
|
279
|
+
#
|
|
280
|
+
# This manifest is used for brownfield upgrades to track:
|
|
281
|
+
# - Which files are part of the framework
|
|
282
|
+
# - SHA256 hashes for change detection
|
|
283
|
+
# - File types for categorization
|
|
284
|
+
#
|
|
285
|
+
`;
|
|
286
|
+
|
|
287
|
+
fs.writeFileSync(manifestPath, header + yamlContent, 'utf8');
|
|
288
|
+
|
|
289
|
+
console.log(`\nManifest written to: ${manifestPath}`);
|
|
290
|
+
console.log(` Version: ${manifest.version}`);
|
|
291
|
+
console.log(` Files: ${manifest.file_count}`);
|
|
292
|
+
console.log(` Generated: ${manifest.generated_at}`);
|
|
293
|
+
|
|
294
|
+
// Also compute and display manifest hash for integrity verification
|
|
295
|
+
const manifestHash = hashString(yamlContent);
|
|
296
|
+
console.log(` Manifest hash: sha256:${manifestHash.substring(0, 16)}...`);
|
|
297
|
+
|
|
298
|
+
return manifestPath;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Main execution
|
|
303
|
+
*/
|
|
304
|
+
async function main() {
|
|
305
|
+
try {
|
|
306
|
+
console.log('='.repeat(60));
|
|
307
|
+
console.log('AIOS-Core Install Manifest Generator');
|
|
308
|
+
console.log('='.repeat(60));
|
|
309
|
+
console.log('');
|
|
310
|
+
|
|
311
|
+
const manifest = await generateManifest();
|
|
312
|
+
await writeManifest(manifest);
|
|
313
|
+
|
|
314
|
+
console.log('\nā
Manifest generated successfully!');
|
|
315
|
+
process.exit(0);
|
|
316
|
+
} catch (error) {
|
|
317
|
+
console.error('\nā Error generating manifest:', error.message);
|
|
318
|
+
if (process.env.DEBUG) {
|
|
319
|
+
console.error(error.stack);
|
|
320
|
+
}
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Run if called directly
|
|
326
|
+
if (require.main === module) {
|
|
327
|
+
main();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
module.exports = {
|
|
331
|
+
generateManifest,
|
|
332
|
+
writeManifest,
|
|
333
|
+
getFileType,
|
|
334
|
+
scanDirectory,
|
|
335
|
+
FOLDERS_TO_COPY,
|
|
336
|
+
ROOT_FILES_TO_COPY,
|
|
337
|
+
};
|