Skip to content

fix: CLI setup-command/color UX and harden save-deliverable path handling#373

Closed
jeypzz wants to merge 3 commits into
KeygraphHQ:mainfrom
jeypzz:fix/cli-ux-and-deliverable-path-handling
Closed

fix: CLI setup-command/color UX and harden save-deliverable path handling#373
jeypzz wants to merge 3 commits into
KeygraphHQ:mainfrom
jeypzz:fix/cli-ux-and-deliverable-path-handling

Conversation

@jeypzz

@jeypzz jeypzz commented Jun 23, 2026

Copy link
Copy Markdown

Summary

A small batch of correctness/UX fixes found while reading through the CLI and worker code.

CLI / UX

  1. Invalid command in config error — the invalid-config error path told users to run shn setup, but the published binary is shannon (see apps/cli/package.json bin); there is no shn command. It now matches the sibling parse-error message in the same file (npx @keygraph/shannon setup).

  2. Splash ignored NO_COLOR / non-TTYdisplaySplash always emitted raw ANSI color codes, so escape sequences leaked into piped/redirected output and the NO_COLOR convention was ignored. Color is now gated behind a shouldUseColor() check (NO_COLOR disables, FORCE_COLOR forces, otherwise TTY-only). The box-drawing glyphs are unaffected, so the logo still renders in monochrome.

Worker

  1. Broken path-traversal guard in save-deliverable — the check used resolved.startsWith(${cwd}/) with a hardcoded / separator and a brittle string-prefix match. On Windows resolve() returns backslash paths, so legitimate paths were rejected as traversal attempts, and the prefix match could false-trigger on sibling directories. Replaced with a path.relative()-based check (separator-correct, no prefix aliasing).

  2. Duplicated path logic — the same script rebuilt the deliverables directory inline with the same subdir.split('/') logic and a hardcoded default string that already lives in deliverablesDir() / DEFAULT_DELIVERABLES_SUBDIR in paths.ts (used by every other call site). It now reuses the shared helper, which also removes a local variable that shadowed it.

Testing

  • tsc --noEmit passes for both packages (turbo run check).
  • biome lint is clean on all changed files.
  • The new traversal logic was verified against inside / parent / absolute path cases.

jeypzz added 3 commits June 23, 2026 09:03
The invalid-config error path told users to run 'shn setup', but the
published binary is 'shannon' (see apps/cli/package.json `bin`) — there
is no 'shn' command. Match the sibling parse-error message in the same
file, which already uses 'npx @keygraph/shannon setup'.
displaySplash always emitted raw ANSI color codes, so the escape
sequences leaked into piped/redirected output and ignored the NO_COLOR
convention (https://no-color.org). Gate the color codes behind a
shouldUseColor() check: NO_COLOR disables color, FORCE_COLOR forces it,
otherwise color is only emitted to an interactive TTY. The box-drawing
glyphs are unaffected, so the logo still renders in monochrome.
Two related path-handling issues in the save-deliverable script:

1. Traversal guard: the check used `resolved.startsWith(`${cwd}/`)` with
   a hardcoded '/' separator and a brittle string-prefix match. On
   Windows resolve() returns backslash paths, so every legitimate path
   was rejected as a traversal attempt; the prefix match could also
   false-trigger on sibling directories. Replace it with a
   path.relative() based check (separator-correct, no prefix aliasing).

2. Deduplicate: the deliverables directory was rebuilt inline with the
   same `subdir.split('/')` logic — and hardcoded default string — that
   already lives in deliverablesDir()/DEFAULT_DELIVERABLES_SUBDIR in
   paths.ts (used by every other call site). Reuse the shared helper,
   which also removes the confusing local variable that shadowed it.
@ezl-keygraph

Copy link
Copy Markdown
Collaborator

Hi @jeypzz, thanks for reporting these.

Both CLI/UX fixes have since been resolved independently:

On save-deliverable: we are planning to remove it in an upcoming update.

Closing this out, appreciate the work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants