feat(cli): restructure run folder and improve terminal UX (#384)

* feat: surface report at run root and nest run internals under .shannon

* feat: use plain-language wording in user-facing terminal messages

* feat(cli): guide users to watch scan progress and surface report path on start

* docs: sync run-folder layout and CLI wording across docs and comments

* feat(cli): add version command reporting package version or git SHA

* feat(cli): detect TTY for interactive prompts, color, and progress output

* docs: document --yes flag, version command, and tty module

* fix(cli): FORCE_COLOR precedence and plain uninstall --yes output

* fix(cli): respect empty NO_COLOR

* fix(cli): let NO_COLOR take precedence over FORCE_COLOR

* docs: mark claude-code-router integration as removed
This commit is contained in:
ezl-keygraph
2026-07-04 21:14:04 +05:30
committed by GitHub
parent 5a2f78c5d9
commit 00e56455df
27 changed files with 445 additions and 172 deletions
+13 -26
View File
@@ -9,9 +9,6 @@
* in the current working directory.
*/
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { build } from './commands/build.js';
import { logs } from './commands/logs.js';
import { setup } from './commands/setup.js';
@@ -21,9 +18,7 @@ import { stop } from './commands/stop.js';
import { uninstall } from './commands/uninstall.js';
import { workspaces } from './commands/workspaces.js';
import { getMode } from './mode.js';
import { displaySplash } from './splash.js';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
import { getVersion, getVersionLine } from './version.js';
function blockSudo(): void {
const isSudo = !!process.env.SUDO_USER;
@@ -44,16 +39,6 @@ function blockSudo(): void {
process.exit(1);
}
function getVersion(): string {
try {
const pkgPath = path.join(__dirname, '..', 'package.json');
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as { version?: string };
return pkg.version || '1.0.0';
} catch {
return '1.0.0';
}
}
function showHelp(): void {
const mode = getMode();
const prefix = mode === 'local' ? './shannon' : 'npx @keygraph/shannon';
@@ -68,17 +53,17 @@ Usage:${
${prefix} setup Configure credentials`
}
${prefix} start --url <url> --repo <path> [options] Start a pentest scan
${prefix} stop [--clean] Stop all containers
${prefix} stop [--clean] [--yes] Stop all running scans
${prefix} workspaces List all workspaces
${prefix} logs <workspace> Tail workflow log
${prefix} status Show running workers${
${prefix} logs <workspace> Show a scan's live log
${prefix} status Show running scans${
mode === 'local'
? `
${prefix} build [--no-cache] Build worker image`
: `
${prefix} uninstall Remove ~/.shannon/ and all data`
${prefix} uninstall [--yes] Remove ~/.shannon/ and all data`
}
${prefix} info Show splash screen
${prefix} version Show version
${prefix} help Show this help
Options for 'start':
@@ -102,7 +87,7 @@ State directory: ./workspaces/`
: `
State directory: ~/.shannon/`
}
Monitor workflows at http://localhost:8233
Monitor scans at http://localhost:8233
`);
}
@@ -209,7 +194,7 @@ switch (command) {
break;
}
case 'stop':
stop(args.includes('--clean'));
stop(args.includes('--clean'), args.includes('--yes') || args.includes('-y'));
break;
case 'logs': {
const workspaceId = args[1];
@@ -242,10 +227,12 @@ switch (command) {
console.error('ERROR: uninstall is only available in npx mode.');
process.exit(1);
}
uninstall();
uninstall(args.includes('--yes') || args.includes('-y'));
break;
case 'info':
displaySplash(getMode() === 'local' ? undefined : getVersion());
case 'version':
case '--version':
case '-v':
console.log(getVersionLine());
break;
case 'help':
case '--help':