feat(cli+docs): colorize --help output + workspace view spec
Some checks failed
CI / Lint (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled

Help text was a wall of monochrome ASCII. Now section headers print
bold-clay, the program title is brand-orange, each verb's syntax is
tinted cyan, and `(alias: ...)` parentheticals are dimmed so they
read as secondary metadata. The styles helper already gates on TTY +
NO_COLOR, so non-interactive output stays unchanged.

Adds .artifacts/specs/2026-05-02-workspace-view.md — the v0.4.0
spec for a per-user virtual workspace that aggregates reads across
all joined meshes while keeping writes mesh-scoped. Roadmap entry
added under v0.3.0.
This commit is contained in:
Alejandro Gutiérrez
2026-05-02 22:28:46 +01:00
parent 8697c1c032
commit 82ee89d0dc
3 changed files with 267 additions and 1 deletions

View File

@@ -9,6 +9,7 @@ import { renderVersion } from "~/cli/output/version.js";
import { isInviteUrl, normaliseInviteUrl } from "~/utils/url.js";
import { classifyInvocation } from "~/cli/policy-classify.js";
import { gate, type ApprovalMode } from "~/services/policy/index.js";
import { bold, clay, cyan, dim, orange } from "~/ui/styles.js";
installSignalHandlers();
installErrorHandlers();
@@ -192,8 +193,59 @@ Flags
-q, --quiet suppress non-essential output
`;
/**
* Apply color treatment to the HELP block for terminal readability.
*
* Strategy is line-based and intentionally conservative:
* - Section header lines (the title-case categories like `Mesh`,
* `Topic`, `Auth`, `USAGE`) get bold + accent.
* - Each verb row (` claudemesh <verb> ...`) gets the command tinted
* cyan up to the second whitespace gap (separating the syntax from
* the description), and any trailing `(alias: ...)` parenthetical
* dimmed so it reads as secondary metadata.
* - The header (program name + version) gets the brand orange.
*
* Falls through to plain output when stdout is not a TTY or NO_COLOR
* is set — the underlying style helpers already gate on that.
*/
function colorizeHelp(raw: string): string {
const lines = raw.split("\n");
const SECTION_HEADER_RE = /^([A-Z][A-Za-z0-9 /+-]*?)(\s*\(.*\))?$/;
const VERB_ROW_RE = /^(\s{2})(claudemesh[^\s]*(?:\s+[^\s]+)*?)(\s{2,})(.*)$/;
const ALIAS_RE = /(\(alias[^)]*\))/g;
const out: string[] = [];
for (const line of lines) {
if (line.startsWith("claudemesh —")) {
out.push(orange(line));
continue;
}
if (line.trim() === "") {
out.push(line);
continue;
}
// Section header: a line with no leading spaces that isn't a verb.
if (!line.startsWith(" ") && SECTION_HEADER_RE.test(line)) {
const m = line.match(SECTION_HEADER_RE)!;
const head = bold(clay(m[1]!));
const meta = m[2] ? dim(m[2]) : "";
out.push(head + meta);
continue;
}
// Verb row: tint the syntax, dim the alias parenthetical.
const verbMatch = line.match(VERB_ROW_RE);
if (verbMatch) {
const [, indent, syntax, gap, rest] = verbMatch;
const dimmedRest = rest!.replace(ALIAS_RE, (m) => dim(m));
out.push(`${indent}${cyan(syntax!)}${gap}${dimmedRest}`);
continue;
}
out.push(line);
}
return out.join("\n");
}
async function main(): Promise<void> {
if (flags.help || flags.h) { console.log(HELP); process.exit(EXIT.SUCCESS); }
if (flags.help || flags.h) { console.log(colorizeHelp(HELP)); process.exit(EXIT.SUCCESS); }
if (flags.version || flags.V) { console.log(renderVersion()); process.exit(EXIT.SUCCESS); }
// Policy gate — runs before any broker-touching command. Skipped for help,