@@ -14,6 +14,16 @@ const INIT = path.join(ROOT, 'src', 'tools', 'caveman-init.js');
1414let passed = 0 ;
1515let failed = 0 ;
1616
17+ // Point OPENCLAW_WORKSPACE at a nonexistent dir inside the fixture so the
18+ // openclaw target reports skipped-workspace-missing instead of writing to
19+ // the developer's real ~/.openclaw/workspace.
20+ function runInit ( tmp , ...args ) {
21+ return execFileSync ( process . execPath , [ INIT , tmp , ...args ] , {
22+ encoding : 'utf8' ,
23+ env : { ...process . env , OPENCLAW_WORKSPACE : path . join ( tmp , 'no-openclaw' ) } ,
24+ } ) ;
25+ }
26+
1727function test ( name , fn ) {
1828 const tmp = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'caveman-init-test-' ) ) ;
1929 try {
@@ -31,7 +41,7 @@ function test(name, fn) {
3141console . log ( 'caveman-init tests\n' ) ;
3242
3343test ( 'greenfield: creates all rule files with proper frontmatter' , ( tmp ) => {
34- execFileSync ( process . execPath , [ INIT , tmp ] , { encoding : 'utf8' } ) ;
44+ runInit ( tmp ) ;
3545 const cursor = fs . readFileSync ( path . join ( tmp , '.cursor/rules/caveman.mdc' ) , 'utf8' ) ;
3646 assert . match ( cursor , / a l w a y s A p p l y : t r u e / ) ;
3747 assert . match ( cursor , / R e s p o n d t e r s e l i k e s m a r t c a v e m a n / ) ;
@@ -43,18 +53,21 @@ test('greenfield: creates all rule files with proper frontmatter', (tmp) => {
4353 assert . match ( copilot , / R e s p o n d t e r s e / ) ;
4454 const agents = fs . readFileSync ( path . join ( tmp , 'AGENTS.md' ) , 'utf8' ) ;
4555 assert . match ( agents , / R e s p o n d t e r s e / ) ;
56+ const opencode = fs . readFileSync ( path . join ( tmp , '.opencode/AGENTS.md' ) , 'utf8' ) ;
57+ assert . match ( opencode , / R e s p o n d t e r s e / ) ;
4658} ) ;
4759
4860test ( 'idempotent: re-running on a clean install skips all' , ( tmp ) => {
49- execFileSync ( process . execPath , [ INIT , tmp ] , { encoding : 'utf8' } ) ;
50- const out = execFileSync ( process . execPath , [ INIT , tmp ] , { encoding : 'utf8' } ) ;
51- assert . match ( out , / 5 s k i p p e d / ) ;
61+ runInit ( tmp ) ;
62+ const out = runInit ( tmp ) ;
63+ // 6 repo rule files skipped-already-installed + openclaw skipped (no workspace)
64+ assert . match ( out , / 7 s k i p p e d / ) ;
5265 assert . doesNotMatch ( out , / [ 1 - 9 ] \d * a d d e d / ) ;
5366} ) ;
5467
5568test ( 'append mode: existing AGENTS.md gets caveman appended (not replaced)' , ( tmp ) => {
5669 fs . writeFileSync ( path . join ( tmp , 'AGENTS.md' ) , '# My project\n\nDo not delete me.\n' ) ;
57- execFileSync ( process . execPath , [ INIT , tmp ] , { encoding : 'utf8' } ) ;
70+ runInit ( tmp ) ;
5871 const agents = fs . readFileSync ( path . join ( tmp , 'AGENTS.md' ) , 'utf8' ) ;
5972 assert . match ( agents , / D o n o t d e l e t e m e / ) ;
6073 assert . match ( agents , / R e s p o n d t e r s e l i k e s m a r t c a v e m a n / ) ;
@@ -64,7 +77,7 @@ test('skip mode: existing .cursor rule is not overwritten without --force', (tmp
6477 const dir = path . join ( tmp , '.cursor/rules' ) ;
6578 fs . mkdirSync ( dir , { recursive : true } ) ;
6679 fs . writeFileSync ( path . join ( dir , 'caveman.mdc' ) , '# original\nDo not delete me.\n' ) ;
67- const out = execFileSync ( process . execPath , [ INIT , tmp ] , { encoding : 'utf8' } ) ;
80+ const out = runInit ( tmp ) ;
6881 assert . match ( out , / \? .* \. c u r s o r \/ r u l e s \/ c a v e m a n \. m d c / ) ;
6982 const after = fs . readFileSync ( path . join ( dir , 'caveman.mdc' ) , 'utf8' ) ;
7083 assert . strictEqual ( after , '# original\nDo not delete me.\n' ) ;
@@ -74,25 +87,26 @@ test('--force overwrites existing rule files', (tmp) => {
7487 const dir = path . join ( tmp , '.cursor/rules' ) ;
7588 fs . mkdirSync ( dir , { recursive : true } ) ;
7689 fs . writeFileSync ( path . join ( dir , 'caveman.mdc' ) , '# original\n' ) ;
77- execFileSync ( process . execPath , [ INIT , tmp , '--force' ] , { encoding : 'utf8' } ) ;
90+ runInit ( tmp , '--force' ) ;
7891 const after = fs . readFileSync ( path . join ( dir , 'caveman.mdc' ) , 'utf8' ) ;
7992 assert . match ( after , / a l w a y s A p p l y : t r u e / ) ;
8093 assert . match ( after , / R e s p o n d t e r s e / ) ;
8194} ) ;
8295
8396test ( '--dry-run: announces but writes nothing' , ( tmp ) => {
84- const out = execFileSync ( process . execPath , [ INIT , tmp , '--dry-run' ] , { encoding : 'utf8' } ) ;
97+ const out = runInit ( tmp , '--dry-run' ) ;
8598 assert . match ( out , / \( d r y r u n \) / ) ;
86- assert . match ( out , / 5 a d d e d / ) ;
99+ assert . match ( out , / 6 a d d e d / ) ;
87100 assert . ok ( ! fs . existsSync ( path . join ( tmp , '.cursor' ) ) ) ;
88101 assert . ok ( ! fs . existsSync ( path . join ( tmp , '.windsurf' ) ) ) ;
89102 assert . ok ( ! fs . existsSync ( path . join ( tmp , '.clinerules' ) ) ) ;
90103 assert . ok ( ! fs . existsSync ( path . join ( tmp , '.github/copilot-instructions.md' ) ) ) ;
104+ assert . ok ( ! fs . existsSync ( path . join ( tmp , '.opencode' ) ) ) ;
91105 assert . ok ( ! fs . existsSync ( path . join ( tmp , 'AGENTS.md' ) ) ) ;
92106} ) ;
93107
94108test ( '--only filters to one target' , ( tmp ) => {
95- const out = execFileSync ( process . execPath , [ INIT , tmp , '--only' , 'cline' ] , { encoding : 'utf8' } ) ;
109+ const out = runInit ( tmp , '--only' , 'cline' ) ;
96110 assert . match ( out , / 1 a d d e d / ) ;
97111 assert . ok ( fs . existsSync ( path . join ( tmp , '.clinerules/caveman.md' ) ) ) ;
98112 assert . ok ( ! fs . existsSync ( path . join ( tmp , '.cursor' ) ) ) ;
@@ -104,7 +118,7 @@ test('detects sentinel and skips files that already have caveman content', (tmp)
104118 fs . mkdirSync ( dir , { recursive : true } ) ;
105119 fs . writeFileSync ( path . join ( dir , 'caveman.md' ) ,
106120 '# Existing\n\nRespond terse like smart caveman. Hello.\n' ) ;
107- const out = execFileSync ( process . execPath , [ INIT , tmp , '--only' , 'cline' ] , { encoding : 'utf8' } ) ;
121+ const out = runInit ( tmp , '--only' , 'cline' ) ;
108122 assert . match ( out , / s k i p p e d - a l r e a d y - i n s t a l l e d / ) ;
109123} ) ;
110124
0 commit comments