feat(init): add SCM selection with Sapling and GitHub support#196
feat(init): add SCM selection with Sapling and GitHub support#196
Conversation
Add planning documents for extending the init flow to support source control type selection (GitHub/Git and Sapling+Phabricator): - Research doc analyzing current command architecture and SCM usage - Technical design spec with detailed implementation plan - Sapling SCM reference guide with Git command mappings Assistant-model: Claude Code
Add support for multiple source control systems (GitHub/Git and Sapling+Phabricator) as part of the source control type selection feature. Changes: - Add SourceControlType union type for supported SCM systems - Add ScmConfig interface with fields for CLI tools, review systems, etc. - Add SCM_CONFIG constant with GitHub and Sapling+Phabricator configurations - Add helper functions: getScmKeys(), isValidScm(), getScmConfig() - Add comprehensive unit tests for all SCM configuration functions This lays the foundation for SCM-aware command file copying during atomic init, enabling users to select their preferred source control workflow. Assistant-model: Claude Code
Update the technical design document with refined implementation details and clarifications for the SCM type selection feature. Assistant-model: Claude Code
Add utilities for persisting project configuration in .atomic.json file. This enables storing the user's SCM selection for use by Ralph workflow and future re-initialization. Changes: - Add AtomicConfig interface with version, agent, scm, and lastUpdated fields - Add readAtomicConfig() to read config from project directory - Add saveAtomicConfig() to merge updates with existing config - Add getSelectedScm() convenience function for SCM lookup - Add comprehensive unit tests with temp directory isolation The .atomic.json file will store project-level settings after init, allowing SCM-aware features to determine the user's source control choice. Assistant-model: Claude Code
Add template directory structure with command files for GitHub and Sapling+Phabricator source control systems. Templates added: - templates/scm/github/ - Git/GitHub commands (commit.md, create-gh-pr.md) - templates/scm/sapling-phabricator/ - Sapling commands (commit.md, submit-diff.md) - templates/scm/sapling-phabricator-windows/ - Windows-specific Sapling templates with full sl.exe path to avoid PowerShell alias conflict Each SCM template includes: - .claude/commands/ - Claude Code command files - .opencode/command/ - OpenCode command files - .github/skills/ - GitHub Copilot skill files with full content The init flow will copy appropriate templates based on user's SCM selection. Assistant-model: Claude Code
Extend the atomic init command to support source control system selection. Users can now choose between GitHub/Git and Sapling+Phabricator workflows. Changes: - Add preSelectedScm option to InitOptions interface - Add getScmTemplatePath() to resolve OS-specific templates (Windows handling) - Add getCommandsSubfolder() to map agent types to command folder names - Add copyScmCommands() to copy SCM-specific command files - Add SCM selection prompt after agent selection in init flow - Save SCM selection to .atomic.json for future reference - Add Phabricator .arcconfig validation warning when Sapling is selected - Add -s/--scm CLI flag for non-interactive SCM selection The init flow now: 1. Selects agent (claude/opencode/copilot) 2. Selects SCM (github/sapling-phabricator) 3. Copies agent config files 4. Copies SCM-specific command files 5. Saves selection to .atomic.json Assistant-model: Claude Code
Parameterize buildImplementFeaturePrompt with SourceControlType so ralph uses the correct history and commit commands for the selected SCM (git log vs sl smartlog, /commit with git vs sl). workflow-commands reads the SCM choice from .atomic.json at runtime. Assistant-model: Claude Code
Add isValidScm guard in the init action so invalid --scm values are rejected with a clear error before the init flow starts. Includes SCM validation tests and comprehensive init SCM flow tests. Assistant-model: Claude Code
Document the source control selection flow during atomic init, Sapling + Phabricator setup steps, and the .atomic.json config file schema. Assistant-model: Claude Code
PR Review: feat: add Sapling SCM integration with SCM selection flowOverall AssessmentThis is a well-structured PR that adds Sapling SCM (Source Control Management) integration with a clean selection flow during ✅ Strengths1. Clean Architecture
2. Comprehensive Test Coverage
3. Windows Support
4. SCM-Aware Workflow
🔶 Suggestions for Improvement1. Type Safety Enhancement ( preSelectedScm: localOpts.scm as SourceControlType | undefined,Consider using a type guard validation instead of direct casting. The validation happens earlier at line 91, but the cast feels fragile if code order changes. 2. Config File Location Inconsistency 3. Error Handling in try {
const content = await readFile(configPath, "utf-8");
return JSON.parse(content) as AtomicConfig;
} catch {
return null;
}Silent error handling is fine for missing files, but parsing errors could benefit from logging in DEBUG mode to help users diagnose malformed config files. 4. Template Duplication 5. SCM Detection for Auto-Init ( 🟡 Minor Issues1. Progress.txt File 2. Documentation Placement
Consider consolidating or clarifying the distinction between these. 3. Unused Constant ( export const SCM_SPECIFIC_COMMANDS = ["commit"];This constant is exported but only used in tests. If it's intended for future use, that's fine, but consider adding a comment explaining its purpose. 🔒 Security Considerations
📋 Test Plan VerificationThe test plan items in the PR description are well-covered:
VerdictApprove - This is a solid implementation with good architecture and test coverage. The suggestions above are mostly minor improvements that could be addressed in follow-up PRs. The PR adds valuable functionality for teams using Sapling + Phabricator workflows while maintaining backward compatibility for GitHub/Git users. |
There was a problem hiding this comment.
Pull request overview
This PR adds comprehensive Source Control Management (SCM) selection to the Atomic CLI, enabling users to choose between Git/GitHub and Sapling/Phabricator workflows during initialization. The feature introduces SCM-aware command templates, configuration persistence, and platform-specific support (including Windows-specific Sapling templates to handle PowerShell alias conflicts).
Changes:
- Added SCM configuration system with support for GitHub/Git and Sapling+Phabricator
- Implemented
.atomic.jsonconfig file for persisting SCM and agent selections - Created SCM-specific command templates for all supported agents (Claude, OpenCode, Copilot)
- Updated Ralph workflow to use SCM-aware prompts based on configured SCM type
- Added comprehensive test coverage for SCM configuration and persistence
Reviewed changes
Copilot reviewed 36 out of 36 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| src/config.ts | Added SCM type definitions, configurations, and helper functions |
| src/utils/atomic-config.ts | New module for reading/writing .atomic.json configuration |
| src/cli.ts | Added --scm flag to init command with validation |
| src/commands/init.ts | Integrated SCM selection prompt and template copying logic |
| src/graph/nodes/ralph-nodes.ts | Made implement-feature prompts SCM-aware (git log vs sl smartlog) |
| src/ui/commands/workflow-commands.ts | Updated Ralph workflow to read SCM from config |
| templates/scm/github/*.md | GitHub/Git command templates for all agents |
| templates/scm/sapling-phabricator/*.md | Sapling+Phabricator templates for Unix/macOS |
| templates/scm/sapling-phabricator-windows/*.md | Windows-specific templates using full sl.exe paths |
| tests/**/*.test.ts | Comprehensive unit and integration tests |
| README.md | Documentation for SCM selection and configuration |
| specs/source-control-type-selection.md | Complete technical specification |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const preSelectedScm = "sapling-phabricator" as const; | ||
|
|
||
| let scmType: string; | ||
| let shouldCallSelect = true; |
There was a problem hiding this comment.
The initial value of shouldCallSelect is unused, since it is always overwritten.
|
|
||
| describe("SCM_CONFIG", () => { | ||
| test("all SCMs have required name field", () => { | ||
| for (const [key, config] of Object.entries(SCM_CONFIG)) { |
There was a problem hiding this comment.
Unused variable key.
| }); | ||
|
|
||
| test("all SCMs have required displayName field", () => { | ||
| for (const [key, config] of Object.entries(SCM_CONFIG)) { |
There was a problem hiding this comment.
Unused variable key.
| }); | ||
|
|
||
| test("all SCMs have required cliTool field", () => { | ||
| for (const [key, config] of Object.entries(SCM_CONFIG)) { |
There was a problem hiding this comment.
Unused variable key.
| }); | ||
|
|
||
| test("all SCMs have required reviewTool field", () => { | ||
| for (const [key, config] of Object.entries(SCM_CONFIG)) { |
There was a problem hiding this comment.
Unused variable key.
| }); | ||
|
|
||
| test("all SCMs have required reviewCommandFile field", () => { | ||
| for (const [key, config] of Object.entries(SCM_CONFIG)) { |
There was a problem hiding this comment.
Unused variable key.
| */ | ||
|
|
||
| import { test, expect, describe, beforeEach, afterEach } from "bun:test"; | ||
| import { test, expect, describe, beforeEach, afterEach, mock, spyOn } from "bun:test"; |
There was a problem hiding this comment.
Unused imports mock, spyOn.
| @@ -0,0 +1,156 @@ | |||
| import { test, expect, describe, beforeEach, afterEach } from "bun:test"; | |||
| import { mkdtemp, rm, readFile, writeFile, mkdir } from "fs/promises"; | |||
There was a problem hiding this comment.
Unused import mkdir.
| const scmType = "github"; | ||
| const isWindowsPlatform = false; | ||
|
|
||
| const templatePath = scmType === "sapling-phabricator" && isWindowsPlatform |
There was a problem hiding this comment.
This expression always evaluates to false.
| const scmType = "sapling-phabricator"; | ||
| const isWindowsPlatform = false; | ||
|
|
||
| const templatePath = scmType === "sapling-phabricator" && isWindowsPlatform |
There was a problem hiding this comment.
This expression always evaluates to false.
- Fix SDK event handling with proper type assertions for dynamic event data - Add type-safe clipboard method calls in UI components - Update subagent tests to use spawnRecords instead of sentMessages - Configure opus model for codebase analysis and debugging agents - Fix annotation and init test type annotations Assistant-model: Claude Code
|
Claude finished @flora131's task in 20s —— View job Hello! 👋
I noticed you mentioned me, but I didn't see a specific request in your comment. I can help you with:
Just let me know what you'd like me to do! For example:
|
PR Review: feat(init): add SCM selection with Sapling and GitHub supportOverviewThis is a substantial PR that adds source control management (SCM) selection to the 👍 StrengthsArchitecture & Design
Code Quality
Test Coverage
🔧 Suggestions for Improvement1. Type Casting in
|
Summary
Adds source control management (SCM) selection to the init flow, enabling users to choose between GitHub/Git and Sapling/Phabricator workflows. The selected SCM type is persisted in
.atomic.jsonand configures SCM-specific commands throughout the application.Key Changes
Core Features
atomic initwith support for GitHub/Git and Sapling/Phabricator--scmparameter on init command.atomic.jsonfile in project rootImplementation Details
SCM_CONFIGinsrc/config.tswith metadata for each SCM type (display name, CLI tools, review systems)src/utils/atomic-config.tsfor reading/writing.atomic.jsonconfigurationsrc/commands/init.tsto:--scmflag)slalias conflict).arcconfigpresence for Phabricator workflowssrc/graph/nodes/ralph-nodes.ts) to use SCM-appropriate:git logvssl smartlog)/commitwith appropriate tool)src/ui/commands/workflow-commands.tsto read SCM config and pass to promptsTemplates
Added SCM-specific command templates for all three agents (Claude, OpenCode, Copilot):
GitHub/Git:
/commit→ usesgit commit/create-gh-pr→ usesgh pr createSapling/Phabricator:
/commit→ usessl commit/submit-diff→ usesjf submitfor Phabricator diffsWindows variant: Sapling templates use full path
& 'C:\Program Files\Sapling\sl.exe'to avoid PowerShell alias conflictsDocumentation
.atomic.jsonconfiguration referenceTest Coverage
--scmparameterConfiguration File
The new
.atomic.jsonfile stores:{ "version": 1, "agent": "claude", "scm": "github", "lastUpdated": "2026-02-13T..." }Breaking Changes
None. Existing projects without
.atomic.jsondefault to GitHub/Git workflow.