Skip to content

[Hackathon] fix(test): the documented --out ./.testsprite/… bundle commands exit 5 in a fresh project, including the verify skill's step 5 #654

Open

Description

@naufalfx805-source

Verified against (commit SHA or released version)

commit a18d37c (v0.15.0; testsprite --version → 0.15.0), built from source. Reproduced on Linux (WSL2, Node 24) on 2026-10-23.

Discord Username / User ID

npall_805

What does this improvement do?

The failure-bundle commands that the shipped agent skill and the README tell you to run are refused with exit 5 the first time they run in a project, before any request is sent, because ./.testsprite/ doesn't exist yet:

Where Command In a project with no .testsprite/ folder
Verify skill, step "5. On failure → download the artifact" (skill.md#L543, codex.md#L99). agent install writes it for all 8 targets: claude, cursor, cline, antigravity, kiro, windsurf, copilot, and the codex section of AGENTS.md testsprite test artifact get <run-id> --out ./.testsprite/runs/<run-id>/ exit 5: parent directory does not exist: …/.testsprite/runs
README loop, step 2 (README.md#L87), and "The complete agent loop" (DOCUMENTATION.md#L122) testsprite test failure get <test-id> --out ./.testsprite/failure exit 5: parent directory does not exist: …/.testsprite
Command reference (DOCUMENTATION.md#L334, #L976) --out ./.testsprite/failure/<test-id>, --out ./.testsprite/runs/<run-id> exit 5, same reason

Nothing in the CLI creates a project's .testsprite/ except test artifact get without --out, and that default is exactly the directory the skill spells out. So the same directory is created when it is implied and refused when it is named:

testsprite test artifact get run_abc                                    # default ./.testsprite/runs/run_abc/: created, proceeds
testsprite test artifact get run_abc --out ./.testsprite/runs/run_abc/  # the verify skill's command: exit 5

Who hits it: every coding agent that follows the verify skill, on the first failed run it investigates in a repo (.testsprite/runs/ only appears after a default-path artifact get), and anyone following the README loop. Under --output json the agent gets a VALIDATION_ERROR envelope instead of the bundle, and has to work out that it should mkdir -p and retry.

Reproduction. Offline: the refusal happens before any request, and the dummy key only lets the client be built.

npm ci && npm run build                     # in a checkout of a18d37c
cd "$(mktemp -d)" && git init -q
export TESTSPRITE_API_KEY=sk-user-dummy
node <checkout>/dist/index.js test artifact get run_abc --out ./.testsprite/runs/run_abc/; echo "exit $?"
node <checkout>/dist/index.js test failure get test_abc --out ./.testsprite/failure; echo "exit $?"
Error: Invalid request.
Flag `--out` is invalid: parent directory does not exist: …/.testsprite/runs.
exit 5
Error: Invalid request.
Flag `--out` is invalid: parent directory does not exist: …/.testsprite.
exit 5

Expected: an --out inside the project's own .testsprite/ folder behaves like the default. Missing parents are created and the bundle is written.

Cause: assertOutDirParentExists requires the parent of --out to exist before the fetch (test artifact get --help: "Parent must exist"). The writer has no such limit: writeBundle runs mkdir(dir, { recursive: true }) once the response passes its integrity checks, which is how the default path gets created. So only the pre-check is in the way, and the commands in the docs and the skill don't satisfy it.

Details / implementation notes

Proposed fix: keep the guard, since it catches a mistyped --out before anything is sent, but scope it.

  • In assertOutDirParentExists, when the resolved --out lies inside <cwd>/.testsprite/, require only that the closest existing ancestor is a directory. writeBundle creates the rest, exactly as it does for the default. Every other path is checked as today, so --out ./typo/bundle still exits 5 and creates nothing.
  • That function serves both test failure get and test artifact get, so both commands are fixed, and failure get --dry-run --out ./.testsprite/… stops refusing too.
  • The --out help of both commands says "Parent must exist, except under ./.testsprite/, which is created as needed." Today test failure get --help doesn't mention the rule at all.
  • No docs or skill text has to change, and skills already installed in users' repos start working as soon as the CLI is upgraded.

Tests:

  • In a fresh temp project, the skill's exact spelling (./.testsprite/runs/<run-id>/, trailing slash included) and the README's ./.testsprite/failure both write a bundle.
  • A missing parent outside .testsprite/ is still refused (testsprite/…, .testsprite-old/…, .testsprite/../elsewhere/…).
  • A .testsprite file in the way is reported as "not a directory".
  • The pre-check itself creates nothing.

I have this ready on a branch.

  • The 4 new tests fail on a18d37c and pass with the change.
  • On Linux, the full suite (4,803 tests) and the coverage gate pass.
  • On Windows (Node 24), the spec and the help snapshots pass.

I'll open the PR as soon as this is accepted.

Not included: test scaffold --help's own example, --out tests/health.py, hits the same rule in a repo without tests/. That one is a single-file --out with its own semantics, so I can file it separately if you want it.

Confirmations

  • I have searched existing issues and this is not a duplicate.
  • I have provided my Discord identity above for reward coordination.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions