Repository navigation
fix(cli): close HACK-1426 follow-ups (up E_PROJECT_NOT_FOUND, git-accurate gitignore entry, no-TTY Tailscale test) - #479
Merged
Conversation
…urate gitignore entry, no-TTY Tailscale test) - `hack up` without a project now prints the closed `E_PROJECT_NOT_FOUND: ...` line like down, restart, ps, logs and open. - ensureGitignoreEntry reads each line as git does (trailing CR and spaces dropped, leading whitespace kept), so an indented `.hack.secret.key` no longer counts as the entry and is no longer refused as "re-included"; the exact entry is appended instead. - tests: no-TTY guard test for "Turn on Tailscale?", a named warm-up for the cold transpiler cache in that file, the ACL test's setup moved inside its try, and the paired mode-000 `.hack` fixture without `.hack/.internal` restored. Refs HACK-1426 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The six small CLI follow-ups in HACK-1426, from the verifiers of #466, #441, #453, #460 and #462.
Root cause
canPrompt()guard in front of "Turn on Tailscale?" insetupTailscale(src/commands/ssh.ts) had no case intests/no-tty-prompt-sites-cli.test.ts. If you changed it toif (false), every ssh case still passed.~/Library/Caches/bun/@t@on macOS), so the first spawn started cold inside its 10 s kill bound. On a loaded host that first case took 6.3 s and was SIGKILLed.hack updropped the error code. For a missing project,runUpCommandcaughtMissingProjectContextErrorand, without--json, logged only its message.down,restart,ps,logsandopenlet the error reach the CLI's closed-error renderer, which printsE_PROJECT_NOT_FOUND: .....gitignoreentry counted as present.ensureGitignoreEntry(src/lib/fs.ts) compared trimmed lines. Git keeps leading whitespace as part of the pattern, so.hack.secret.keydoes not ignore the key. Hack counted that line as the entry, wrote nothing, then found the key not ignored. It then refused with the "a later rule re-includes the key" message, which names the wrong cause.tests/git-info-exclude.test.ts, the macOS ACL test ranchmod 0444, the ACL grant andaccess(W_OK)before thetrywhosefinallyrestores mode 0644. If any of those steps failed, the file kept mode 0444.unsearchablefixture a.hack/.internaldirectory. After that, nothing covered a.hackat mode 000 with no.hack/.internal, which is the most common real layout.Fix
ssh --tailscaleruns against a loggingtailscalestand-in placed first on PATH. The stand-in reports{"BackendState":"Stopped"}. The case expects exit 1, theRun \tailscale up`, then re-run `hack ssh`.hint, no prompt, and notailscale up` call.beforeAllnow runs one warm-up child (index.ts --help) under the file's private HOME. It has its own named budget:WARM_UP_KILL_AFTER_MS= 90 s, and the hook bound is that plus 10 s. A kill fails the file with a clear message. The cases keep the 10 s bound.runUpCommandnow handlesMissingProjectContextErroritself only under--json. Without--jsonit rethrows, sohack upprintsERROR: E_PROJECT_NOT_FOUND: No .hack/ (or legacy .dev/) found. Run: hack init(console logger), the same as the other lifecycle commands.docs/cli.mdalready promised this.ensureGitignoreEntrynow reads each line the way git does: it drops a trailing CR and trailing spaces, and keeps leading whitespace. An indented line no longer counts as the entry, so Hack appends the exact entry, git ignores the key, and the secret write goes ahead. The "re-included" refusal now appears only when the exact entry is present and git still does not ignore the key, which is what its message says. Tabs are not trimmed, which matches git'strim_trailing_spaces.accessprobe now run inside thetry.unsearchable-no-internalfixture (never adopted, no.hack/.internal). Its.hackat mode 000 is the first case in the paired CLI/MCP loop. The proof-matrix row indocs/reference/ax-target-result-contract.mdnow names this case.Tests and mutation evidence
For each mutation I applied it, ran the focused tests, and restored the file.
if (!canPrompt())changed toif (false)insetupTailscale: the new case fails. The child was SIGKILLed at the 10 s bound with the prompt open. The other 3 ssh cases pass. The stand-in recorded noupcall.up's non-JSON branch reverted: 2 tests fail,up -p <empty dir> without --json …andup from a working directory without a project …. The same new loop overdown,restart,ps,logsandopenstill passes.line.trim() === entryLinerestored inensureGitignoreEntry: 2 tests fail, the CLI case "an indented entry … is completed by an exact entry instead of being refused as re-included" and the unit case "ensureGitignoreEntry reads each line as git does …".line === entryLine: the unit case fails on the trailing-space and CRLF inputs.permissionin the adoption marker'sclassifyStateRootFailure: the paired loop fails on its first case,unsearchable-no-internalwith.hackat 000. It getsadoption_state_unsafe/E_CONFIG_INVALIDwhereinput_permission_denied/E_PERMISSIONis expected.Validation
no-tty-prompt-sites-cli,missing-project-error-code,project-env-key-ignore,project-target-inspect,git-info-exclude,doctor-generated-files), 121 pass and 0 fail.project-up-commandalso passes. Runs used a private HOME, HACK_HOME and DOCKER_CONFIG, andHACK_SECRETS_DISABLE_KEYCHAIN_FALLBACK=1, as a non-root user on macOS.bun run --cwd packages/cli typecheck: 0 errors.bun run check:privacy-check: ok.@hack/cli:checkshows the 34 warnings that were already there. Biome finds no issues in the changed files.bun run docs:cli-reference: no diff. Only an error line changed, not the CLI surface. No consumer agent guidance changed.gitleaks diron the exportedgit log -p origin/next..HEAD): no leaks found.testjob (all shards) at this PR head.Gaps
.internalcase apart from the.hack000 case with.internal. Both get EACCES from the same state-rootlstat. The new case is live (it fails first under the classifier mutation) but not independent.tests/native-compose-adoption-search-depth.test.ts"a pending adoption more than 64 directories above …" fails in its setup withE_LEGACY_ADOPTION_DEADLINE. It fails the same way withorigin/next'ssrc/, so this change did not cause it. Hosted CI decides.Refs HACK-1426
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.