Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions bin/multiagent-safety.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const GH_BIN = process.env.MUSAFETY_GH_BIN || 'gh';
const REQUIRED_SYSTEM_TOOLS = [
{
name: 'gh',
displayName: 'GitHub (gh)',
command: GH_BIN,
installHint: 'https://cli.github.com/',
},
Expand Down Expand Up @@ -2057,6 +2058,7 @@ function detectRequiredSystemTools() {
const reason = rawReason.split('\n')[0] || '';
services.push({
name: tool.name,
displayName: tool.displayName || tool.name,
command: tool.command,
installHint: tool.installHint,
status: active ? 'active' : 'inactive',
Expand Down Expand Up @@ -2409,6 +2411,7 @@ function status(rawArgs) {
...npmServices,
...requiredSystemTools.map((tool) => ({
name: tool.name,
displayName: tool.displayName || tool.name,
status: tool.status,
})),
];
Expand Down Expand Up @@ -2457,11 +2460,14 @@ function status(rawArgs) {

console.log(`[${TOOL_NAME}] Global services:`);
for (const service of services) {
console.log(` - ${statusDot(service.status)} ${service.name}: ${service.status}`);
const serviceLabel = service.displayName || service.name;
console.log(` - ${statusDot(service.status)} ${serviceLabel}: ${service.status}`);
}
const missingSystemTools = requiredSystemTools.filter((tool) => tool.status !== 'active');
if (missingSystemTools.length > 0) {
const tools = missingSystemTools.map((tool) => tool.name).join(', ');
const tools = missingSystemTools
.map((tool) => tool.displayName || tool.name)
.join(', ');
console.log(`[${TOOL_NAME}] ⚠️ Missing required system tool(s): ${tools}`);
for (const tool of missingSystemTools) {
const reasonText = tool.reason ? ` (${tool.reason})` : '';
Expand All @@ -2479,6 +2485,16 @@ function status(rawArgs) {

if (scanResult.errors === 0 && scanResult.warnings === 0) {
console.log(`[${TOOL_NAME}] Repo safety service: ${statusDot('active')} active.`);
} else if (scanResult.errors === 0) {
console.log(
`[${TOOL_NAME}] Repo safety service: ${statusDot('degraded')} degraded (${scanResult.warnings} warning(s)).`,
);
console.log(`[${TOOL_NAME}] Run '${TOOL_NAME} scan' to review warning details.`);
} else if (scanResult.warnings === 0) {
console.log(
`[${TOOL_NAME}] Repo safety service: ${statusDot('degraded')} degraded (${scanResult.errors} error(s)).`,
);
console.log(`[${TOOL_NAME}] Run '${TOOL_NAME} scan' for detailed findings.`);
} else {
console.log(
`[${TOOL_NAME}] Repo safety service: ${statusDot('degraded')} degraded (${scanResult.errors} error(s), ${scanResult.warnings} warning(s)).`,
Expand Down
34 changes: 34 additions & 0 deletions test/install.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,40 @@ test('default invocation runs non-mutating status output', () => {
assert.equal(fs.existsSync(path.join(repoDir, '.githooks', 'pre-commit')), false);
});

test('status prints GitHub CLI service with friendly label', () => {
const repoDir = initRepo();
const fakeGh = createFakeGhScript(`
if [[ "$1" == "--version" ]]; then
echo "gh version 9.9.9"
exit 0
fi
echo "unexpected gh args: $*" >&2
exit 1
`);

const result = runNodeWithEnv([], repoDir, {
MUSAFETY_GH_BIN: fakeGh.fakePath,
});
assert.equal(result.status, 0, result.stderr || result.stdout);
assert.match(result.stdout, /GitHub \(gh\): active/);
});

test('warning-only degraded status avoids zero-error wording and improves scan hint', () => {
const repoDir = initRepo();

let result = runNode(['setup', '--target', repoDir, '--no-global-install'], repoDir);
assert.equal(result.status, 0, result.stderr || result.stdout);

result = runCmd('git', ['config', 'core.hooksPath', '.bad-hooks'], repoDir);
assert.equal(result.status, 0, result.stderr || result.stdout);

result = runNode(['status', '--target', repoDir], repoDir);
assert.equal(result.status, 0, result.stderr || result.stdout);
assert.match(result.stdout, /Repo safety service: .*degraded \(\d+ warning\(s\)\)\./);
assert.doesNotMatch(result.stdout, /0 error\(s\),/);
assert.match(result.stdout, /Run 'guardex scan' to review warning details\./);
});

test('default invocation outside git repo reports inactive repo service', () => {
const outsideDir = fs.mkdtempSync(path.join(os.tmpdir(), 'musafety-non-repo-'));

Expand Down
Loading