chore: alphabetize npm scripts and fix test file formatting

This commit is contained in:
Magal 2026-05-21 11:36:19 -03:00
parent ea813716e2
commit 58c2e460c8
3 changed files with 105 additions and 75 deletions

View File

@ -36,9 +36,9 @@
"format:fix:staged": "prettier --write",
"install:bmad": "node tools/installer/bmad-cli.js install",
"lint": "eslint . --ext .js,.cjs,.mjs,.yaml --max-warnings=0",
"memtrace:restart": "node _bmad/scripts/memtrace/memtrace-restart.mjs",
"lint:fix": "eslint . --ext .js,.cjs,.mjs,.yaml --fix",
"lint:md": "markdownlint-cli2 \"**/*.md\"",
"memtrace:restart": "node _bmad/scripts/memtrace/memtrace-restart.mjs",
"prepare": "command -v husky >/dev/null 2>&1 && husky || exit 0",
"quality": "npm run format:check && npm run lint && npm run lint:md && npm run docs:build && npm run test:install && npm run test:urls && npm run validate:refs && npm run validate:skills",
"rebundle": "node tools/installer/bundlers/bundle-web.js rebundle",

View File

@ -43,15 +43,19 @@ function runInjector(mode, envOverrides = {}) {
const scriptPath = path.resolve(__dirname, '../_bmad/scripts/memtrace/inject-mcp-config.mjs');
const command = `node "${scriptPath}" --mode ${mode}`;
exec(command, {
env: { ...process.env, ...envOverrides }
}, (error, stdout, stderr) => {
if (error) {
reject({ error, stdout, stderr });
} else {
resolve({ stdout, stderr });
}
});
exec(
command,
{
env: { ...process.env, ...envOverrides },
},
(error, stdout, stderr) => {
if (error) {
reject({ error, stdout, stderr });
} else {
resolve({ stdout, stderr });
}
},
);
});
}
@ -77,14 +81,14 @@ async function runTests() {
assert(
config.mcpServers !== undefined && config.mcpServers.memtrace !== undefined,
'Test 1.1: Creates new Claude config file and injects memtrace server skeleton'
'Test 1.1: Creates new Claude config file and injects memtrace server skeleton',
);
assert(
config.mcpServers.memtrace.command === 'memtrace' && config.mcpServers.memtrace.args[0] === 'mcp',
'Test 1.1: Injected server details match expected schema format'
'Test 1.1: Injected server details match expected schema format',
);
} catch (err) {
assert(false, 'Test 1.1 Failed with error', err.message || JSON.stringify(err));
} catch (error) {
assert(false, 'Test 1.1 Failed with error', error.message || JSON.stringify(error));
}
// Test 1.2: File exists with other servers (preserves other servers)
@ -93,9 +97,9 @@ async function runTests() {
mcpServers: {
otherServer: {
command: 'node',
args: ['other-path/server.js']
}
}
args: ['other-path/server.js'],
},
},
};
await fs.writeFile(claudeTestFile, JSON.stringify(preExistingConfig, null, 2), 'utf8');
@ -105,14 +109,14 @@ async function runTests() {
assert(
config.mcpServers.otherServer !== undefined && config.mcpServers.otherServer.command === 'node',
'Test 1.2: Preserves pre-existing mcpServers in Claude config'
'Test 1.2: Preserves pre-existing mcpServers in Claude config',
);
assert(
config.mcpServers.memtrace !== undefined && config.mcpServers.memtrace.command === 'memtrace',
'Test 1.2: Correctly appends memtrace server configuration alongside existing ones'
'Test 1.2: Correctly appends memtrace server configuration alongside existing ones',
);
} catch (err) {
assert(false, 'Test 1.2 Failed with error', err.message || JSON.stringify(err));
} catch (error) {
assert(false, 'Test 1.2 Failed with error', error.message || JSON.stringify(error));
}
// Test 1.3: File exists and memtrace key already exists (overwrites memtrace key only)
@ -121,13 +125,13 @@ async function runTests() {
mcpServers: {
otherServer: {
command: 'node',
args: ['other-path/server.js']
args: ['other-path/server.js'],
},
memtrace: {
command: 'old-command',
args: ['old-arg']
}
}
args: ['old-arg'],
},
},
};
await fs.writeFile(claudeTestFile, JSON.stringify(preExistingConfig, null, 2), 'utf8');
@ -137,14 +141,14 @@ async function runTests() {
assert(
config.mcpServers.otherServer !== undefined && config.mcpServers.otherServer.command === 'node',
'Test 1.3: Overwriting preserves other servers'
'Test 1.3: Overwriting preserves other servers',
);
assert(
config.mcpServers.memtrace.command === 'memtrace' && config.mcpServers.memtrace.args[0] === 'mcp',
'Test 1.3: Correctly overwrites only the memtrace key'
'Test 1.3: Correctly overwrites only the memtrace key',
);
} catch (err) {
assert(false, 'Test 1.3 Failed with error', err.message || JSON.stringify(err));
} catch (error) {
assert(false, 'Test 1.3 Failed with error', error.message || JSON.stringify(error));
}
console.log('');
@ -164,14 +168,14 @@ async function runTests() {
assert(
config.mcp !== undefined && config.mcp.memtrace !== undefined,
'Test 2.1: Creates new OpenCode config file and injects memtrace server skeleton'
'Test 2.1: Creates new OpenCode config file and injects memtrace server skeleton',
);
assert(
config.mcp.memtrace.type === 'local' && config.mcp.memtrace.command[0] === 'memtrace' && config.mcp.memtrace.command[1] === 'mcp',
'Test 2.1: Injected server details match expected OpenCode schema format'
'Test 2.1: Injected server details match expected OpenCode schema format',
);
} catch (err) {
assert(false, 'Test 2.1 Failed with error', err.message || JSON.stringify(err));
} catch (error) {
assert(false, 'Test 2.1 Failed with error', error.message || JSON.stringify(error));
}
// Test 2.2: File exists with other keys (preserves other keys)
@ -180,9 +184,9 @@ async function runTests() {
mcp: {
otherServer: {
type: 'local',
command: ['other-server']
}
}
command: ['other-server'],
},
},
};
await fs.writeFile(opencodeTestFile, JSON.stringify(preExistingConfig, null, 2), 'utf8');
@ -192,14 +196,14 @@ async function runTests() {
assert(
config.mcp.otherServer !== undefined && config.mcp.otherServer.type === 'local',
'Test 2.2: Preserves pre-existing mcp in OpenCode config'
'Test 2.2: Preserves pre-existing mcp in OpenCode config',
);
assert(
config.mcp.memtrace !== undefined && config.mcp.memtrace.type === 'local',
'Test 2.2: Correctly appends memtrace server configuration alongside existing ones'
'Test 2.2: Correctly appends memtrace server configuration alongside existing ones',
);
} catch (err) {
assert(false, 'Test 2.2 Failed with error', err.message || JSON.stringify(err));
} catch (error) {
assert(false, 'Test 2.2 Failed with error', error.message || JSON.stringify(error));
}
// Test 2.3: File exists and memtrace key already exists (overwrites memtrace key only)
@ -208,13 +212,13 @@ async function runTests() {
mcp: {
otherServer: {
type: 'local',
command: ['other-server']
command: ['other-server'],
},
memtrace: {
type: 'remote',
command: ['old-memtrace']
}
}
command: ['old-memtrace'],
},
},
};
await fs.writeFile(opencodeTestFile, JSON.stringify(preExistingConfig, null, 2), 'utf8');
@ -224,20 +228,20 @@ async function runTests() {
assert(
config.mcp.otherServer !== undefined && config.mcp.otherServer.type === 'local',
'Test 2.3: Overwriting preserves other OpenCode servers'
'Test 2.3: Overwriting preserves other OpenCode servers',
);
assert(
config.mcp.memtrace.type === 'local' && config.mcp.memtrace.command[0] === 'memtrace',
'Test 2.3: Correctly overwrites only the memtrace key in OpenCode config'
'Test 2.3: Correctly overwrites only the memtrace key in OpenCode config',
);
} catch (err) {
assert(false, 'Test 2.3 Failed with error', err.message || JSON.stringify(err));
} catch (error) {
assert(false, 'Test 2.3 Failed with error', error.message || JSON.stringify(error));
}
// Clean up
try {
await fs.rm(tempDir, { recursive: true, force: true });
} catch (err) {
} catch {
// Ignore cleanup errors
}
@ -252,7 +256,7 @@ async function runTests() {
}
}
runTests().catch(err => {
console.error('Fatal test error:', err);
runTests().catch((error) => {
console.error('Fatal test error:', error);
process.exit(1);
});

View File

@ -58,7 +58,7 @@ async function ensureDir(filePath) {
const dir = path.dirname(filePath);
try {
await fs.mkdir(dir, { recursive: true });
} catch (err) {}
} catch { /* directory may already exist */ }
}
async function runVerification() {
@ -116,20 +116,32 @@ async function runVerification() {
const possibleBash1 = path.join(gitParent, 'bin', 'bash.exe');
const possibleBash2 = path.join(gitParent, 'bin', 'sh.exe');
if (await fs.access(possibleBash1).then(() => true).catch(() => false)) {
if (
await fs
.access(possibleBash1)
.then(() => true)
.catch(() => false)
) {
command = `"${possibleBash1}" install-bmad-memtrace.sh`;
} else if (await fs.access(possibleBash2).then(() => true).catch(() => false)) {
} else if (
await fs
.access(possibleBash2)
.then(() => true)
.catch(() => false)
) {
command = `"${possibleBash2}" install-bmad-memtrace.sh`;
}
}
} catch (e) {
} catch {
// Fallback
const paths = [
'C:\\Program Files\\Git\\bin\\bash.exe',
'C:\\Program Files (x86)\\Git\\bin\\bash.exe',
];
const paths = [String.raw`C:\Program Files\Git\bin\bash.exe`, String.raw`C:\Program Files (x86)\Git\bin\bash.exe`];
for (const p of paths) {
if (await fs.access(p).then(() => true).catch(() => false)) {
if (
await fs
.access(p)
.then(() => true)
.catch(() => false)
) {
command = `"${p}" install-bmad-memtrace.sh`;
break;
}
@ -150,23 +162,38 @@ async function runVerification() {
// 5. Assertions
// AC 1: .memtrace-workspace exists
const anchorExists = await fs.access(path.join(tempDir, '.memtrace-workspace')).then(() => true).catch(() => false);
const anchorExists = await fs
.access(path.join(tempDir, '.memtrace-workspace'))
.then(() => true)
.catch(() => false);
assert(anchorExists, 'AC 1: .memtrace-workspace anchor file successfully created in project root');
// Legacy cleanup: README.md is deleted
const readmeExists = await fs.access(dummyClonedFile).then(() => true).catch(() => false);
const readmeExists = await fs
.access(dummyClonedFile)
.then(() => true)
.catch(() => false);
assert(!readmeExists, 'Legacy cleanup: Tracked clone files (README.md) successfully deleted');
// Git removal: .git is deleted
const gitExists = await fs.access(path.join(tempDir, '.git')).then(() => true).catch(() => false);
const gitExists = await fs
.access(path.join(tempDir, '.git'))
.then(() => true)
.catch(() => false);
assert(!gitExists, 'Security/Standalone: .git directory completely removed');
// Staging cleanup: bmad-install is deleted
const stagingExists = await fs.access(path.join(tempDir, 'bmad-install')).then(() => true).catch(() => false);
const stagingExists = await fs
.access(path.join(tempDir, 'bmad-install'))
.then(() => true)
.catch(() => false);
assert(!stagingExists, 'Runtime cleanup: bmad-install staging directory successfully removed');
// BMad preservation: _bmad directory remains
const bmadExists = await fs.access(path.join(tempDir, '_bmad')).then(() => true).catch(() => false);
const bmadExists = await fs
.access(path.join(tempDir, '_bmad'))
.then(() => true)
.catch(() => false);
assert(bmadExists, 'Core preservation: _bmad directory preserved post-cleanup');
// AC 2: Claude Desktop configuration successfully injected
@ -174,7 +201,7 @@ async function runVerification() {
const claudeConfig = JSON.parse(claudeContent);
assert(
claudeConfig.mcpServers && claudeConfig.mcpServers.memtrace && claudeConfig.mcpServers.memtrace.command === 'memtrace',
'AC 2: Claude Desktop config correctly created and populated with memtrace MCP server'
'AC 2: Claude Desktop config correctly created and populated with memtrace MCP server',
);
// AC 3: OpenCode configuration successfully injected
@ -182,20 +209,19 @@ async function runVerification() {
const opencodeConfig = JSON.parse(opencodeContent);
assert(
opencodeConfig.mcp && opencodeConfig.mcp.memtrace && opencodeConfig.mcp.memtrace.type === 'local',
'AC 3: OpenCode config correctly created and populated with memtrace local definition'
'AC 3: OpenCode config correctly created and populated with memtrace local definition',
);
} catch (err) {
console.error('Verification failed with error:', err);
if (err.stdout) console.error('stdout:', err.stdout);
if (err.stderr) console.error('stderr:', err.stderr);
} catch (error) {
console.error('Verification failed with error:', error);
if (error.stdout) console.error('stdout:', error.stdout);
if (error.stderr) console.error('stderr:', error.stderr);
failed++;
}
// Clean up
try {
await fs.rm(tempDir, { recursive: true, force: true });
} catch (err) {}
} catch { /* cleanup errors are non-fatal */ }
console.log(`\n${colors.cyan}========================================`);
console.log(`Verification Summary: Passed: ${passed}, Failed: ${failed}`);
@ -208,7 +234,7 @@ async function runVerification() {
}
}
runVerification().catch(err => {
console.error('Fatal verification error:', err);
runVerification().catch((error) => {
console.error('Fatal verification error:', error);
process.exit(1);
});