From 1bdadbcd1f73eb0c205dbd3c36bdebb8e60b2ae9 Mon Sep 17 00:00:00 2001 From: NagyVikt Date: Mon, 13 Apr 2026 17:35:53 +0200 Subject: [PATCH] Improve status clarity for GitHub dependency and warning-only degraded repos Status output now names the GitHub CLI dependency explicitly as GitHub (gh), and warning-only degraded states no longer print a confusing 0 error(s), N warning(s) tuple. The degraded hint is also tuned for warning-only states while preserving the existing detailed-findings hint for error cases. Constraint: Keep status output compatible with existing command flow and JSON payload shape Rejected: Renaming internal service key from gh to github | would ripple through integrations without user benefit Confidence: high Scope-risk: narrow Reversibility: clean Directive: If status wording is changed again, keep warning-only and error-containing degraded paths distinct Tested: npm test Tested: node --check bin/multiagent-safety.js Tested: node bin/multiagent-safety.js status --target /home/deadpool/Documents/multiagent-safety --- bin/multiagent-safety.js | 20 ++++++++++++++++++-- test/install.test.js | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/bin/multiagent-safety.js b/bin/multiagent-safety.js index 50d27fa..6dc9c00 100755 --- a/bin/multiagent-safety.js +++ b/bin/multiagent-safety.js @@ -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/', }, @@ -2052,6 +2053,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', @@ -2404,6 +2406,7 @@ function status(rawArgs) { ...npmServices, ...requiredSystemTools.map((tool) => ({ name: tool.name, + displayName: tool.displayName || tool.name, status: tool.status, })), ]; @@ -2452,11 +2455,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})` : ''; @@ -2474,6 +2480,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)).`, diff --git a/test/install.test.js b/test/install.test.js index bcd65c1..43e1a35 100644 --- a/test/install.test.js +++ b/test/install.test.js @@ -765,6 +765,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-'));