skillhub/docs/superpowers/plans/2026-07-28-cli-namespace-errors.md
XiaoSeS a9007a4e8c fix(cli): preserve download error contract (#606)
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-07-29 10:31:49 +08:00

11 KiB

CLI Namespace Errors Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Make every documented namespace coordinate reach the correct registry path and preserve public server error messages and request IDs without misclassifying all 403 responses as token-scope failures.

Architecture: Extend the shared coordinate parser with a resolver that owns explicit namespace conflict handling, then make install/remove consume it while removing the argument parser's early global default. Add one response-error converter inside SkillHubClient so JSON endpoints and downloads share safe msg/requestId extraction while retaining status-based exit codes.

Tech Stack: TypeScript, Bun test/build, cac, npm package tarballs.

Completion record

Completed in PR #608 and revalidated after merging origin/main on 2026-07-29. The checklist below reflects the delivered implementation. The maintainer revalidation did not recreate historical RED states; it reran the current GREEN gates with the repository-pinned Bun 1.3.13:

  • Focused namespace/error/help regression: 142 tests passed.
  • Complete CLI regression: 378 tests passed with bun test --max-concurrency=1 (peak RSS 152128 KiB).
  • Typecheck, lint, and build passed.
  • The packed @astron-team/skillhub@0.1.9 artifact contained dist/index.js, README.md, CHANGELOG.md, LICENSE, and package.json.
  • Packed Node artifact smoke passed for version, help install, all three namespaced coordinate forms, coordinate/--namespace conflict handling, and structured 403 message/request-ID rendering.
  • The Chinese and English VitePress documentation build passed.

Task 1: Establish release artifact baseline

Files:

  • Inspect: cli/package.json

  • Inspect: npm package @astron-team/skillhub@0.1.9

  • Step 1: Read published metadata and download the package

Run:

npm view @astron-team/skillhub@0.1.9 version dist.tarball dist.integrity --json
npm pack @astron-team/skillhub@0.1.9 --pack-destination /tmp/skillhub-npm-019-issue-606 --json

Expected: version 0.1.9, a tarball with dist/index.js, README.md, LICENSE, and package.json.

  • Step 2: Confirm the published bundle contains both bug signatures

Run:

tar -xOf /tmp/skillhub-npm-019-issue-606/astron-team-skillhub-0.1.9.tgz package/dist/index.js | rg 'indexOf\("--"\)|token may lack required scope'

Expected: both patterns are present, proving 0.1.9 includes the double-dash parser but also the misleading 403 fallback.

Task 2: Normalize coordinates and reject conflicts

Files:

  • Modify: cli/test/unit/shared/skill-name-parser.test.ts

  • Modify: cli/src/shared/skill-name-parser.ts

  • Step 1: Replace permissive edge tests with the public coordinate matrix

Add table-driven assertions for my-skill, team/my-skill, @team/my-skill, and team--my-skill. Add resolver assertions for an explicit namespace on a bare slug, a matching coordinate namespace, and a conflicting namespace. Add malformed-input assertions for empty or incomplete coordinates.

  • Step 2: Run the parser test and verify RED

Run:

cd cli && bun test test/unit/shared/skill-name-parser.test.ts

Expected: failures for slash forms, malformed input, and the missing resolver.

  • Step 3: Implement the minimal parser and resolver

Keep ParsedSkillName unchanged. Add resolveSkillName(skillName, explicitNamespace?) returning ParsedSkillName. It calls one internal parser, applies global only to bare slugs, accepts a matching explicit namespace, and throws CliError(..., EXIT.usage) on malformed input or conflict.

  • Step 4: Run the parser test and verify GREEN

Run:

cd cli && bun test test/unit/shared/skill-name-parser.test.ts

Expected: all parser tests pass with no warnings.

Task 3: Wire the resolver through real CLI parsing

Files:

  • Modify: cli/src/commands/install.ts

  • Modify: cli/src/commands/remove.ts

  • Modify: cli/src/index.ts

  • Modify: cli/test/unit/commands/install-command.test.ts

  • Modify: cli/test/integration/install-command.test.ts

  • Step 1: Add failing command and integration tests

Capture installSkill options in the unit test and assert a namespaced coordinate passes namespace: 'team' and slug: 'my-skill'. In the integration test, register a team/my-skill fixture and execute:

skillhub install @team/my-skill --dir <temp> --registry <fake> --token sk_ok --json

Assert exit 0, JSON namespace team, and fake-registry resolve state { namespace: 'team', slug: 'my-skill' }. Add a conflicting --namespace other case that exits with usage code 5 before registry access.

  • Step 2: Run the focused command tests and verify RED

Run:

cd cli && bun test test/unit/commands/install-command.test.ts test/integration/install-command.test.ts

Expected: the namespaced integration case resolves global or fails, and the conflict case does not produce the expected usage error.

  • Step 3: Use resolveSkillName and remove the cac default

Change install/remove to call:

const { namespace, slug } = resolveSkillName(skillNameArg, options.namespace)

Change install's option declaration to:

.option('--namespace <slug>', 'Namespace for a bare skill slug')
  • Step 4: Run the focused command tests and verify GREEN

Run the same Bun test command. Expected: all focused command tests pass.

Task 4: Preserve structured API errors and request IDs

Files:

  • Modify: cli/test/unit/clients/skillhub-client.test.ts

  • Modify: cli/test/unit/shared/output.test.ts

  • Modify: cli/src/clients/skillhub-client.ts

  • Modify: cli/src/shared/output.ts

  • Step 1: Add failing response and output tests

Add client tests for:

Response.json(
  { code: 403, msg: 'token has been revoked', requestId: 'req-403' },
  { status: 403 }
)

Assert message token has been revoked, auth exit code, and details containing requestId: 'req-403'. Add 403 tests without msg, with invalid JSON, and a 404 with structured fields. Add a download 403 structured-response test. Add a human output assertion for Request ID: req-403.

  • Step 2: Run focused tests and verify RED

Run:

cd cli && bun test test/unit/clients/skillhub-client.test.ts test/unit/shared/output.test.ts

Expected: structured messages/request IDs are discarded and human output omits the request ID.

  • Step 3: Implement one safe response-error converter

Inside SkillHubClient, add a private method that reads non-success bodies once, parses only object-shaped JSON, accepts only non-empty string msg and requestId, selects status-specific fallback text and exit codes, and returns a CliError. Use it from both handleJsonResponse and download. Do not add the old token-scope hint to 403 errors. Update renderError with:

if (typeof cliError.details.requestId === 'string') {
  lines.push(`Request ID: ${cliError.details.requestId}`)
}
  • Step 4: Run focused tests and verify GREEN

Run the same focused Bun test command. Expected: all client/output tests pass.

Task 5: Document the public contract and release impact

Files:

  • Modify: cli/src/commands/help.ts

  • Modify: cli/README.md

  • Create: cli/CHANGELOG.md

  • Modify: cli/package.json

  • Modify: cli/test/integration/help-command.test.ts

  • Step 1: Add a failing help assertion

Assert skillhub help install includes @team/my-skill, team/my-skill, and team--my-skill examples.

  • Step 2: Run the help test and verify RED

Run:

cd cli && bun test test/integration/help-command.test.ts

Expected: the coordinate examples are absent.

  • Step 3: Update help, README, and release notes

Use <coordinate> in install usage. Document all accepted forms and the same-namespace/conflict rule. Add an Unreleased changelog entry covering coordinate normalization and structured 403 messages/request IDs. Include CHANGELOG.md in the npm package files list.

  • Step 4: Run the help test and verify GREEN

Run the same Bun test command. Expected: all help tests pass.

Task 6: Verify source, build, and packed artifact

Files:

  • Verify: all files changed by Tasks 2-5

  • Produce locally: cli/dist/index.js

  • Produce locally: npm tarball under /tmp

  • Step 1: Run the complete CLI quality gate

Run:

cd cli && bun test
cd cli && bun run typecheck
cd cli && bun run lint
cd cli && bun run build

Expected: every command exits 0 with no errors or warnings.

  • Step 2: Pack and inspect the candidate artifact

Run:

cd cli && npm pack --pack-destination /tmp/skillhub-cli-issue-606 --json
tar -tf /tmp/skillhub-cli-issue-606/astron-team-skillhub-0.1.9.tgz

Expected: the package contains the built executable, README, changelog, license, and package metadata.

  • Step 3: Run packed-bundle smoke checks

Extract the tarball to a temporary directory and run the built executable's version and help install commands. Expected: version reports 0.1.9 and help shows every coordinate form. Run the relevant unit/integration suites against source to verify request paths and structured errors.

  • Step 4: Review the diff and commit

Run:

git diff --check
git status --short
git diff --stat

Expected: only CLI implementation/tests/docs and the two planning documents are changed; generated cli/dist/index.js and tarballs are not committed.

Commit with a conventional message containing the issue ID:

git commit -m "fix(cli): normalize namespace coordinates and errors (#606)"

Task 7: Review and create the single final PR

Files:

  • Review: committed diff against origin/main

  • Step 1: Run tester and reviewer gates

The tester must confirm focused and full CLI gates plus package smoke evidence. The reviewer must inspect coordinate compatibility, error disclosure, test coverage, docs, commit metadata, and absence of unrelated changes. Resolve all blocking findings before continuing.

  • Step 2: Push only the assigned branch

Run:

git push -u origin fix/cli-namespace-errors

Expected: only the assigned branch is created or updated remotely.

  • Step 3: Create one PR linked to the issue

Create one PR titled fix(cli): normalize namespace coordinates and errors with Related to #606 in the body, complete test/package evidence, docs and risk sections, and no close intent unless the project manager requests it. Do not merge the PR.