@@ -410,24 +410,42 @@ async function main() {
410410 const toolArg = args . find ( arg => arg . startsWith ( '--tool=' ) ) ;
411411 const targetFolderArg = args . find ( arg => arg . startsWith ( '--targetFolder=' ) ) ;
412412 const homeDirArg = args . find ( arg => arg . startsWith ( '--homeDir=' ) ) ;
413- const isNonInteractive = ! ! toolArg ;
413+ const sddShortcut = args . includes ( '--sdd' ) ;
414+ const isNonInteractive = ! ! toolArg || sddShortcut ;
414415
415416 let tool = toolArg ? toolArg . split ( '=' ) [ 1 ] : null ;
416417 let targetFolder = targetFolderArg ? targetFolderArg . split ( '=' ) [ 1 ] : null ;
417418 let overrideHomeDir = homeDirArg ? homeDirArg . split ( '=' ) [ 1 ] : null ;
418419
420+ // Convenience: allow --sdd without specifying a tool
421+ if ( ! tool && sddShortcut ) {
422+ tool = 'sdd' ;
423+ }
424+
419425 if ( ! tool ) {
420426 const answers = await inquirer . prompt ( [
421427 {
422428 type : 'list' ,
423429 name : 'tool' ,
424430 message : 'Select the tool:' ,
425- choices : Object . keys ( TOOL_CONFIG ) ,
431+ choices : [ ... Object . keys ( TOOL_CONFIG ) , 'sdd' ] ,
426432 } ,
427433 ] ) ;
428434 tool = answers . tool ;
429435 }
430436
437+ // Handle SDD-only installation mode (no rules), copying assets from spec-kit into a project
438+ if ( tool === 'sdd' ) {
439+ // Single, simple path: clone repo then copy assets
440+ const repo = process . env . SPEC_KIT_REPO || 'https://github.com/github/spec-kit.git' ;
441+ const ref = process . env . SPEC_KIT_REF || '' ;
442+ // pick destination
443+ const dest = targetFolder || ( await inquirer . prompt ( [ { type : 'input' , name : 'sddDest' , message : 'Project folder for Spec Kit (SDD) assets:' , validate : ( v ) => ! ! v . trim ( ) || 'Folder name required' } ] ) ) . sddDest ;
444+ const clonePath = await cloneSpecKit ( repo , ref ) ;
445+ await copySpecKitAssets ( clonePath , dest ) ;
446+ return ;
447+ }
448+
431449 const config = TOOL_CONFIG [ tool ] ;
432450
433451 if ( config . copyEntireFolder ) {
@@ -568,4 +586,119 @@ async function main() {
568586main ( ) . catch ( ( err ) => {
569587 console . error ( err ) ;
570588 process . exit ( 1 ) ;
571- } ) ;
589+ } ) ;
590+
591+ // --- Spec Kit integration: clone-on-demand, then copy ---
592+ import { execSync } from 'child_process' ;
593+
594+ async function cloneSpecKit ( repoUrl , ref = '' ) {
595+ const base = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'spec-kit-' ) ) ;
596+ const cloneDir = path . join ( base , 'src' ) ;
597+ showProgress ( `Cloning Spec Kit from ${ repoUrl } ` ) ;
598+ execSync ( `git clone --depth 1 ${ repoUrl } ${ cloneDir } ` , { stdio : 'pipe' } ) ;
599+ if ( ref && ref . trim ( ) ) {
600+ execSync ( `git -C ${ cloneDir } fetch origin ${ ref } --depth 1` , { stdio : 'pipe' } ) ;
601+ execSync ( `git -C ${ cloneDir } checkout ${ ref } ` , { stdio : 'pipe' } ) ;
602+ }
603+ completeProgress ( 'Cloned Spec Kit' ) ;
604+ return cloneDir ;
605+ }
606+ async function copySpecKitAssets ( specKitRoot , projectRoot ) {
607+ const requiredFiles = {
608+ claudeCommands : [
609+ '.claude/commands/specify.md' ,
610+ '.claude/commands/plan.md' ,
611+ '.claude/commands/tasks.md' ,
612+ ] ,
613+ scripts : [
614+ 'scripts/create-new-feature.sh' ,
615+ 'scripts/setup-plan.sh' ,
616+ 'scripts/check-task-prerequisites.sh' ,
617+ 'scripts/common.sh' ,
618+ 'scripts/get-feature-paths.sh' ,
619+ 'scripts/update-agent-context.sh' ,
620+ ] ,
621+ templates : [
622+ 'templates/spec-template.md' ,
623+ 'templates/plan-template.md' ,
624+ 'templates/tasks-template.md' ,
625+ 'templates/agent-file-template.md' ,
626+ ] ,
627+ memory : [
628+ 'memory/constitution.md' ,
629+ ] ,
630+ } ;
631+
632+ const exists = ( p ) => fs . existsSync ( p ) ;
633+ const src = ( rel ) => path . join ( specKitRoot , rel ) ;
634+ const dst = ( rel ) => path . join ( projectRoot , rel ) ;
635+
636+ if ( ! exists ( specKitRoot ) ) {
637+ throw new Error ( `[SDD] Spec Kit path not found: ${ specKitRoot } ` ) ;
638+ }
639+
640+ console . log ( `\n⠋ Installing Spec Kit (SDD) assets from: ${ specKitRoot } ` ) ;
641+
642+ // Ensure directories
643+ const ensureParent = ( p ) => fs . mkdirSync ( path . dirname ( p ) , { recursive : true } ) ;
644+ const copyFileIdempotent = ( from , to , makeExecutable = false ) => {
645+ ensureParent ( to ) ;
646+ if ( exists ( to ) ) {
647+ const a = fs . readFileSync ( from ) ;
648+ const b = fs . readFileSync ( to ) ;
649+ if ( Buffer . compare ( a , b ) === 0 ) {
650+ return 'skipped' ;
651+ }
652+ fs . copyFileSync ( to , `${ to } .bak` ) ;
653+ }
654+ fs . copyFileSync ( from , to ) ;
655+ if ( makeExecutable ) {
656+ try { fs . chmodSync ( to , 0o755 ) ; } catch { }
657+ }
658+ return 'copied' ;
659+ } ;
660+
661+ // Commands
662+ for ( const rel of requiredFiles . claudeCommands ) {
663+ const from = src ( `.${ path . sep } ${ rel . split ( '/' ) . slice ( 1 ) . join ( path . sep ) } ` ) ; // map .claude/commands under spec-kit root
664+ const to = dst ( rel ) ;
665+ if ( ! exists ( from ) ) {
666+ // In spec-kit, commands live at .claude/commands
667+ const alt = src ( rel ) ;
668+ copyFileIdempotent ( exists ( alt ) ? alt : from , to ) ;
669+ } else {
670+ copyFileIdempotent ( from , to ) ;
671+ }
672+ }
673+
674+ // Scripts (executable)
675+ for ( const rel of requiredFiles . scripts ) {
676+ const from = src ( rel ) ;
677+ const to = dst ( rel ) ;
678+ copyFileIdempotent ( from , to , true ) ;
679+ }
680+
681+ // Templates
682+ for ( const rel of requiredFiles . templates ) {
683+ const from = src ( rel ) ;
684+ const to = dst ( rel ) ;
685+ copyFileIdempotent ( from , to ) ;
686+ }
687+
688+ // Memory
689+ for ( const rel of requiredFiles . memory ) {
690+ const from = src ( rel ) ;
691+ const to = dst ( rel ) ;
692+ copyFileIdempotent ( from , to ) ;
693+ }
694+
695+ // Optional quickstart doc (generated)
696+ const quickstartPath = dst ( 'docs/sdd-quickstart.md' ) ;
697+ ensureParent ( quickstartPath ) ;
698+ if ( ! exists ( quickstartPath ) ) {
699+ const qs = `# Spec-Driven Development (SDD) Quickstart\n\n- Requires: Git, bash (macOS/Linux/WSL).\n- Commands live in \`.claude/commands\` for Claude Code.\n\nWorkflow:\n- /specify → creates branch + \`specs/###-.../spec.md\`\n- /plan → fills \`plan.md\` and generates research/data model/contracts/quickstart\n- /tasks → creates \`tasks.md\` from available docs\n\nRun manually (if needed):\n- \`bash scripts/create-new-feature.sh --json \"My feature\"\`\n- \`bash scripts/setup-plan.sh --json\` (must be on feature branch)\n- \`bash scripts/check-task-prerequisites.sh --json\`\n\nBranch rule: must match \`^[0-9]{3}-\` for /plan and /tasks.\n` ;
700+ fs . writeFileSync ( quickstartPath , qs ) ;
701+ }
702+
703+ console . log ( '\x1b[32m✓ Installed Spec Kit assets\x1b[0m' ) ;
704+ }
0 commit comments