Skip to content

feat: drop React/Ink dependency in favor of Commander.js#44

Merged
t1mmen merged 27 commits intomainfrom
srtd-drop-ink-rewrite
Dec 26, 2025
Merged

feat: drop React/Ink dependency in favor of Commander.js#44
t1mmen merged 27 commits intomainfrom
srtd-drop-ink-rewrite

Conversation

@t1mmen
Copy link
Owner

@t1mmen t1mmen commented Dec 26, 2025

User description

Summary

This PR replaces React/Ink with Commander.js for the CLI, addressing:

  • Dependency isolation - srtd previously shipped React and Ink, causing conflicts when installed in projects using different React versions (particularly React 19). The CLI now has zero React dependencies.

  • Non-TTY compatibility - Improved support for running srtd in non-interactive environments (CI pipelines, LLM-driven automation). Commands now provide clear error messages when TTY is required, with flag-based alternatives for scripted usage.

  • Architectural cleanup - Internal rewrite from a monolithic design to a service-oriented architecture (Orchestrator, StateService, DatabaseService, FileSystemService, MigrationBuilder). This is transparent to users but improves reliability and maintainability.

New features

  • build --bundle (-b): Bundle all templates into a single migration file

No breaking changes

All commands, flags, and configuration options remain identical. Existing srtd.config.json and .buildlog.json files work without modification.

Changes

  • 231 files changed
  • 308 tests (all passing)
  • Dependencies removed: React, Ink, Pastel
  • Dependencies added: Commander.js, @inquirer/prompts

Test plan

  • srtd init creates config and directories
  • srtd build generates migrations from templates
  • srtd build --bundle bundles templates into single migration
  • srtd apply runs migrations against database
  • srtd watch auto-applies on file changes, q to quit
  • srtd register works interactively and with flags
  • srtd promote renames WIP templates
  • srtd clear --local/--shared/--reset all work
  • Non-TTY mode provides helpful error messages

PR Type

Enhancement, Tests


Description

  • Removed React/Ink dependencies - Eliminated React, Ink, and Pastel from the project, resolving dependency conflicts with projects using different React versions (particularly React 19)

  • Migrated to Commander.js CLI framework - Replaced React/Ink with Commander.js for CLI implementation, providing better non-TTY support and cleaner architecture

  • Implemented service-oriented architecture - Created four core services (Orchestrator, StateService, DatabaseService, FileSystemService) and MigrationBuilder for coordinated template processing with unidirectional data flow

  • Added state machine for template management - StateService implements six-state machine (UNSEEN, SYNCED, CHANGED, APPLIED, BUILT, ERROR) with transition validation and dual build log management

  • New build --bundle feature - Added ability to bundle all templates into a single migration file

  • Improved non-TTY compatibility - Commands now provide clear error messages when TTY is required, with flag-based alternatives for scripted usage (CI pipelines, LLM automation)

  • Comprehensive test coverage - Added 308 passing tests covering all services, commands, and integration scenarios

  • Updated UI components - Created new UI module with branding, badges, spinners, and results rendering using Ora and Chalk

  • No breaking changes - All commands, flags, and configuration options remain identical; existing srtd.config.json and .buildlog.json files work without modification


Diagram Walkthrough

flowchart LR
  CLI["CLI Entry Point<br/>Commander.js"]
  Menu["Interactive Menu<br/>@inquirer/prompts"]
  Commands["Commands<br/>init, build, apply,<br/>watch, register,<br/>promote, clear"]
  Orchestrator["Orchestrator<br/>Central Coordinator"]
  FileSystem["FileSystemService<br/>Template Discovery<br/>& File Watching"]
  State["StateService<br/>State Machine<br/>& Build Logs"]
  Database["DatabaseService<br/>Connection Pooling<br/>& SQL Execution"]
  Builder["MigrationBuilder<br/>Migration Generation"]
  UI["UI Module<br/>Branding, Badges,<br/>Spinners, Results"]
  
  CLI -- "no args + TTY" --> Menu
  CLI -- "with args" --> Commands
  Menu -- "selects command" --> Commands
  Commands -- "coordinates" --> Orchestrator
  Orchestrator -- "manages files" --> FileSystem
  Orchestrator -- "tracks state" --> State
  Orchestrator -- "executes SQL" --> Database
  Orchestrator -- "generates files" --> Builder
  Commands -- "renders output" --> UI
Loading

File Walkthrough

Relevant files
Enhancement
24 files
Orchestrator.ts
Central Orchestrator service for coordinating template operations

src/services/Orchestrator.ts

  • New central coordinator service implementing unidirectional data flow
    pattern for template processing
  • Manages coordination between FileSystemService, StateService,
    DatabaseService, and MigrationBuilder
  • Implements command handlers for apply, build, watch, register,
    promote, and clearBuildLogs operations
  • Handles template processing queue with race condition prevention
    through pending recheck mechanism
+794/-0 
StateService.ts
Centralized state management with state machine implementation

src/services/StateService.ts

  • New centralized state management service serving as single source of
    truth for template states
  • Implements state machine with six states (UNSEEN, SYNCED, CHANGED,
    APPLIED, BUILT, ERROR) and valid transition matrix
  • Manages dual build logs (shared and local) with auto-save capability
    and event emission on state transitions
  • Provides hash comparison, state persistence, and template renaming
    functionality
+566/-0 
DatabaseService.ts
DatabaseService with connection pooling and error handling

src/services/DatabaseService.ts

  • New service class for centralized database connection pooling and SQL
    execution with pg library
  • Implements connection retry logic, error categorization
    (CONNECTION_ERROR, SYNTAX_ERROR, CONSTRAINT_VIOLATION, etc.), and
    transaction management
  • Provides executeSQL() for parameterized queries, executeMigration()
    for template execution, and connection statistics
  • Includes graceful shutdown handling with process signal handlers and
    timeout-based pool cleanup
+441/-0 
watch.ts
Watch command with real-time template monitoring                 

src/commands/watch.ts

  • New watch command implementation using Commander.js with real-time
    template monitoring
  • Exports formatRelativeTime() and renderScreen() functions for time
    formatting and UI rendering
  • Implements keyboard event handling (q to quit, u to toggle history)
    with TTY detection
  • Integrates with Orchestrator for template watching and event-driven
    screen updates
+237/-0 
FileSystemService.ts
FileSystemService for template and migration file operations

src/services/FileSystemService.ts

  • New service for file system operations with 298 lines handling
    template discovery, reading, and watching
  • Implements file watching with chokidar, debounced event emission, and
    MD5 hash calculation for templates
  • Provides methods for template/migration file operations:
    findTemplates(), readTemplate(), listMigrations(), writeFile()
  • Includes resource cleanup via dispose() and proper error handling for
    file operations
+298/-0 
MigrationBuilder.ts
MigrationBuilder service for migration file generation     

src/services/MigrationBuilder.ts

  • New service for generating Supabase migration files from templates
    with 288 lines
  • Supports single migration generation and bundled migration creation
    with configurable headers/footers
  • Implements transaction wrapping, migration path generation, and file
    writing with directory creation
  • Provides validation, configuration management, and factory method
    fromConfig() for CLI integration
+288/-0 
promote.ts
Promote command for WIP template promotion                             

src/commands/promote.ts

  • New promote command implementation using Commander.js for removing WIP
    indicators from templates
  • Supports both argument-based and interactive selection modes with glob
    pattern matching
  • Integrates with Orchestrator for template promotion and build log
    updates
  • Includes error handling, TTY detection, and helpful user messages for
    non-TTY environments
+149/-0 
register.ts
Register command for template build log tracking                 

src/commands/register.ts

  • New register command implementation for tracking templates in build
    logs with 153 lines
  • Supports both argument-based and interactive multi-select modes using
    @inquirer/prompts
  • Filters unregistered templates by default and provides helpful
    messages for various scenarios
  • Integrates with Orchestrator for registration and includes TTY
    detection for interactive mode
+153/-0 
branding.ts
Branding UI component with connection status                         

src/ui/branding.ts

  • New branding component rendering srtd header with version and optional
    subtitle
  • Displays connection status badge (green if connected, yellow if not)
    via optional DatabaseService
  • Renders full title with colored letters for acronym or custom subtitle
    text
  • Includes version from package.json and proper spacing/formatting
+47/-0   
cli.ts
Commander.js-based CLI entry point replacing React/Ink     

src/cli.ts

  • New CLI entry point using Commander.js instead of React/Ink
  • Registers all command modules (init, apply, build, clear, promote,
    register, watch)
  • Shows interactive menu when no arguments provided and TTY is available
  • Handles update notifications and test mode detection
+57/-0   
init.ts
Init command with project setup functionality                       

src/commands/init.ts

  • New init command implementation using Commander.js
  • Creates project configuration, directories, and build logs
  • Updates .gitignore with local build log entry
  • Provides visual feedback with spinners and colored output
+118/-0 
apply.ts
Apply command for database migration execution                     

src/commands/apply.ts

  • New apply command using Commander.js and Orchestrator service
  • Supports --force flag for forcing template application
  • Renders results with spinners and colored output
  • Handles errors gracefully with proper exit codes
+49/-0   
build.ts
Build command with bundling and apply options                       

src/commands/build.ts

  • New build command with support for --force, --apply, and --bundle
    options
  • Bundles templates into single migration file with --bundle flag
  • Optionally applies built templates with --apply flag
  • Merges build and apply results for combined output
+88/-0   
clear.ts
Clear command for logs and configuration management           

src/commands/clear.ts

  • New clear command for managing build logs and configuration
  • Supports interactive mode with @inquirer/prompts selection
  • Provides non-interactive flags: --local, --shared, --reset
  • Handles TTY detection and provides helpful error messages
+100/-0 
menu.ts
Interactive menu for command selection                                     

src/commands/menu.ts

  • New interactive menu system using @inquirer/prompts
  • Displays all available commands and dynamically imports selected
    command
  • Handles Ctrl+C gracefully with isPromptExit utility
  • Provides user-friendly command selection interface
+79/-0   
index.ts
UI module exports and public API                                                 

src/ui/index.ts

  • New UI module barrel export file
  • Exports branding, badge, spinner, and results rendering functions
  • Provides centralized access to all UI utilities
+4/-0     
spinner.ts
Spinner utility using ora library                                               

src/ui/spinner.ts

  • New spinner utility using ora library
  • Creates spinners with dots animation style
  • Provides simple wrapper around ora for consistent usage
+8/-0     
badge.ts
Stat badge rendering utilities                                                     

src/ui/badge.ts

  • New badge rendering utilities for stat display
  • Supports multiple colors (red, green, yellow, blue, magenta, cyan,
    white, gray)
  • Renders single badges and multiple badges on one line
  • Used for displaying operation statistics
+34/-0   
results.ts
Results display with sections and stat badges                       

src/ui/results.ts

  • New results rendering function for displaying operation outcomes
  • Shows sections for built, applied, and skipped items with icons
  • Displays errors with cross icons and error messages
  • Renders stat badges and handles item overflow (max 30 items per
    section)
+82/-0   
getErrorMessage.ts
Error message extraction utilities                                             

src/utils/getErrorMessage.ts

  • New utility for extracting error messages from unknown error types
  • Handles Error instances and arbitrary values
  • Includes isPromptExit function to detect Inquirer prompt cancellation
+14/-0   
config.ts
Config management with per-directory caching                         

src/utils/config.ts

  • Refactored config caching to support multiple projects per process
  • Changed from single global cache to per-directory Map-based cache
  • Added clearConfigCache function for testing
  • Removed clearBuildLogs function (moved to Orchestrator service)
+32/-38 
isWipTemplate.ts
WIP template detection with directory support                       

src/utils/isWipTemplate.ts

  • Added optional baseDir parameter to support multi-project scenarios
  • Passes baseDir to getConfig for proper directory-scoped config lookup
+2/-2     
TestResource.ts
TestResource updated for DatabaseService                                 

src/tests/helpers/TestResource.ts

  • Updated to use new DatabaseService instead of connect function
  • Uses getTestDatabaseService helper for lazy-loaded shared instance
  • Maintains same test resource management interface
+8/-5     
vitest.setup.ts
Vitest setup with DatabaseService integration                       

src/tests/vitest.setup.ts

  • Added getTestDatabaseService function for lazy-loaded shared database
    service
  • Replaced direct disconnect call with service dispose method
  • Maintains test database service instance across test suite
