diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md index a4670ff..af3e3ba 100644 --- a/.specify/memory/constitution.md +++ b/.specify/memory/constitution.md @@ -1,50 +1,90 @@ -# [PROJECT_NAME] Constitution - + + +# Renamer CLI Constitution ## Core Principles -### [PRINCIPLE_1_NAME] - -[PRINCIPLE_1_DESCRIPTION] - +### Preview-First Safety +Renamer MUST present a deterministic preview of every pending rename (files and directories) before +applying changes. Users MUST explicitly confirm the preview or abort; unattended destructive modes +are prohibited. The preview MUST surface conflicts and skipped items so the final rename plan +matches user intent. **Rationale:** Safeguarding rename operations prevents accidental data loss and +builds trust in the tool. -### [PRINCIPLE_2_NAME] - -[PRINCIPLE_2_DESCRIPTION] - +### Persistent Undo Ledger +Every confirmed rename batch MUST append an entry to the `.renamer` ledger in the working +directory, capturing original paths, new paths, applied rules, and timestamps. The CLI MUST expose +an undo command that replays the last ledger entry in reverse and refuses to proceed if the ledger +is inconsistent or missing. Ledger writes MUST be atomic to guarantee reversibility. **Rationale:** +An auditable history is essential for recovering from mistakes and for user confidence. -### [PRINCIPLE_3_NAME] - -[PRINCIPLE_3_DESCRIPTION] - +### Composable Rule Engine +Rename logic MUST be expressed as composable, deterministic rules that can be chained without +mutating shared state. Each rule MUST declare its inputs, validations, and postconditions so new +rules can be added without rewriting existing ones. Rule evaluation MUST be tested independently +and in combination to guarantee predictable outcomes across platforms. **Rationale:** A modular rule +engine unlocks flexibility while containing complexity. -### [PRINCIPLE_4_NAME] - -[PRINCIPLE_4_DESCRIPTION] - +### Scope-Aware Traversal +By default the CLI MUST operate on the current directory, renaming files only. The `-d` flag MUST +explicitly include directory renames, and the optional `-r` flag MUST traverse subdirectories +depth-first while avoiding hidden/system paths unless the user opts in. The `-e` flag MUST accept a +`.`-prefixed, `|`-delimited list of extensions (e.g., `-e .jpg|.exe|.mov`) that filters candidates +before preview, execution, and undo. Traversal MUST protect against escaping the requested scope and +MUST report skipped paths or filters that yield no matches. **Rationale:** Clear scope controls keep +operations targeted and safe for diverse directory structures. -### [PRINCIPLE_5_NAME] - -[PRINCIPLE_5_DESCRIPTION] - +### Ergonomic CLI Stewardship +The CLI MUST use Cobra for command structure, flag parsing, and contextual help. Commands MUST +provide consistent flag naming, validation, exit codes, and scriptable output modes for automation. +Tests MUST cover help text, flag behavior, preview output, and undo flows to guarantee a polished +experience. **Rationale:** A dependable CLI experience drives adoption and lowers operational risk. -## [SECTION_2_NAME] - +## Operational Constraints -[SECTION_2_CONTENT] - +- Commands operate relative to the invocation directory; alternate roots MUST be supplied via an + explicit flag and validated before execution. +- The `.renamer` ledger MUST be treated as append-only, stored alongside user-controlled files, and + ignored by rename scans to avoid self-modification. +- Preview mode MUST remain the default behavior; force-apply pathways require a future governance + amendment before implementation is permitted. +- Extension filters MUST require `.`-prefixed tokens, reject duplicate/empty values, and clearly + indicate when filters exclude all candidates so users can adjust before executing. +- File system interactions MUST handle cross-platform path semantics (case sensitivity, Unicode) via + Go’s standard libraries or vetted wrappers. -## [SECTION_3_NAME] - +## Development Workflow -[SECTION_3_CONTENT] - +- Specs, plans, and tasks MUST document how preview, ledger, and traversal guarantees are satisfied + before implementation begins. +- Each feature implementation MUST add or update automated tests that demonstrate preview accuracy, + ledger integrity, and undo safety for the affected rules. +- Code reviews MUST verify compliance with every principle and confirm that documentation explains + new flags, rules, traversal behaviors, and extension filtering semantics. ## Governance - -[GOVERNANCE_RULES] - +- **Amendments:** Proposals MUST include impacted principles, updated template guidance, and a dry + run preview demonstrating continued safety before acceptance. +- **Versioning Policy:** This constitution follows semantic versioning. MAJOR increments reflect + breaking governance changes, MINOR increments add or materially expand principles/sections, and + PATCH increments capture clarifications. +- **Compliance Reviews:** Before each release, the maintainer MUST confirm that CLI behavior, tests, + and documentation satisfy the principles and that the `.renamer` ledger remains reversible. -**Version**: [CONSTITUTION_VERSION] | **Ratified**: [RATIFICATION_DATE] | **Last Amended**: [LAST_AMENDED_DATE] - +**Version**: 1.1.0 | **Ratified**: 2025-10-29 | **Last Amended**: 2025-10-29 diff --git a/.specify/templates/plan-template.md b/.specify/templates/plan-template.md index 6a8bfc6..110e167 100644 --- a/.specify/templates/plan-template.md +++ b/.specify/templates/plan-template.md @@ -31,7 +31,11 @@ *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* -[Gates determined based on constitution file] +- Preview flow MUST show deterministic rename mappings and require explicit confirmation (Preview-First Safety). +- Undo strategy MUST describe how the `.renamer` ledger entry is written and reversed (Persistent Undo Ledger). +- Planned rename rules MUST document their inputs, validations, and composing order (Composable Rule Engine). +- Scope handling MUST cover files vs directories (`-d`), recursion (`-r`), and extension filtering via `-e` without escaping the requested path (Scope-Aware Traversal). +- CLI UX plan MUST confirm Cobra usage, flag naming, help text, and automated tests for preview/undo flows (Ergonomic CLI Stewardship). ## Project Structure diff --git a/.specify/templates/spec-template.md b/.specify/templates/spec-template.md index c67d914..7e9cb33 100644 --- a/.specify/templates/spec-template.md +++ b/.specify/templates/spec-template.md @@ -72,8 +72,10 @@ Fill them out with the right edge cases. --> -- What happens when [boundary condition]? -- How does system handle [error scenario]? +- How does the rename plan handle conflicting target names or read-only files? +- What is the expected behavior when the `.renamer` ledger is missing, corrupted, or out of sync? +- How are case-only renames or Unicode normalization differences managed across platforms? +- What feedback is provided when an extension filter yields zero matches or contains invalid tokens? ## Requirements *(mandatory)* @@ -84,21 +86,22 @@ ### Functional Requirements -- **FR-001**: System MUST [specific capability, e.g., "allow users to create accounts"] -- **FR-002**: System MUST [specific capability, e.g., "validate email addresses"] -- **FR-003**: Users MUST be able to [key interaction, e.g., "reset their password"] -- **FR-004**: System MUST [data requirement, e.g., "persist user preferences"] -- **FR-005**: System MUST [behavior, e.g., "log all security events"] +- **FR-001**: CLI MUST generate a deterministic preview of all pending renames before execution. +- **FR-002**: Users MUST confirm the preview (or abort) prior to any filesystem changes. +- **FR-003**: The tool MUST append every confirmed batch to the `.renamer` ledger with sufficient metadata for undo. +- **FR-004**: Users MUST be able to undo the most recent batch safely, even across process restarts. +- **FR-005**: CLI MUST support directory targeting (`-d`) and optional recursive traversal (`-r`) with clear scope boundaries. +- **FR-006**: CLI MUST accept an extension filter flag (`-e`) that parses `.`-prefixed, `|`-delimited extensions and applies the filter consistently across preview, execute, and undo flows. *Example of marking unclear requirements:* -- **FR-006**: System MUST authenticate users via [NEEDS CLARIFICATION: auth method not specified - email/password, SSO, OAuth?] -- **FR-007**: System MUST retain user data for [NEEDS CLARIFICATION: retention period not specified] +- **FR-007**: CLI MUST support additional rename rule `[RULE_NAME]` [NEEDS CLARIFICATION: inputs/outputs not defined] +- **FR-008**: CLI MUST expose automation-friendly output [NEEDS CLARIFICATION: format (JSON, plain text) undecided] ### Key Entities *(include if feature involves data)* -- **[Entity 1]**: [What it represents, key attributes without implementation] -- **[Entity 2]**: [What it represents, relationships to other entities] +- **RenameBatch**: Represents a single preview/execute cycle; attributes include rules applied, timestamp, working directory, and file mappings. +- **RuleDefinition**: Captures configuration for a rename rule (inputs, validations, dependencies) without binding to implementation. ## Success Criteria *(mandatory)* diff --git a/.specify/templates/tasks-template.md b/.specify/templates/tasks-template.md index 60f9be4..c572674 100644 --- a/.specify/templates/tasks-template.md +++ b/.specify/templates/tasks-template.md @@ -48,9 +48,9 @@ description: "Task list template for feature implementation" **Purpose**: Project initialization and basic structure -- [ ] T001 Create project structure per implementation plan -- [ ] T002 Initialize [language] project with [framework] dependencies -- [ ] T003 [P] Configure linting and formatting tools +- [ ] T001 Scaffold Cobra CLI command layout in `cmd/` per implementation plan +- [ ] T002 Configure Go module dependencies (cobra, pflag) and shared config in `go.mod` +- [ ] T003 [P] Establish `.renamer` ledger helpers in `internal/history/ledger.go` --- @@ -62,12 +62,12 @@ description: "Task list template for feature implementation" Examples of foundational tasks (adjust based on your project): -- [ ] T004 Setup database schema and migrations framework -- [ ] T005 [P] Implement authentication/authorization framework -- [ ] T006 [P] Setup API routing and middleware structure -- [ ] T007 Create base models/entities that all stories depend on -- [ ] T008 Configure error handling and logging infrastructure -- [ ] T009 Setup environment configuration management +- [ ] T004 Implement preview engine service in `internal/preview/service.go` +- [ ] T005 [P] Implement ledger append and undo mechanics in `internal/history/undo.go` +- [ ] T006 [P] Define rule interface and registry in `internal/rules/registry.go` +- [ ] T007 Create traversal utilities supporting `-d`, `-r`, and extension filtering in `internal/traversal/walker.go` +- [ ] T008 Configure structured logging and error handling for rename operations in `internal/logging/logger.go` +- [ ] T009 Document CLI flag contract and validation rules (including `-e`) in `docs/cli-flags.md` **Checkpoint**: Foundation ready - user story implementation can now begin in parallel @@ -83,17 +83,18 @@ Examples of foundational tasks (adjust based on your project): > **NOTE: Write these tests FIRST, ensure they FAIL before implementation** -- [ ] T010 [P] [US1] Contract test for [endpoint] in tests/contract/test_[name].py -- [ ] T011 [P] [US1] Integration test for [user journey] in tests/integration/test_[name].py +- [ ] T010 [P] [US1] CLI preview contract test (covers extension filters) in `tests/contract/preview_test.go` +- [ ] T011 [P] [US1] Integration test covering preview confirmation flow in `tests/integration/preview_flow_test.go` ### Implementation for User Story 1 -- [ ] T012 [P] [US1] Create [Entity1] model in src/models/[entity1].py -- [ ] T013 [P] [US1] Create [Entity2] model in src/models/[entity2].py -- [ ] T014 [US1] Implement [Service] in src/services/[service].py (depends on T012, T013) -- [ ] T015 [US1] Implement [endpoint/feature] in src/[location]/[file].py -- [ ] T016 [US1] Add validation and error handling -- [ ] T017 [US1] Add logging for user story 1 operations +- [ ] T012 [P] [US1] Implement default rename rule in `internal/rules/default.go` +- [ ] T013 [P] [US1] Implement extension filter parsing and validation in `internal/filters/extensions.go` +- [ ] T014 [US1] Implement preview renderer in `internal/preview/format.go` +- [ ] T015 [US1] Wire Cobra command to preview service and filters in `cmd/root.go` (depends on T012, T013, T014) +- [ ] T016 [US1] Add confirmation prompt and dry-run guardrails in `cmd/root.go` +- [ ] T017 [US1] Harden validation and conflict detection (including filter edge cases) in `internal/preview/validate.go` +- [ ] T018 [US1] Emit structured preview logs in `internal/logging/logger.go` **Checkpoint**: At this point, User Story 1 should be fully functional and testable independently @@ -107,15 +108,15 @@ Examples of foundational tasks (adjust based on your project): ### Tests for User Story 2 (OPTIONAL - only if tests requested) ⚠️ -- [ ] T018 [P] [US2] Contract test for [endpoint] in tests/contract/test_[name].py -- [ ] T019 [P] [US2] Integration test for [user journey] in tests/integration/test_[name].py +- [ ] T019 [P] [US2] Ledger append/undo contract test in `tests/contract/ledger_test.go` +- [ ] T020 [P] [US2] Integration test for undo workflow in `tests/integration/undo_flow_test.go` ### Implementation for User Story 2 -- [ ] T020 [P] [US2] Create [Entity] model in src/models/[entity].py -- [ ] T021 [US2] Implement [Service] in src/services/[service].py -- [ ] T022 [US2] Implement [endpoint/feature] in src/[location]/[file].py -- [ ] T023 [US2] Integrate with User Story 1 components (if needed) +- [ ] T021 [P] [US2] Create ledger persistence adapter in `internal/history/storage.go` +- [ ] T022 [US2] Implement undo command wiring in `cmd/undo.go` +- [ ] T023 [US2] Guard undo execution with validation in `internal/history/validate.go` +- [ ] T024 [US2] Reuse preview output to display revert plan prior to undo **Checkpoint**: At this point, User Stories 1 AND 2 should both work independently @@ -129,14 +130,14 @@ Examples of foundational tasks (adjust based on your project): ### Tests for User Story 3 (OPTIONAL - only if tests requested) ⚠️ -- [ ] T024 [P] [US3] Contract test for [endpoint] in tests/contract/test_[name].py -- [ ] T025 [P] [US3] Integration test for [user journey] in tests/integration/test_[name].py +- [ ] T025 [P] [US3] Recursion traversal contract test in `tests/contract/traversal_test.go` +- [ ] T026 [P] [US3] Integration test for nested directory rename in `tests/integration/traversal_flow_test.go` ### Implementation for User Story 3 -- [ ] T026 [P] [US3] Create [Entity] model in src/models/[entity].py -- [ ] T027 [US3] Implement [Service] in src/services/[service].py -- [ ] T028 [US3] Implement [endpoint/feature] in src/[location]/[file].py +- [ ] T027 [P] [US3] Extend traversal walker to honor include/exclude patterns in `internal/traversal/filter.go` +- [ ] T028 [US3] Implement directory rename rule enabling `-d` support in `internal/rules/directories.go` +- [ ] T029 [US3] Update CLI to surface traversal options and help text in `cmd/root.go` **Checkpoint**: All user stories should now be independently functional diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..3470088 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,51 @@ +/* +Copyright © 2025 NAME HERE + +*/ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" +) + + + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "renamer", + Short: "A brief description of your application", + Long: `A longer description that spans multiple lines and likely contains +examples and usage of using your application. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + // Uncomment the following line if your bare application + // has an action associated with it: + // Run: func(cmd *cobra.Command, args []string) { }, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { + // Here you will define your flags and configuration settings. + // Cobra supports persistent flags, which, if defined here, + // will be global for your application. + + // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.renamer.yaml)") + + // Cobra also supports local flags, which will only run + // when this action is called directly. + rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e3c13c5 --- /dev/null +++ b/go.mod @@ -0,0 +1,9 @@ +module github.com/rogeecn/renamer + +go 1.24.0 + +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/cobra v1.10.1 // indirect + github.com/spf13/pflag v1.0.9 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e613680 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..da23c50 --- /dev/null +++ b/main.go @@ -0,0 +1,11 @@ +/* +Copyright © 2025 NAME HERE + +*/ +package main + +import "github.com/rogeecn/renamer/cmd" + +func main() { + cmd.Execute() +}