Skip to content

feat(cli): add read-only agent-init status subcommand#74

Open
Lillevang wants to merge 3 commits into
mainfrom
feat/cli-status-subcommand
Open

feat(cli): add read-only agent-init status subcommand#74
Lillevang wants to merge 3 commits into
mainfrom
feat/cli-status-subcommand

Conversation

@Lillevang

Copy link
Copy Markdown
Owner

Summary

  • Adds agent-init status [target] — read-only reporter that prints the scaffold's current visibility mode (shared, local, hidden, or shadowed-by-global), the absolute path of the file carrying the agent-init ignore block, and the exact sed undo command. For shadowed-by-global it also prints the force-add hint explaining why files may still be tracked.
  • Detection follows git's ignore precedence (.gitignore > .git/info/exclude > core.excludesfile) and reports the most-local carrier. Writes nothing; touches no git config.
  • Reuses the marker constants and path helpers from internal/gitignore rather than duplicating them. gitignore gains HasBlock and exports MarkerStart/MarkerEnd so the detector and the undo hint stay byte-for-byte in sync with the writers.
  • Wired into the help table in internal/cli/cli.go; TestHelpFlagsMatchDocs, the top-level help test, and the flagless-subcommand help test are updated to include status. Docs added under docs/cli.md; README subcommand list updated.

Closes #60.

Acceptance criterion calls

  • Mode names: used shared, local, hidden, shadowed-by-global verbatim from the issue.
  • Precedence when block exists in multiple files: report the most-local hit (.gitignore > .git/info/exclude > global). shadowed-by-global only fires when neither repo-local file carries the block but the global one does — the state where the scaffold is committed openly here yet ignored everywhere else.
  • Undo command: portable sed -i.bak invocation that works on both GNU and BSD sed, plus a note about the .bak leftover and a manual-edit fallback. Markers come from gitignore.MarkerStart / MarkerEnd.
  • Detection is marker-based, not effective-behavior: documented explicitly under docs/cli.md "Behavior". A user who manually negates a rule below the block still sees local/hidden/shadowed-by-global.
  • No flags: rejects unknown flags (status --no-such-flag errors instead of silently treating the flag as a target path).

Test plan

  • ./.agent/scripts/check.sh passes (codemap, fmt, lint, lint-shell, mod-tidy, typecheck, test, cross-build, smoke-test).
  • just smoke-test passes (no template changes, but verified — no-op).
  • New unit tests in internal/cli/status_test.go cover: shared, local, hidden, shadowed-by-global, multi-carrier precedence, default target (cwd), explicit target canonicalization, extra-positional rejection, unknown-flag rejection, three help triggers, and graceful degradation when HOME is unreadable. Read-only is asserted via on-disk snapshots taken before and after the run.
  • New gitignore tests cover HasBlock (six edge cases) and a drift guard linking MarkerStart/MarkerEnd to the internal constants.
  • Manual smoke: scaffolded a local and a hidden project and ran status against both; output matches the documented format.

🤖 Generated with Claude Code

Lillevang and others added 2 commits June 21, 2026 10:03
`status [target]` reports the scaffold's current visibility (shared / local
/ hidden / shadowed-by-global), the absolute path of the file carrying the
agent-init ignore block, and the exact sed undo command. When the scaffold
is committed locally but a global-default ignore exists, the report
includes the force-add hint explaining why files may still be tracked.

Detection follows git's ignore precedence (.gitignore > .git/info/exclude
> core.excludesfile) and reports the most-local carrier. The subcommand is
strictly read-only — no files and no git config are mutated. `gitignore`
gains `HasBlock` and exports `MarkerStart` / `MarkerEnd` so the detector
and the undo hint reuse the same markers the writers do.

Closes #60

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Reject unknown flags loudly: `status --no-such-flag` now errors instead
  of silently resolving the flag string to an absolute target path.
- Documented that detection is marker-based (not effective-behavior),
  and that `git config --global --get core.excludesfile` is invoked to
  locate the machine-wide excludes file.
- Print a note that `sed -i.bak` leaves a one-shot backup file.
- Rephrase the shadowed-by-global note so "git ignores rules" no longer
  garden-paths as "git ignores-the-rules".
- Switch the default-target test to `t.Chdir` (Go 1.24+); it auto-restores
  and refuses `t.Parallel`, removing a latent race.
- Justify detectStatus's slight overrun of the ~40-line guideline inline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the hand-rolled strings.HasPrefix check with a.newFlagSet, matching
how init and add-tracker handle unknown flags. Drops the dedicated
TestStatusRejectsUnknownFlag test — unknown-flag rejection is a property of
the shared FlagSet, not of status specifically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Lillevang

Copy link
Copy Markdown
Owner Author

LOWinternal/cli/status.go:165 (writeStatusReport): the carrier path is printed unquoted into the suggested sed -i.bak '/.../,/.../d' <path> undo command. The path is derived from the positional target arg (or, in shadowed mode, from git config --global core.excludesfile). A target like '; echo pwned; # would render an undo line that, if pasted into a shell, runs the injected command. Blast radius is bounded — the user controls both the arg and the paste — but the line is presented as a copy-paste recipe, which earns it a hardening note.

Fix: render the path with %q (or strconv.Quote) so the printed command is sed -i.bak '/.../,/.../d' "<path>" and metacharacters are inert when pasted. Apply the same to the two trailing "or open ..." lines below.

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.

feat(cli): add read-only agent-init status subcommand for scaffold visibility

1 participant