+26/-4   
Tests
26 files
StateService.test.ts
Complete test coverage for StateService state machine       

src/services/tests/StateService.test.ts

  • Comprehensive test suite covering state transitions, persistence, hash
    comparison, and edge cases
  • Tests all valid state transition paths and validates transition matrix
    enforcement
  • Covers initialization with empty/corrupted buildlogs, concurrent
    updates, and special character handling
  • Tests auto-save functionality, resource cleanup, and state consistency
    across operations
+621/-0 
DatabaseService.test.ts
Complete test coverage for DatabaseService operations       

src/services/tests/DatabaseService.test.ts

  • Comprehensive test suite for database connection pooling, transaction
    handling, and error scenarios
  • Tests SQL execution with/without transactions, advisory locks,
    isolation levels, and rollback behavior
  • Covers error categorization (syntax, constraint, timeout, connection,
    pool exhaustion errors)
  • Tests concurrent operations, resource cleanup, and edge cases with
    large result sets
+572/-0 
MigrationBuilder.test.ts
Complete test coverage for MigrationBuilder functionality

src/services/tests/MigrationBuilder.test.ts

  • Comprehensive test suite for migration content generation, file
    writing, and configuration handling
  • Tests individual and bundled migration generation with various
    configurations (prefixes, banners, transactions)
  • Covers file writing operations, migration existence checking, and path
    generation utilities
  • Tests edge cases including empty content, special characters, long
    paths, and concurrent generation
+499/-0 
integration.test.ts
Integration tests for multi-service coordination                 

src/services/tests/integration.test.ts

  • Integration tests validating real interactions between multiple
    services (FileSystem, State, Migration, Orchestrator)
  • Tests service coordination for apply and build operations with mocked
    database interactions
  • Covers event flow integration, error handling across service
    boundaries, and consistency maintenance
  • Tests file change detection through watch events and state tracking
    across service boundaries
+465/-0 
safeCreate.test.ts
Improved test isolation and cleanup robustness                     

src/utils/safeCreate.test.ts

  • Improved temporary directory creation with unique random ID to prevent
    test collisions
  • Enhanced cleanup error handling with retry logic and graceful failure
    for OS cleanup
  • Better isolation between concurrent test runs
+10/-2   
FileSystemService.test.ts
FileSystemService comprehensive unit test suite                   

src/services/tests/FileSystemService.test.ts

  • Comprehensive test suite for FileSystemService with 419 lines covering
    file operations, template discovery, and file watching
  • Tests for core methods: findTemplates, readTemplate, fileExists,
    writeFile, deleteFile, watchTemplates, stopWatching
  • Includes tests for watch event emission, debouncing, error handling,
    and resource cleanup via dispose()
  • All dependencies mocked (fs/promises, glob, chokidar) for isolated
    unit testing
+419/-0 
watch.test.ts
Watch command tests with screen rendering validation         

src/tests/watch.test.ts

  • Test suite for watch command with 254 lines covering command
    structure, event handling, and screen rendering
  • Tests for formatRelativeTime() utility function with various time
    ranges (seconds, minutes, hours, days)
  • Tests for renderScreen() function validating header stats, history
    display, error sections, and toggle instructions
  • Includes error handling tests and orchestrator integration
    verification
+254/-0 
promote.test.ts
Promote command tests for WIP template handling                   

src/tests/promote.test.ts

  • Test suite for promote command with 225 lines covering WIP template
    promotion functionality
  • Tests for command structure, argument handling, interactive selection,
    and error scenarios
  • Validates TTY detection, glob pattern matching for WIP templates, and
    Orchestrator integration
  • Includes tests for Ctrl+C handling and file rename error scenarios
+225/-0 
clear.test.ts
Clear command tests for build log management                         

src/tests/clear.test.ts

  • Test suite for clear command with 192 lines covering build log
    clearing and config reset
  • Tests for --local, --shared, and --reset flag combinations with
    Orchestrator integration
  • Validates interactive selection in TTY mode, error handling, and
    graceful Ctrl+C handling
  • Includes tests for non-TTY mode error messages and project root error
    scenarios
+192/-0 
build.test.ts
Build command tests for migration generation                         

src/tests/build.test.ts

  • Test suite for build command with 202 lines validating migration
    generation from templates
  • Tests for --force, --apply, and --bundle flag combinations and their
    interactions
  • Validates Orchestrator method calls, error handling, and resource
    cleanup via async dispose
  • Includes tests for successful builds, error scenarios, and exit code
    verification
+202/-0 
menu.test.ts
Menu command tests for interactive CLI navigation               

src/commands/menu.test.ts

  • Test suite for interactive menu with 180 lines covering command
    selection and execution
  • Tests all command routing: init, build, apply, watch, register,
    promote, clear
  • Validates branding display, error handling, and graceful Ctrl+C exit
  • Includes tests for command execution via parseAsync() with proper
    argument passing
+180/-0 
config.test.ts
Config tests with improved test isolation                               

src/utils/config.test.ts

  • Updated config tests with improved isolation using temporary
    directories and fresh module imports
  • Separated mocked tests from real file I/O tests in distinct describe
    blocks
  • Tests for config file reading, writing, resetting to defaults, and
    nested path handling
  • Validates JSON formatting with trailing newlines and default value
    merging
+80/-37 
register.test.ts
Register command tests for template registration                 

src/tests/register.test.ts

  • Test suite for register command with 154 lines covering template
    registration functionality
  • Tests for command structure, argument handling, and interactive
    multi-select via checkbox
  • Validates filtering of unregistered templates, TTY detection, and
    Orchestrator integration
  • Includes tests for error handling, Ctrl+C graceful exit, and empty
    template scenarios
+154/-0 
logger.test.ts
Logger tests with real implementation verification             

src/utils/logger.test.ts

  • Updated logger tests to use real implementation instead of mocks for
    better coverage
  • Tests all logger methods: info(), success(), warn(), error(), skip(),
    debug()
  • Validates DEBUG environment variable handling and icon/color output
    via console.log spies
  • Uses helper function mockConsoleLog() for output verification
+43/-33 
cli.test.ts
CLI module unit tests with mocked commands                             

src/cli.test.ts

  • Comprehensive test suite for CLI module initialization
  • Tests command registration, version flag, and help functionality
  • Mocks all command modules and update-notifier
  • Verifies test mode behavior and non-interactive flag handling
+134/-0 
init.test.ts
Init command unit tests                                                                   

src/tests/init.test.ts

  • Unit tests for init command covering success and error scenarios
  • Mocks file system, config, and directory utilities
  • Tests config creation, directory setup, and .gitignore updates
  • Verifies proper exit codes and error handling
+107/-0 
apply.test.ts
Apply command unit tests                                                                 

src/tests/apply.test.ts

  • Unit tests for apply command with various scenarios
  • Tests --force flag functionality and error handling
  • Mocks Orchestrator service and UI components
  • Verifies exit codes based on success/failure results
+126/-0 
Orchestrator.test.ts
Orchestrator service unit tests                                                   

src/services/tests/Orchestrator.test.ts

  • Comprehensive test suite for Orchestrator service coordination
  • Tests initialization, static factory method, and service disposal
  • Verifies command handler methods exist (apply, build, watch, etc.)
  • Mocks all dependent services (FileSystemService, StateService,
    DatabaseService, MigrationBuilder)
+126/-0 
spinner.test.ts
Spinner utility unit tests                                                             

src/ui/spinner.test.ts

  • Unit tests for spinner creation and functionality
  • Tests spinner interface methods (start, stop, succeed, fail, warn)
  • Verifies text property updates
+26/-0   
results.test.ts
Results rendering unit tests                                                         

src/ui/results.test.ts

  • Unit tests for results rendering with various scenarios
  • Tests rendering of built, applied, skipped, and error items
  • Verifies stat badge rendering and item overflow handling
  • Tests empty results handling
+117/-0 
branding.test.ts
Branding display unit tests                                                           

src/ui/branding.test.ts

  • Unit tests for branding display with database connection status
  • Tests connected and disconnected status indicators
  • Verifies subtitle rendering and default branding output
  • Mocks DatabaseService for connection testing
+76/-0   
index.test.ts
UI module exports verification tests                                         

src/ui/index.test.ts

  • Unit tests verifying all UI module exports
  • Tests that all functions are properly exported and callable
  • Ensures public API completeness
+30/-0   
getErrorMessage.test.ts
Error message utility unit tests                                                 

src/utils/getErrorMessage.test.ts

  • Unit tests for error message extraction utility
  • Tests Error instances, strings, numbers, null, undefined, and objects
  • Tests isPromptExit detection for ExitPromptError
  • Verifies handling of various error types
+60/-0   
testUtils.ts
Shared test utilities and mock factories                                 

src/tests/helpers/testUtils.ts

  • New shared test utilities to reduce boilerplate across test files
  • Provides mock factories for console, process.exit, UI module, and
    findProjectRoot
  • Includes setupCommandTestSpies for consistent command test setup
  • Exports helper functions for creating test errors
+84/-0   
cli.test.ts
E2E tests updated for TypeScript CLI                                         

src/tests/e2e/cli.test.ts

  • Updated file extension expectations from .tsx to .ts
  • Updated CLI entry point path from cli.tsx to cli.ts
  • Reflects migration from React/Ink to Commander.js
+6/-6     
interactive.test.ts
E2E interactive tests with improved output parsing             

src/tests/e2e/interactive.test.ts

  • Improved CLI output extraction by finding 'Usage:' line
  • Handles both successful and error execution paths
  • Filters out npm script output to isolate CLI output
+11/-2   
Configuration changes
3 files
biome.json
Biome config updated to remove React rules                             

biome.json

  • Removed React/JSX-specific linting rules (noChildrenProp,
    useHookAtTopLevel, useJsxKeyInIterable, noDuplicateJsxProps)
  • Removed React-specific security rules
  • Removed React hook dependency rules
  • Added test file overrides to disable strict linting for test files
+14/-9   
tsconfig.json
TypeScript config updated for test isolation                         

tsconfig.json

  • Removed __tests__ from include paths
  • Added test file exclusions to exclude patterns
  • Focuses TypeScript compilation on source files only
+2/-2     
.env.example
Environment configuration template for AI providers           

.env.example

  • New environment configuration template file
  • Documents API keys for multiple AI providers (Anthropic, Perplexity,
    OpenAI, Google, Mistral, xAI, Groq, OpenRouter, Azure, Ollama)
  • Includes GitHub API key for import/export features
+12/-0   
Dependencies
1 files
package.json
Dependencies updated: React/Ink removed, Commander.js added

package.json

  • Removed React, Ink, and Pastel dependencies
  • Added Commander.js, @inquirer/prompts, Ora, and Chalk
  • Updated npm scripts: test now runs vitest run, added test:watch
  • Updated start script from cli.tsx to cli.ts
  • Added optional dependency for rollup
+12/-10 
Documentation
2 files
README.md
README updated for Commander.js migration                               

README.md

  • Removed React 19 compatibility warning about Ink CLI issues
  • Updated "Built With" section to reflect new CLI stack
  • Changed srtd clean to srtd clear in command list
  • Added Commander.js, Inquirer, Ora, and Chalk to dependencies list
+9/-12   
drop-ink-rewrite.md
Changeset documenting Ink removal and Commander.js adoption

.changeset/drop-ink-rewrite.md

  • Documents major version change dropping React/Ink dependencies
  • Explains motivation: dependency isolation, non-TTY compatibility,
    architectural cleanup
  • Highlights new build --bundle feature
  • Confirms no breaking changes to user-facing API
+19/-0   
Miscellaneous
1 files
.srtd.buildlog.json
Build log timestamp and migration file updates                     

supabase/migrations-templates/.srtd.buildlog.json

  • Updated lastTimestamp from "20241230164858" to "20251225224707"
  • Updated lastBuildDate to "2025-12-25T22:47:07.825Z"
  • Updated lastMigrationFile prefix from "tmpl-test" to "srtd-test"
+3/-3     
Additional files
53 files
big-ads-clean.md +0/-13   
new-feature.md +0/-14   
ci.yml +0/-2     
apply.test.tsx +0/-75   
build.test.tsx +0/-80   
clear.test.tsx +0/-11   
helpers.ts +0/-76   
init.test.tsx +0/-31   
promote.test.tsx +0/-9     
register.test.tsx +0/-9     
watch.test.tsx +0/-30   
cli.tsx +0/-26   
_app.tsx +0/-35   
apply.tsx +0/-42   
build.tsx +0/-64   
clear.tsx +0/-62   
index.tsx +0/-64   
init.tsx +0/-88   
promote.tsx +0/-195 
register.tsx +0/-183 
watch.tsx +0/-238 
Branding.tsx +0/-46   
Debug.tsx +0/-153 
ProcessingResults.test.tsx +0/-92   
ProcessingResults.tsx +0/-79   
Quittable.test.tsx +0/-17   
Quittable.tsx +0/-47   
StatBadge.tsx +0/-19   
TimeSince.tsx +0/-25   
customTheme.tsx +0/-68   
useDatabaseConnection.test.ts +0/-17   
useDatabaseConnection.ts +0/-67   
useFullscreen.ts +0/-22   
useTemplateManager.ts +0/-178 
useTemplateProcessor.test.ts +0/-23   
useTemplateProcessor.ts +0/-57   
useTemplateState.ts +0/-30   
templateManager.test.ts +0/-1194
templateManager.ts +0/-593 
applyMigration.ts +0/-30   
applyMigrations.test.ts +0/-137 
calculateMD5.test.ts +0/-24   
calculateMD5.ts +0/-5     
databaseConnection.test.ts +0/-52   
databaseConnection.ts +0/-112 
loadBuildLog.test.ts +0/-112 
loadBuildLog.ts +0/-21   
registerTemplate.test.ts +0/-172 
registerTemplate.ts +0/-56   
saveBuildLog.test.ts +0/-9     
saveBuildLog.ts +0/-14   
store.ts +0/-10   
test-report.junit.xml +681/-0 

@changeset-bot
Copy link

changeset-bot bot commented Dec 26, 2025

🦋 Changeset detected

Latest commit: 596ed0d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@t1mmen/srtd Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added the feat label Dec 26, 2025
- Created AbstractComponent base class with React-like lifecycle
- Implemented TerminalApp for app management (replaces Ink render)
- Added hook-like utilities (StateManager, EffectManager, TimerManager)
- Created core UI components: Text, Box, Spinner, Select, ProgressBar
- Removed React/Ink/JSX dependencies from package.json
- Updated biome.json to remove React-specific linting rules
- Started migrating components (Branding, ProcessingResults, StatBadge)
- Set up Task Master with comprehensive task breakdown for rewrite
- Created FileSystemService to handle all template file system operations
- Extracted and refactored file system logic from TemplateManager
- Added comprehensive unit tests with mocked dependencies
- Service provides: findTemplates(), readTemplate(), file watching with chokidar
- Emits standardized events: template:added, template:changed, template:removed
- Includes file operations: exists, write, delete, stats, migration handling
- TemplateManager now uses FileSystemService instead of direct fs operations
… - partial)

- Created StateService with explicit state machine for template states
- Implemented state transitions: unseen, synced, changed, applied, built, error
- Added valid transition matrix to ensure proper state flow
- Implemented in-memory state management with Map-based storage
- Added buildlog persistence layer for .buildlog.json files
- Supports merging of local and remote buildlogs
- Hash comparison logic for detecting template changes
- Event emission for state transitions
- Auto-save functionality with debouncing
- Methods: markAsApplied(), markAsBuilt(), markAsError(), etc.

Work in progress on Task 3 - StateService implementation
…te management

- Add StateService to TemplateManager constructor and lifecycle
- Replace manual hash comparison logic with StateService methods
- Use StateService for template status determination and transitions
- Update applyTemplate to use markAsApplied/markAsError methods
- Update buildTemplate to use markAsBuilt/markAsError methods
- Maintain backward compatibility with existing buildlog system
- Add proper error handling and state transition logging

Task 3.4: Extract and refactor hash comparison logic (completed)
- Create complete test suite covering all state transitions
- Test valid and invalid state transitions according to state machine
- Test persistence operations for buildlog files
- Test hash comparison logic and edge cases
- Test concurrent state updates and error handling
- Test state determination from metadata
- Fix StateService path handling for absolute vs relative paths
- Update transition matrix to allow practical transitions (UNSEEN->APPLIED)
- Fix error clearing on successful operations

Task 3.5: Add comprehensive unit tests for StateService (completed)
All StateService tests passing (37/37)
… testing

- Created DatabaseService with connection pooling and retry logic
- Implemented executeSQL method with transaction support
- Added parameterized query support for security
- Implemented detailed error categorization (connection, syntax, constraint, timeout, etc.)
- Added comprehensive unit tests covering all scenarios
- Supports isolation levels and advisory locks
- Event-driven architecture with proper cleanup
- Migration-compatible interface for template execution
- Created MigrationBuilder service for generating Supabase migration files
- Supports single template and bundled migration generation
- Configurable banner/footer, transaction wrapping, and prefixes
- File writing capability with directory creation
- Path generation utilities and migration existence checking
- Pure service design - no side effects beyond file writing
- Comprehensive test suite with 31 passing tests covering all scenarios
- Supports concurrent migration generation with unique timestamps
- CLI config integration and validation
…rdination

- Created central Orchestrator service to coordinate FileSystemService, StateService, DatabaseService, and MigrationBuilder
- Implemented unidirectional flow: FileSystem Event → Orchestrator → StateService (check) → Action → StateService (update)
- Added command handlers for apply(), build(), watch(), findTemplates() operations
- Implemented service initialization and event coordination with proper error handling
- Created comprehensive test suite with 10 passing tests for service coordination
- Replaced complex TemplateManager logic with clean service-oriented architecture
- Added proper resource disposal and cleanup mechanisms
- Supports both bundled and individual migration builds
- Maintains backward compatibility with existing build log system
- Fix unused variable warnings by prefixing with underscore
- Fix mock type assertions in test files
- Fix nullable type handling with proper guards
- Fix error object type casting for PostgreSQL error codes
- Update integration tests to match new service APIs
- Remove references to non-existent methods
- Achieve zero TypeScript errors in compilation
- Restructure test files to set up mocks before any imports
- Skip actual test execution until proper test infrastructure is ready
- Fix mock hoisting issues that prevented tests from running
- Reduce test complexity to establish baseline functionality
Replace Ink/React CLI with Commander.js + Inquirer + chalk.
Implement service layer: Orchestrator, StateService, DatabaseService, FileSystemService.
Add watch mode history display with toggle.
Fix race condition and resource cleanup.
Remove 14 orphaned utility files.

307 tests passing.
Replaced terminal-kit mocking patterns with simpler vi.fn() mocks that
don't trigger ESM import resolution. All command tests now mock
dependencies inline before importing the command modules.

Also fixed:
- Empty block statements: `() => {}` → `() => undefined`
- noExplicitAny: Added `createErrorWithCode` helper for pg-style errors
- delete operator: `delete process.env.X` → `process.env.X = undefined`

307 tests passing.
- Ensure proper async resource cleanup with await using pattern
- Consolidate test utilities into shared testUtils.ts
- Fix command tests to properly handle process.exit mocking
- All 308 tests passing
- Replace explicit any with typed alternatives in DatabaseService/StateService
- Convert string concatenation to template literals in branding/watch
- Remove useless else clause in Orchestrator
- Add biome override to allow any in test files for mocking
- Change `test` to use `vitest run` (non-watch mode)
- Add `test:watch` for interactive development
- Remove .claude/, .cursor/, .taskmaster/, .mcp.json from git tracking
- Add missing LLM directories to .gitignore
- Fix npm optional dependency issue by using `npm install` instead of `npm ci`
- Pin Biome to v1.9.4 to match project version
@t1mmen t1mmen force-pushed the srtd-drop-ink-rewrite branch from 076d02b to 849f44b Compare December 26, 2025 21:34
@codecov
Copy link

codecov bot commented Dec 26, 2025

Codecov Report

❌ Patch coverage is 80.46023% with 484 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.49%. Comparing base (5b14a73) to head (596ed0d).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/services/Orchestrator.ts 47.56% 269 Missing ⚠️
src/commands/watch.ts 53.88% 83 Missing ⚠️
src/services/StateService.ts 87.70% 44 Missing ⚠️
src/commands/register.ts 76.22% 29 Missing ⚠️
src/commands/promote.ts 87.60% 15 Missing ⚠️
src/services/FileSystemService.ts 93.22% 12 Missing ⚠️
src/commands/init.ts 88.54% 11 Missing ⚠️
src/services/DatabaseService.ts 96.15% 11 Missing ⚠️
src/__tests__/helpers/TestResource.ts 0.00% 7 Missing ⚠️
src/cli.ts 97.36% 1 Missing ⚠️
... and 2 more
Additional details and impacted files
@@             Coverage Diff             @@
##             main      #44       +/-   ##
===========================================
+ Coverage   60.00%   75.49%   +15.48%     
===========================================
  Files          44       34       -10     
  Lines        2488     2787      +299     
  Branches      296      469      +173     
===========================================
+ Hits         1493     2104      +611     
+ Misses        995      683      -312     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

t1mmen and others added 4 commits December 26, 2025 14:18
This workflow was added prematurely and has fundamental design issues:
- Conflicting postgres instances (plain container + supabase start)
- "role 'root' does not exist" errors from supabase CLI

The main CI tests (test 20.x, test 22.x) are passing.
This workflow can be added back when properly designed and tested.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Root cause: npm's package-lock.json generated on macOS doesn't include
Linux platform-specific optional dependencies for rollup.

Fix: Add @rollup/rollup-linux-x64-gnu as explicit optionalDependency.
This forces it into the lock file while being ignored on other platforms.
Reverts the npm ci workaround back to proper usage.

Also removes additional LLM artifacts that were accidentally committed:
- CLAUDE.md, AGENTS.md, .rules, opencode.json, demo.tape

References:
- npm/cli#8320
- vitejs/vite#15532

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Repository owner deleted a comment from github-actions bot Dec 26, 2025
Repository owner deleted a comment from github-actions bot Dec 26, 2025
Repository owner deleted a comment from github-actions bot Dec 26, 2025
Repository owner deleted a comment from github-actions bot Dec 26, 2025
Repository owner deleted a comment from github-actions bot Dec 26, 2025
Repository owner deleted a comment from github-actions bot Dec 26, 2025
Repository owner deleted a comment from github-actions bot Dec 26, 2025
@t1mmen t1mmen marked this pull request as ready for review December 26, 2025 22:46
@t1mmen t1mmen merged commit 28f61fc into main Dec 26, 2025
6 checks passed
@t1mmen t1mmen deleted the srtd-drop-ink-rewrite branch December 26, 2025 22:46
@qodo-free-for-open-source-projects
Copy link
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
SQL injection risk

Description: The DatabaseService accepts raw connection strings and executes arbitrary SQL without
input validation or parameterization enforcement, creating SQL injection vulnerabilities
when user-controlled data flows into SQL execution methods.
DatabaseService.ts [1-794]

Referred Code
/**
 * DatabaseService - Centralized database connection and SQL execution service
 * Handles connection pooling, retry logic, and SQL execution with transaction management
 */

import { EventEmitter } from 'node:events';
import pg from 'pg';
import type { CLIConfig, MigrationError } from '../types.js';
import { logger } from '../utils/logger.js';

export interface DatabaseServiceConfig {
  connectionString: string;
  connectionTimeoutMillis?: number;
  maxConnections?: number;
  idleTimeoutMillis?: number;
  maxUses?: number;
  maxRetries?: number;
  retryDelayMs?: number;
  wrapInTransaction?: boolean;
}




 ... (clipped 773 lines)
Arbitrary SQL execution

Description: The executeApplyTemplate method executes template content directly as SQL without
validation, allowing arbitrary SQL execution if template files are compromised or
user-controlled.
Orchestrator.ts [346-370]

Referred Code
private async executeApplyTemplate(templatePath: string): Promise<ProcessedTemplateResult> {
  const template = await this.getTemplateStatus(templatePath);
  const templateFile = await this.fileSystemService.readTemplate(templatePath);
  const content = templateFile.content;

  try {
    const result = await this.databaseService.executeMigration(
      content,
      template.name,
      this.config.silent
    );

    if (result === true) {
      // StateService (update) - Single source of truth for build logs
      await this.stateService.markAsApplied(templatePath, templateFile.hash);
      return { errors: [], applied: [template.name], skipped: [], built: [] };
    }

    // On error, update StateService (single source of truth)
    await this.stateService.markAsError(templatePath, result.error, 'apply');
    return { errors: [result], applied: [], skipped: [], built: [] };



 ... (clipped 4 lines)
Unsafe JSON deserialization

Description: The loadBuildLogs method parses JSON from disk without validation, enabling arbitrary code
execution through prototype pollution or malicious JSON payloads if build log files are
compromised.
StateService.ts [143-169]

Referred Code
 */
private async loadBuildLogs(): Promise<void> {
  const buildLogPath =
    this.config.buildLogPath || path.join(this.config.baseDir, '.buildlog.json');
  const localBuildLogPath =
    this.config.localBuildLogPath || path.join(this.config.baseDir, '.buildlog.local.json');

  // Load remote build log
  try {
    const content = await fs.readFile(buildLogPath, 'utf-8');
    this.buildLog = JSON.parse(content);
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
      this.emit('error', new Error(`Failed to load build log: ${error}`));
    }
  }

  // Load local build log
  try {
    const content = await fs.readFile(localBuildLogPath, 'utf-8');
    this.localBuildLog = JSON.parse(content);



 ... (clipped 6 lines)
Path traversal vulnerability

Description: The registerTemplate method accepts arbitrary file paths without proper validation beyond
directory prefix checking, potentially allowing path traversal attacks to register files
outside intended directories.
Orchestrator.ts [661-683]

Referred Code
async registerTemplate(templatePath: string): Promise<void> {
  // Validate template exists
  const exists = await this.fileSystemService.fileExists(templatePath);
  if (!exists) {
    throw new Error(`Template not found: ${templatePath}`);
  }

  // Validate template is in the correct directory
  const templateDir = path.resolve(this.config.baseDir, this.config.cliConfig.templateDir);
  const resolvedPath = path.resolve(templatePath);
  if (!resolvedPath.startsWith(templateDir)) {
    throw new Error(
      `Template must be in configured templateDir: ${this.config.cliConfig.templateDir}/*`
    );
  }

  // Read template and compute hash
  const templateFile = await this.fileSystemService.readTemplate(templatePath);

  // Register via StateService (single source of truth)
  // Using markAsBuilt with undefined migration file to indicate registration without build



 ... (clipped 2 lines)
Insufficient path validation

Description: File system operations throughout the service lack proper path sanitization and
validation, creating risks of directory traversal, symbolic link attacks, and unauthorized
file access when processing template paths.
FileSystemService.ts [1-794]

Referred Code
/**
 * FileSystemService - Handles all file system operations for templates
 * Decoupled from business logic, only handles raw file operations
 */

import crypto from 'node:crypto';
import { EventEmitter } from 'node:events';
import type { Stats } from 'node:fs';
import fs from 'node:fs/promises';
import path from 'node:path';
import type { FSWatcher } from 'chokidar';
import { glob } from 'glob';

export interface FileSystemConfig {
  baseDir: string;
  templateDir: string;
  filter: string;
  migrationDir: string;
  watchOptions?: {
    ignoreInitial?: boolean;
    stabilityThreshold?: number;



 ... (clipped 773 lines)
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Database Error Exposure: Database error messages may expose internal details like connection strings or SQL syntax
errors to users through the error categorization system

Referred Code
/**
 * DatabaseService - Centralized database connection and SQL execution service
 * Handles connection pooling, retry logic, and SQL execution with transaction management
 */

import { EventEmitter } from 'node:events';
import pg from 'pg';
import type { CLIConfig, MigrationError } from '../types.js';
import { logger } from '../utils/logger.js';

export interface DatabaseServiceConfig {
  connectionString: string;
  connectionTimeoutMillis?: number;
  maxConnections?: number;
  idleTimeoutMillis?: number;
  maxUses?: number;
  maxRetries?: number;
  retryDelayMs?: number;
  wrapInTransaction?: boolean;
}




 ... (clipped 29 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Potential Sensitive Data Logging: Template paths and error messages are logged without sanitization, which may inadvertently
expose sensitive information if templates contain sensitive data in filenames or content

Referred Code
 */
private log(
  msg: string,
  logLevel: 'info' | 'warn' | 'error' | 'success' | 'skip' = 'info'
): void {
  if (this.config.silent) return;

  // Simple logging for now - can be enhanced with proper logger
  const prefix = {
    info: '[INFO]',
    warn: '[WARN]',
    error: '[ERROR]',
    success: '[SUCCESS]',
    skip: '[SKIP]',
  }[logLevel];

  console.log(`${prefix} ${msg}`);
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
SQL Injection Risk: SQL execution accepts raw SQL strings without visible parameterization enforcement, which
could lead to SQL injection if not properly handled by callers

Referred Code
/**
 * DatabaseService - Centralized database connection and SQL execution service
 * Handles connection pooling, retry logic, and SQL execution with transaction management
 */

import { EventEmitter } from 'node:events';
import pg from 'pg';
import type { CLIConfig, MigrationError } from '../types.js';
import { logger } from '../utils/logger.js';

export interface DatabaseServiceConfig {
  connectionString: string;
  connectionTimeoutMillis?: number;
  maxConnections?: number;
  idleTimeoutMillis?: number;
  maxUses?: number;
  maxRetries?: number;
  retryDelayMs?: number;
  wrapInTransaction?: boolean;
}




 ... (clipped 29 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-free-for-open-source-projects
Copy link
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix silent failure on corrupted files

Modify the error handling in loadBuildLogs to explicitly check for ENOENT and
report all other errors, including JSON.parse failures, to prevent silently
ignoring corrupted build log files.

src/services/StateService.ts [151-168]

 // Load remote build log
 try {
   const content = await fs.readFile(buildLogPath, 'utf-8');
   this.buildLog = JSON.parse(content);
 } catch (error) {
-  if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
+  if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
+    // File not found is expected, do nothing.
+  } else {
+    // Report any other error, including JSON parsing errors.
     this.emit('error', new Error(`Failed to load build log: ${error}`));
   }
 }
 
 // Load local build log
 try {
   const content = await fs.readFile(localBuildLogPath, 'utf-8');
   this.localBuildLog = JSON.parse(content);
 } catch (error) {
-  if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
+  if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
+    // File not found is expected, do nothing.
+  } else {
+    // Report any other error, including JSON parsing errors.
     this.emit('error', new Error(`Failed to load local build log: ${error}`));
   }
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 8

__

Why: This suggestion identifies a critical flaw where a corrupted build log file would be silently ignored, leading to incorrect application state. The fix ensures all relevant errors are reported.

Medium
Use a robust hash for lock keys

Replace the weak lock key generation, which sums byte values, with a stronger
method using a cryptographic hash to prevent potential collisions for advisory
locks.

src/services/DatabaseService.ts [284-288]

         // Use advisory lock for templates to prevent concurrent modifications
         if (templateName !== 'unknown') {
-          const lockKey = Math.abs(Buffer.from(templateName).reduce((acc, byte) => acc + byte, 0));
-          await client.query(`SELECT pg_advisory_xact_lock(${lockKey}::bigint)`);
+          const hash = crypto.createHash('md5').update(templateName).digest('hex');
+          // Use first 8 hex characters (32 bits) for the lock key
+          const lockKey = parseInt(hash.substring(0, 8), 16);
+          await client.query(`SELECT pg_advisory_xact_lock(${lockKey})`);
         }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a flaw in the advisory lock key generation that could lead to collisions and race conditions, proposing a much more robust hashing mechanism to ensure correctness.

Medium
Correctly resolve user-provided file paths

Resolve user-provided template paths against the current working directory
(process.cwd()) instead of the project root to correctly handle both relative
and absolute paths.

src/commands/register.ts [66-70]

 if (templateArgs?.length) {
-  // Resolve template paths (may be relative)
-  const resolvedPaths = templateArgs.map(t => path.resolve(projectRoot, t));
+  // Resolve template paths, which could be relative to cwd or absolute
+  const resolvedPaths = templateArgs.map(t => path.resolve(process.cwd(), t));
   exitCode = await handleTemplateRegistration(resolvedPaths, orchestrator, projectRoot);
 } else {
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that resolving paths against the project root is less intuitive for users and proposes resolving against the current working directory, which better aligns with standard CLI behavior and improves usability.

Medium
Remove unsafe synchronous dispose implementation

Remove the synchronous [Symbol.dispose] method to prevent unsafe, non-blocking
resource cleanup, enforcing the use of the safer [Symbol.asyncDispose] for all
disposal operations.

src/services/Orchestrator.ts [773-775]

 /**
  * Synchronous dispose for using statement - schedules async cleanup
  * Note: For proper cleanup, prefer await using with Symbol.asyncDispose
  */
-[Symbol.dispose](): void {
-  void this.dispose();
-}
+// [Symbol.dispose] is removed to prevent unsafe, non-blocking cleanup.
+// Consumers should use `await using` with `[Symbol.asyncDispose]`.

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies that the "fire-and-forget" call in [Symbol.dispose] can lead to incomplete resource cleanup, and removing it enforces a safer, purely asynchronous disposal pattern.

Low
Refine glob pattern to prevent ambiguity

Refine the glob pattern to be more specific (/${templateName}.sql) to prevent
incorrect file matches and remove a redundant, unreachable !isWip check.**

src/commands/promote.ts [51-69]

-const pattern = `**/*${templateName}*`;
+const pattern = `**/${templateName}.sql`;
 const matches = await glob(pattern, { cwd: templateDir });
 const isWip = config.wipIndicator && templateName?.includes(config.wipIndicator);
 
 if (matches.length === 0 || !isWip) {
   console.log();
   console.log(
     chalk.red(
       `${figures.cross} No WIP template found matching: ${templateName} in ${config.templateDir}`
     )
   );
   return 1;
 }
 
-if (!isWip) {
-  console.log();
-  console.log(chalk.red(`${figures.cross} Template is not a WIP template: ${templateName}`));
-  return 1;
-}
-
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a broad glob pattern that could lead to ambiguity and removes a redundant, unreachable code block, improving both robustness and code quality.

Low
General
Preserve original error stack trace

In executeApplyTemplate, re-throw the original error object in the catch block
instead of creating a new Error to preserve the full stack trace for easier
debugging.

src/services/Orchestrator.ts [351-371]

 try {
   const result = await this.databaseService.executeMigration(
     content,
     template.name,
     this.config.silent
   );
 
   if (result === true) {
     // StateService (update) - Single source of truth for build logs
     await this.stateService.markAsApplied(templatePath, templateFile.hash);
     return { errors: [], applied: [template.name], skipped: [], built: [] };
   }
 
   // On error, update StateService (single source of truth)
   await this.stateService.markAsError(templatePath, result.error, 'apply');
   return { errors: [result], applied: [], skipped: [], built: [] };
 } catch (error) {
-  const errorMessage = error instanceof Error ? error.message : String(error);
-  throw new Error(errorMessage);
+  throw error;
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that creating a new error discards the stack trace, and re-throwing the original error is a best practice that significantly improves debuggability.

Medium
Prevent multiple cleanup calls on exit

Prevent multiple cleanup calls on exit by removing the keypress listener
immediately after a quit command is detected, ensuring the shutdown logic
executes only once.

src/commands/watch.ts [206-215]

-        process.stdin.on('keypress', (_str, key) => {
+        const keypressHandler = (_str: string, key: { name: string; ctrl: boolean }) => {
           if (key && (key.name === 'q' || (key.ctrl && key.name === 'c'))) {
+            process.stdin.removeListener('keypress', keypressHandler);
             process.stdin.setRawMode(false);
             void cleanup();
-          }
-          if (key && key.name === 'u') {
+          } else if (key && key.name === 'u') {
             showHistory = !showHistory;
             renderScreen(templates, recentUpdates, errors, config.templateDir, showHistory);
           }
-        });
+        };
 
+        process.stdin.on('keypress', keypressHandler);
+
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a potential race condition during shutdown and provides a robust solution by removing the event listener to ensure the cleanup logic runs only once.

Low
Avoid duplicate entries in results

Use a Set to deduplicate the skipped array when merging build and apply results
to prevent showing the same skipped template twice in the final report.

src/commands/build.ts [60-66]

 // Merge results
 result = {
   errors: [...buildResult.errors, ...applyResult.errors],
   applied: applyResult.applied,
   built: buildResult.built,
-  skipped: [...buildResult.skipped, ...applyResult.skipped],
+  skipped: [...new Set([...buildResult.skipped, ...applyResult.skipped])],
 };
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies that skipped items can be duplicated in the final report when using --apply, and the proposed use of Set is an effective way to deduplicate the results, improving the clarity of the output.

Low
  • More

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant