aios-core
Version:
Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework
124 lines (100 loc) • 3.4 kB
JavaScript
;
/**
* IDS Pre-Push Hook (Story IDS-3)
*
* Runs synchronously before push to ensure registry is up-to-date.
* Processes all files that differ between local HEAD and remote tracking branch.
* Exits with 0 (success) even on errors — registry issues should not block push.
*
* Usage: node .aios-core/hooks/ids-pre-push.js
*/
const { execSync } = require('child_process');
const path = require('path');
const REPO_ROOT = path.resolve(__dirname, '../..');
function isDocsOnlyPath(relativePath) {
const p = String(relativePath || '').replace(/\\/g, '/');
if (!p) return false;
if (p.startsWith('docs/')) return true;
if (p === 'README.md') return true;
if (p === 'CHANGELOG.md') return true;
if (p === 'CONTRIBUTING.md') return true;
if (p === 'CODE_OF_CONDUCT.md') return true;
if (p === 'AGENTS.md') return true;
return false;
}
function isDocsOnlyPush(changes) {
if (!Array.isArray(changes) || changes.length === 0) return false;
return changes.every((c) => isDocsOnlyPath(c.relativePath));
}
function getChangedFilesSinceRemote() {
try {
const trackingBranch = execSync('git rev-parse --abbrev-ref --symbolic-full-name @{u}', {
cwd: REPO_ROOT,
encoding: 'utf8',
timeout: 5000,
}).trim();
const output = execSync(`git diff --name-status ${trackingBranch}...HEAD`, {
cwd: REPO_ROOT,
encoding: 'utf8',
timeout: 10000,
});
const changes = [];
const lines = output.trim().split('\n').filter(Boolean);
for (const line of lines) {
const [status, ...fileParts] = line.split('\t');
if (fileParts.length === 0) continue;
let action;
let filePath;
if (status === 'A') {
action = 'add';
filePath = fileParts[0];
} else if (status === 'M') {
action = 'change';
filePath = fileParts[0];
} else if (status === 'D') {
action = 'unlink';
filePath = fileParts[0];
} else if (status.startsWith('R') || status.startsWith('C')) {
action = status.startsWith('C') ? 'add' : 'change';
filePath = fileParts[fileParts.length - 1];
} else {
continue;
}
if (!filePath) continue;
changes.push({
action,
relativePath: filePath,
filePath: path.resolve(REPO_ROOT, filePath),
});
}
return changes;
} catch {
// No tracking branch or git error — skip
return [];
}
}
async function main() {
const changes = getChangedFilesSinceRemote();
if (changes.length === 0) {
console.log('[IDS-Hook] No relevant changes for registry update.');
process.exit(0);
}
if (process.env.AIOS_IDS_FORCE !== '1' && isDocsOnlyPush(changes)) {
console.log('[IDS-Hook] Docs-only push detected, skipping registry update.');
process.exit(0);
}
try {
const { RegistryUpdater } = require(path.resolve(REPO_ROOT, '.aios-core/core/ids/registry-updater.js'));
const updater = new RegistryUpdater();
const result = await updater.processChanges(changes);
if (result.updated > 0) {
console.log(`[IDS-Hook] Registry synced: ${result.updated} entities updated before push.`);
}
} catch (err) {
// Pre-push hook should warn but NOT block push
console.warn(`[IDS-Hook] Registry sync failed (non-blocking): ${err.message}`);
}
process.exit(0);
}
main();