thachvd-kit 1.0.19 → 1.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.js CHANGED
@@ -136,9 +136,10 @@ ${pc.bold('Options:')}
136
136
  --help Show this help message
137
137
 
138
138
  ${pc.bold('What gets generated:')}
139
- AGENTS.md Shared instructions for Codex, Antigravity, and Claude Code
139
+ AGENTS.md Shared instructions for Codex, Antigravity, Claude Code, and Cursor
140
140
  CLAUDE.md Claude Code entry file that imports AGENTS.md
141
141
  GEMINI.md Antigravity entry file that points to AGENTS.md
142
+ .cursorrules Cursor entry file that points to AGENTS.md
142
143
  .agent/ Shared docs, skills, workflows, agents, and rules
143
144
  ~/.codex/skills/ Selected Codex skills copied to global user dir (shows in $ menu)
144
145
  .claude/skills/ Selected Claude Code project skills copied from .agent/skills
@@ -885,33 +886,31 @@ function resolveAgentTable(data) {
885
886
  rows.push(["Debug", "debugger", "systematic-debugging"]);
886
887
  rows.push(["Security", "security-auditor", "vulnerability-scanner"]);
887
888
  rows.push(["Planning", "project-planner", "brainstorming, plan-writing"]);
888
-
889
- return rows;
890
- }
891
-
892
- // --- File Generators ---
893
-
894
- function generateSharedAgentsMd(data) {
895
- return `# AGENTS.md
896
-
897
- Shared operating instructions for Codex, Antigravity, and Claude Code.
898
-
899
- ## Startup
900
-
901
- 1. Read this file first.
902
- 2. Read \`.agent/docs/project.md\` for detected stack, commands, and routing.
889
+
903
890
  return rows;
891
+ }
892
+ // --- File Generators ---
893
+
894
+ function generateSharedAgentsMd(data) {
895
+ return `# AGENTS.md
896
+
897
+ Shared operating instructions for Codex, Antigravity, Claude Code, and Cursor.
898
+
899
+ ## Startup
900
+
901
+ 1. Read this file first.
902
+ 2. Read \`.agent/docs/project.md\` for detected stack, commands, and routing.
904
903
  3. Read \`.agent/docs/workflow.md\` for the task flow before editing.
905
904
  4. Read \`.agent/docs/architecture.md\` and \`.agent/docs/conventions.md\` before planning code changes.
906
905
  5. Read \`.agent/docs/tooling.md\` when the task needs Playwright, codegraph, MCP, or native Codex/Claude skill setup.
907
906
  6. Select and load only the agent, skill, or workflow files that match the current task.
908
-
909
- If any \`.agent/docs/*.md\` file still contains \`TODO: refine\`, update the docs by scanning the project before making product code changes.
910
-
911
- ## Task Flow
912
-
913
- - Questions and analysis: answer directly, cite relevant files when useful, and do not edit code.
914
- - Simple fix: inspect dependencies, make the smallest change, run focused verification.
915
- - Feature or refactor: define success criteria, make a short plan, implement, then verify.
907
+
908
+ If any \`.agent/docs/*.md\` file still contains \`TODO: refine\`, update the docs by scanning the project before making product code changes.
909
+
910
+ ## Task Flow
911
+
912
+ - Questions and analysis: answer directly, cite relevant files when useful, and do not edit code.
913
+ - Simple fix: inspect dependencies, make the smallest change, run focused verification.
914
+ - Feature or refactor: define success criteria, make a short plan, implement, then verify.
916
915
  - Multi-domain work: use \`.agent/workflows/orchestrate.md\` and route to the relevant specialist docs.
917
916
  - UI work: read \`.agent/agents/frontend-specialist.md\` and applicable design skills before editing.
918
917
 
@@ -927,16 +926,16 @@ If any \`.agent/docs/*.md\` file still contains \`TODO: refine\`, update the doc
927
926
  - When creating or improving skills, use \`writing-skills\` first and make the \`description\` field specific enough for implicit invocation.
928
927
 
929
928
  ## Rules
930
-
931
- - Respond in the user's language; keep code, identifiers, and code comments in English.
932
- - State assumptions when the request is ambiguous.
933
- - Prefer the existing project style over new abstractions.
934
- - Keep changes surgical and remove only dead code introduced by your change.
935
- - Tests or equivalent verification are mandatory before claiming done.
936
- - Keep files under ${data.max_file_lines || '300'} lines unless the project already has a different standard in \`.agent/docs/conventions.md\`.
937
-
938
- ## Shared Knowledge
939
-
929
+
930
+ - Respond in the user's language; keep code, identifiers, and code comments in English.
931
+ - State assumptions when the request is ambiguous.
932
+ - Prefer the existing project style over new abstractions.
933
+ - Keep changes surgical and remove only dead code introduced by your change.
934
+ - Tests or equivalent verification are mandatory before claiming done.
935
+ - Keep files under ${data.max_file_lines || '300'} lines unless the project already has a different standard in \`.agent/docs/conventions.md\`.
936
+
937
+ ## Shared Knowledge
938
+
940
939
  - Project docs: \`.agent/docs/\`
941
940
  - Specialist agents: \`.agent/agents/\`
942
941
  - Skills: \`.agent/skills/\`
@@ -945,180 +944,190 @@ If any \`.agent/docs/*.md\` file still contains \`TODO: refine\`, update the doc
945
944
  - Workflows: \`.agent/workflows/\`
946
945
  - Tooling setup: \`.agent/docs/tooling.md\`
947
946
  - Antigravity mirror rules: \`.agent/rules/GEMINI.md\`
947
+ - Cursor entry rules: \`.cursorrules\`
948
948
  `;
949
949
  }
950
-
951
- function generateSharedClaudeMd() {
952
- return `@AGENTS.md
953
-
954
- ## Claude Code
955
-
956
- This repository uses AGENTS.md as the shared cross-agent entry file. Follow the imported instructions and keep Claude-specific notes here only when they cannot apply to Codex or Antigravity.
957
- `;
958
- }
959
-
960
- function generateSharedGeminiMd() {
961
- return `# GEMINI.md
962
-
963
- Antigravity entry file for this project.
964
-
965
- Read AGENTS.md first, then follow the shared docs under .agent/docs/.
966
- `;
967
- }
968
-
969
- function resolveCommands(data) {
970
- const frameworks = data.frameworks || [];
971
- const primaryLang = data.primary_language || 'javascript';
972
- const pkgManager = data.package_manager || 'npm';
973
- const testFramework = data.test_framework || 'auto-detect';
974
-
975
- const isPython = primaryLang === 'python';
976
- const isGo = primaryLang === 'go';
977
- const isRust = primaryLang === 'rust';
978
- const isPhp = primaryLang === 'php';
979
-
980
- let install = 'npm install';
981
- let dev = 'npm run dev';
982
- let build = 'npm run build';
983
- let test = 'npm test';
984
- let lint = 'npm run lint';
985
-
986
- if (pkgManager === 'pnpm') { install = 'pnpm install'; dev = 'pnpm dev'; build = 'pnpm build'; test = 'pnpm test'; lint = 'pnpm lint'; }
987
- else if (pkgManager === 'yarn') { install = 'yarn'; dev = 'yarn dev'; build = 'yarn build'; test = 'yarn test'; lint = 'yarn lint'; }
988
- else if (pkgManager === 'bun') { install = 'bun install'; dev = 'bun dev'; build = 'bun run build'; test = 'bun test'; lint = 'bun run lint'; }
989
- else if (isPython) { install = 'pip install -r requirements.txt'; dev = 'python manage.py runserver'; build = '# no build step'; test = 'pytest'; lint = 'ruff check .'; }
990
- else if (isGo) { install = 'go mod download'; dev = 'go run .'; build = 'go build ./...'; test = 'go test ./...'; lint = 'golangci-lint run'; }
991
- else if (isRust) { install = 'cargo build'; dev = 'cargo run'; build = 'cargo build --release'; test = 'cargo test'; lint = 'cargo clippy'; }
992
- else if (isPhp) {
993
- install = 'composer install';
994
- build = '# no build step';
995
- test = testFramework === 'pest' ? './vendor/bin/pest' : './vendor/bin/phpunit';
996
- const isCakePHP = frameworks.some(f => f.toLowerCase().includes('cakephp'));
997
- const isSymfony = frameworks.some(f => f.toLowerCase().includes('symfony'));
998
- const isCodeIgniter = frameworks.some(f => f.toLowerCase().includes('codeigniter'));
999
- if (isCakePHP) {
1000
- dev = 'bin/cake server';
1001
- lint = './vendor/bin/phpcs';
1002
- } else if (isSymfony) {
1003
- dev = 'bin/console server:run';
1004
- lint = './vendor/bin/phpcs';
1005
- } else if (isCodeIgniter) {
1006
- dev = 'php spark serve';
1007
- lint = './vendor/bin/phpcs';
1008
- } else {
1009
- dev = 'php artisan serve';
1010
- lint = 'php artisan pint';
1011
- }
1012
- }
1013
-
1014
- if (testFramework === 'vitest') test = `${pkgManager === 'pnpm' ? 'pnpm' : pkgManager === 'yarn' ? 'yarn' : pkgManager === 'bun' ? 'bun run' : 'npx'} vitest`;
1015
- else if (testFramework === 'jest') test = `${pkgManager === 'pnpm' ? 'pnpm' : pkgManager === 'yarn' ? 'yarn' : 'npx'} jest`;
1016
-
1017
- return { install, dev, build, test, lint };
1018
- }
1019
-
1020
- function generateProjectDoc(data) {
1021
- const commands = resolveCommands(data);
1022
- const agentRows = resolveAgentTable(data).map(([task, agent, skills]) => `| ${task} | \`${agent}\` | ${skills} |`).join('\n');
1023
- const skillsList = resolveSkills(data).map(s => `- ${s}`).join('\n');
1024
- const evidence = (data.scan_evidence || []).length > 0
1025
- ? (data.scan_evidence || []).map(line => `- ${line}`).join('\n')
1026
- : '- TODO: refine scan evidence by inspecting the project.';
1027
-
1028
- return `# Project Rules
1029
-
1030
- Generated by thachvd-kit on ${new Date().toISOString().split('T')[0]}.
1031
-
1032
- ## Summary
1033
-
1034
- - Name: ${data.project_name}
1035
- - Description: ${data.description}
1036
- - Type: ${data.project_type}
1037
- - App root: ${data.app_root || '.'}
1038
-
1039
- ## Stack
1040
-
1041
- - Language: ${data.primary_language}
1042
- - Frameworks: ${(data.frameworks || []).join(', ') || 'none'}
1043
- - Database: ${data.database || 'none'}
1044
- - Infrastructure: ${(data.infrastructure || []).join(', ') || 'none'}
1045
- - Package manager: ${data.package_manager || 'auto-detect'}
1046
- - Test framework: ${data.test_framework || 'auto-detect'}
1047
-
1048
- ## Commands
1049
-
1050
- - Install: \`${commands.install}\`
1051
- - Dev: \`${commands.dev}\`
1052
- - Build: \`${commands.build}\`
1053
- - Test: \`${commands.test}\`
1054
- - Lint: \`${commands.lint}\`
1055
-
1056
- ## Agent Routing
1057
-
1058
- | Task Type | Agent | Primary Skills |
1059
- |-----------|-------|----------------|
1060
- ${agentRows}
1061
-
1062
- ## Auto-Resolved Skills
1063
-
1064
- ${skillsList}
1065
-
1066
- ## Scan Evidence
1067
-
1068
- ${evidence}
1069
- `;
1070
- }
1071
-
1072
- function generateArchitectureDoc(data) {
1073
- const appRootLine = data.app_root && data.app_root !== '.'
1074
- ? `- App root is currently detected as \`${data.app_root}\`.`
1075
- : '- App root is the repository root unless refined below.';
1076
- const evidence = (data.scan_evidence || []).length > 0
1077
- ? (data.scan_evidence || []).map(line => `- ${line}`).join('\n')
1078
- : '- TODO: refine architecture by scanning source directories.';
1079
-
1080
- return `# Architecture Notes
1081
-
1082
- ## Current Map
1083
-
1084
- ${appRootLine}
1085
- - TODO: refine major directories and responsibilities.
1086
- - TODO: refine main entry points, routing, state boundaries, and integration boundaries.
1087
-
1088
- ## Detected Evidence
1089
-
1090
- ${evidence}
1091
-
1092
- ## AI Maintenance Rule
1093
-
1094
- Before non-trivial implementation work, inspect this file. If it is stale or still contains TODO items relevant to the task, update it from the code before editing product code.
1095
- `;
1096
- }
1097
-
1098
- function generateConventionsDoc(data) {
1099
- return `# Coding Conventions
1100
-
1101
- ## Current Standards
1102
-
1103
- - Maximum file length: ${data.max_file_lines || '300'} lines unless the existing project standard is stricter.
1104
- - Code comments and identifiers should be written in English.
1105
- - Keep changes scoped to the user request.
1106
- - Prefer existing local patterns over introducing new abstractions.
1107
- - TODO: refine naming, formatting, folder, API, state, styling, and testing conventions from the real codebase.
1108
-
1109
- ## Verification
1110
-
1111
- - Run the focused test or lint command that matches the touched area.
1112
- - If no automated check exists, document the manual verification performed.
1113
- - Do not claim completion without verification evidence.
1114
- `;
1115
- }
1116
-
950
+
951
+ function generateSharedClaudeMd() {
952
+ return `@AGENTS.md
953
+
954
+ ## Claude Code
955
+
956
+ This repository uses AGENTS.md as the shared cross-agent entry file. Follow the imported instructions and keep Claude-specific notes here only when they cannot apply to Codex or Antigravity.
957
+ `;
958
+ }
959
+
960
+ function generateSharedGeminiMd() {
961
+ return `# GEMINI.md
962
+
963
+ Antigravity entry file for this project.
964
+
965
+ Read AGENTS.md first, then follow the shared docs under .agent/docs/.
966
+ `;
967
+ }
968
+
969
+ function generateSharedCursorrules() {
970
+ return `# Cursor Rules
971
+
972
+ This repository uses AGENTS.md as the shared cross-agent entry file. Follow the instructions in AGENTS.md and keep Cursor-specific notes here only when they cannot apply to Codex, Antigravity, or Claude Code.
973
+
974
+ Read AGENTS.md first, then follow the shared docs under .agent/docs/.
975
+ `;
976
+ }
977
+
978
+ function resolveCommands(data) {
979
+ const frameworks = data.frameworks || [];
980
+ const primaryLang = data.primary_language || 'javascript';
981
+ const pkgManager = data.package_manager || 'npm';
982
+ const testFramework = data.test_framework || 'auto-detect';
983
+
984
+ const isPython = primaryLang === 'python';
985
+ const isGo = primaryLang === 'go';
986
+ const isRust = primaryLang === 'rust';
987
+ const isPhp = primaryLang === 'php';
988
+
989
+ let install = 'npm install';
990
+ let dev = 'npm run dev';
991
+ let build = 'npm run build';
992
+ let test = 'npm test';
993
+ let lint = 'npm run lint';
994
+
995
+ if (pkgManager === 'pnpm') { install = 'pnpm install'; dev = 'pnpm dev'; build = 'pnpm build'; test = 'pnpm test'; lint = 'pnpm lint'; }
996
+ else if (pkgManager === 'yarn') { install = 'yarn'; dev = 'yarn dev'; build = 'yarn build'; test = 'yarn test'; lint = 'yarn lint'; }
997
+ else if (pkgManager === 'bun') { install = 'bun install'; dev = 'bun dev'; build = 'bun run build'; test = 'bun test'; lint = 'bun run lint'; }
998
+ else if (isPython) { install = 'pip install -r requirements.txt'; dev = 'python manage.py runserver'; build = '# no build step'; test = 'pytest'; lint = 'ruff check .'; }
999
+ else if (isGo) { install = 'go mod download'; dev = 'go run .'; build = 'go build ./...'; test = 'go test ./...'; lint = 'golangci-lint run'; }
1000
+ else if (isRust) { install = 'cargo build'; dev = 'cargo run'; build = 'cargo build --release'; test = 'cargo test'; lint = 'cargo clippy'; }
1001
+ else if (isPhp) {
1002
+ install = 'composer install';
1003
+ build = '# no build step';
1004
+ test = testFramework === 'pest' ? './vendor/bin/pest' : './vendor/bin/phpunit';
1005
+ const isCakePHP = frameworks.some(f => f.toLowerCase().includes('cakephp'));
1006
+ const isSymfony = frameworks.some(f => f.toLowerCase().includes('symfony'));
1007
+ const isCodeIgniter = frameworks.some(f => f.toLowerCase().includes('codeigniter'));
1008
+ if (isCakePHP) {
1009
+ dev = 'bin/cake server';
1010
+ lint = './vendor/bin/phpcs';
1011
+ } else if (isSymfony) {
1012
+ dev = 'bin/console server:run';
1013
+ lint = './vendor/bin/phpcs';
1014
+ } else if (isCodeIgniter) {
1015
+ dev = 'php spark serve';
1016
+ lint = './vendor/bin/phpcs';
1017
+ } else {
1018
+ dev = 'php artisan serve';
1019
+ lint = 'php artisan pint';
1020
+ }
1021
+ }
1022
+
1023
+ if (testFramework === 'vitest') test = `${pkgManager === 'pnpm' ? 'pnpm' : pkgManager === 'yarn' ? 'yarn' : pkgManager === 'bun' ? 'bun run' : 'npx'} vitest`;
1024
+ else if (testFramework === 'jest') test = `${pkgManager === 'pnpm' ? 'pnpm' : pkgManager === 'yarn' ? 'yarn' : 'npx'} jest`;
1025
+
1026
+ return { install, dev, build, test, lint };
1027
+ }
1028
+
1029
+ function generateProjectDoc(data) {
1030
+ const commands = resolveCommands(data);
1031
+ const agentRows = resolveAgentTable(data).map(([task, agent, skills]) => `| ${task} | \`${agent}\` | ${skills} |`).join('\n');
1032
+ const skillsList = resolveSkills(data).map(s => `- ${s}`).join('\n');
1033
+ const evidence = (data.scan_evidence || []).length > 0
1034
+ ? (data.scan_evidence || []).map(line => `- ${line}`).join('\n')
1035
+ : '- TODO: refine scan evidence by inspecting the project.';
1036
+
1037
+ return `# Project Rules
1038
+
1039
+ Generated by thachvd-kit on ${new Date().toISOString().split('T')[0]}.
1040
+
1041
+ ## Summary
1042
+
1043
+ - Name: ${data.project_name}
1044
+ - Description: ${data.description}
1045
+ - Type: ${data.project_type}
1046
+ - App root: ${data.app_root || '.'}
1047
+
1048
+ ## Stack
1049
+
1050
+ - Language: ${data.primary_language}
1051
+ - Frameworks: ${(data.frameworks || []).join(', ') || 'none'}
1052
+ - Database: ${data.database || 'none'}
1053
+ - Infrastructure: ${(data.infrastructure || []).join(', ') || 'none'}
1054
+ - Package manager: ${data.package_manager || 'auto-detect'}
1055
+ - Test framework: ${data.test_framework || 'auto-detect'}
1056
+
1057
+ ## Commands
1058
+
1059
+ - Install: \`${commands.install}\`
1060
+ - Dev: \`${commands.dev}\`
1061
+ - Build: \`${commands.build}\`
1062
+ - Test: \`${commands.test}\`
1063
+ - Lint: \`${commands.lint}\`
1064
+
1065
+ ## Agent Routing
1066
+
1067
+ | Task Type | Agent | Primary Skills |
1068
+ |-----------|-------|----------------|
1069
+ ${agentRows}
1070
+
1071
+ ## Auto-Resolved Skills
1072
+
1073
+ ${skillsList}
1074
+
1075
+ ## Scan Evidence
1076
+
1077
+ ${evidence}
1078
+ `;
1079
+ }
1080
+
1081
+ function generateArchitectureDoc(data) {
1082
+ const appRootLine = data.app_root && data.app_root !== '.'
1083
+ ? `- App root is currently detected as \`${data.app_root}\`.`
1084
+ : '- App root is the repository root unless refined below.';
1085
+ const evidence = (data.scan_evidence || []).length > 0
1086
+ ? (data.scan_evidence || []).map(line => `- ${line}`).join('\n')
1087
+ : '- TODO: refine architecture by scanning source directories.';
1088
+
1089
+ return `# Architecture Notes
1090
+
1091
+ ## Current Map
1092
+
1093
+ ${appRootLine}
1094
+ - TODO: refine major directories and responsibilities.
1095
+ - TODO: refine main entry points, routing, state boundaries, and integration boundaries.
1096
+
1097
+ ## Detected Evidence
1098
+
1099
+ ${evidence}
1100
+
1101
+ ## AI Maintenance Rule
1102
+
1103
+ Before non-trivial implementation work, inspect this file. If it is stale or still contains TODO items relevant to the task, update it from the code before editing product code.
1104
+ `;
1105
+ }
1106
+
1107
+ function generateConventionsDoc(data) {
1108
+ return `# Coding Conventions
1109
+
1110
+ ## Current Standards
1111
+
1112
+ - Maximum file length: ${data.max_file_lines || '300'} lines unless the existing project standard is stricter.
1113
+ - Code comments and identifiers should be written in English.
1114
+ - Keep changes scoped to the user request.
1115
+ - Prefer existing local patterns over introducing new abstractions.
1116
+ - TODO: refine naming, formatting, folder, API, state, styling, and testing conventions from the real codebase.
1117
+
1118
+ ## Verification
1119
+
1120
+ - Run the focused test or lint command that matches the touched area.
1121
+ - If no automated check exists, document the manual verification performed.
1122
+ - Do not claim completion without verification evidence.
1123
+ `;
1124
+ }
1125
+
1117
1126
  function generateWorkflowDoc() {
1118
- return `# Agent Workflow
1119
-
1120
- ## Before Every Task
1121
-
1127
+ return `# Agent Workflow
1128
+
1129
+ ## Before Every Task
1130
+
1122
1131
  1. Read AGENTS.md.
1123
1132
  2. Read .agent/docs/project.md.
1124
1133
  3. Classify the request: question, survey, simple fix, feature, refactor, debug, UI, security, or deploy.
@@ -1136,20 +1145,20 @@ function generateWorkflowDoc() {
1136
1145
  - Run thachvd-kit --help to see common workflow and skill recommendations.
1137
1146
 
1138
1147
  ## Implementation Flow
1139
-
1140
- 1. State assumptions and success criteria when the task is not trivial.
1141
- 2. Inspect dependent files before editing.
1142
- 3. Make the smallest coherent change.
1143
- 4. Add or update focused tests when behavior changes.
1144
- 5. Run verification.
1145
- 6. Summarize changed files and verification evidence.
1146
-
1147
- ## When To Update Docs
1148
-
1149
- - Update .agent/docs/architecture.md when structure, boundaries, or entry points change.
1150
- - Update .agent/docs/conventions.md when repeated project patterns become clear.
1151
- - Update .agent/docs/project.md when stack, scripts, app root, test tooling, or routing changes.
1152
- - Keep AGENTS.md concise. Put project-specific detail in .agent/docs.
1148
+
1149
+ 1. State assumptions and success criteria when the task is not trivial.
1150
+ 2. Inspect dependent files before editing.
1151
+ 3. Make the smallest coherent change.
1152
+ 4. Add or update focused tests when behavior changes.
1153
+ 5. Run verification.
1154
+ 6. Summarize changed files and verification evidence.
1155
+
1156
+ ## When To Update Docs
1157
+
1158
+ - Update .agent/docs/architecture.md when structure, boundaries, or entry points change.
1159
+ - Update .agent/docs/conventions.md when repeated project patterns become clear.
1160
+ - Update .agent/docs/project.md when stack, scripts, app root, test tooling, or routing changes.
1161
+ - Keep AGENTS.md concise. Put project-specific detail in .agent/docs.
1153
1162
  `;
1154
1163
  }
1155
1164
 
@@ -1298,39 +1307,39 @@ Recommended candidates to copy first:
1298
1307
  - Stack-specific skills listed in \`.agent/docs/project.md\`
1299
1308
  `;
1300
1309
  }
1301
-
1302
- // --- Agent Folder Copy ---
1303
-
1310
+
1311
+ // --- Agent Folder Copy ---
1312
+
1304
1313
  function copyAgentFolder() {
1305
- const srcAgent = path.join(sourceDir, '.agent');
1306
- if (!fs.existsSync(srcAgent)) return { copied: 0, skipped: 0 };
1307
-
1308
- const destAgent = path.join(targetDir, '.agent');
1309
- let copied = 0;
1310
- let skipped = 0;
1311
-
1312
- function copyDir(src, dest) {
1313
- fs.mkdirSync(dest, { recursive: true });
1314
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
1315
- const srcPath = path.join(src, entry.name);
1316
- const destPath = path.join(dest, entry.name);
1317
- const relativeSrc = path.relative(srcAgent, srcPath).split(path.sep).join('/');
1318
- if (relativeSrc === 'docs' || relativeSrc.startsWith('docs/')) {
1319
- continue;
1320
- }
1321
- if (entry.isDirectory()) {
1322
- copyDir(srcPath, destPath);
1323
- } else {
1324
- if (fs.existsSync(destPath)) {
1325
- skipped++;
1326
- } else {
1327
- fs.copyFileSync(srcPath, destPath);
1328
- copied++;
1329
- }
1330
- }
1331
- }
1332
- }
1333
-
1314
+ const srcAgent = path.join(sourceDir, '.agent');
1315
+ if (!fs.existsSync(srcAgent)) return { copied: 0, skipped: 0 };
1316
+
1317
+ const destAgent = path.join(targetDir, '.agent');
1318
+ let copied = 0;
1319
+ let skipped = 0;
1320
+
1321
+ function copyDir(src, dest) {
1322
+ fs.mkdirSync(dest, { recursive: true });
1323
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
1324
+ const srcPath = path.join(src, entry.name);
1325
+ const destPath = path.join(dest, entry.name);
1326
+ const relativeSrc = path.relative(srcAgent, srcPath).split(path.sep).join('/');
1327
+ if (relativeSrc === 'docs' || relativeSrc.startsWith('docs/')) {
1328
+ continue;
1329
+ }
1330
+ if (entry.isDirectory()) {
1331
+ copyDir(srcPath, destPath);
1332
+ } else {
1333
+ if (fs.existsSync(destPath)) {
1334
+ skipped++;
1335
+ } else {
1336
+ fs.copyFileSync(srcPath, destPath);
1337
+ copied++;
1338
+ }
1339
+ }
1340
+ }
1341
+ }
1342
+
1334
1343
  copyDir(srcAgent, destAgent);
1335
1344
  return { copied, skipped };
1336
1345
  }
@@ -1521,28 +1530,28 @@ function setupMcpServers() {
1521
1530
  }
1522
1531
 
1523
1532
  // --- Main CLI ---
1524
-
1533
+
1525
1534
  async function main() {
1526
- const rawArgs = process.argv.slice(2);
1527
- const command = rawArgs[0] && !rawArgs[0].startsWith('-') ? rawArgs[0] : 'init';
1528
- const args = command === 'init' ? rawArgs.slice(rawArgs[0] === 'init' ? 1 : 0) : rawArgs.slice(1);
1529
-
1530
- if (rawArgs.includes('--version') || rawArgs.includes('-v')) {
1531
- console.log(packageJson.version);
1532
- return;
1533
- }
1534
-
1535
- if (rawArgs.includes('--help') || rawArgs.includes('-h')) {
1536
- printHelp();
1537
- return;
1538
- }
1539
-
1540
- if (command !== 'init') {
1541
- console.error(pc.red(`Unknown command: ${command}`));
1542
- printHelp();
1543
- process.exit(1);
1544
- }
1545
-
1535
+ const rawArgs = process.argv.slice(2);
1536
+ const command = rawArgs[0] && !rawArgs[0].startsWith('-') ? rawArgs[0] : 'init';
1537
+ const args = command === 'init' ? rawArgs.slice(rawArgs[0] === 'init' ? 1 : 0) : rawArgs.slice(1);
1538
+
1539
+ if (rawArgs.includes('--version') || rawArgs.includes('-v')) {
1540
+ console.log(packageJson.version);
1541
+ return;
1542
+ }
1543
+
1544
+ if (rawArgs.includes('--help') || rawArgs.includes('-h')) {
1545
+ printHelp();
1546
+ return;
1547
+ }
1548
+
1549
+ if (command !== 'init') {
1550
+ console.error(pc.red(`Unknown command: ${command}`));
1551
+ printHelp();
1552
+ process.exit(1);
1553
+ }
1554
+
1546
1555
  const assumeYes = args.includes('--yes') || args.includes('-y');
1547
1556
  const skipMcpSetup = args.includes('--no-setup-mcp') || process.env.THACHVD_KIT_SKIP_MCP_SETUP === '1';
1548
1557
 
@@ -1579,17 +1588,17 @@ async function main() {
1579
1588
  test_framework: scanned?.test_framework || 'auto-detect',
1580
1589
  max_file_lines: scanned?.max_file_lines || '300'
1581
1590
  };
1582
-
1583
- data.database = data.database || scanned?.database || 'none';
1584
- data.uses_docker = typeof data.uses_docker === 'boolean' ? data.uses_docker : (scanned?.uses_docker ?? true);
1585
- data.cloud = data.cloud || scanned?.cloud || 'none';
1586
- data.package_manager = data.package_manager || scanned?.package_manager || 'auto-detect';
1587
- data.test_framework = data.test_framework || scanned?.test_framework || 'auto-detect';
1588
- data.max_file_lines = data.max_file_lines || scanned?.max_file_lines || '300';
1589
- data.framework_details = scanned?.framework_details || [];
1590
- data.scan_evidence = scanned?.scan_evidence || [];
1591
- data.app_root = scanned?.app_root || '.';
1592
-
1591
+
1592
+ data.database = data.database || scanned?.database || 'none';
1593
+ data.uses_docker = typeof data.uses_docker === 'boolean' ? data.uses_docker : (scanned?.uses_docker ?? true);
1594
+ data.cloud = data.cloud || scanned?.cloud || 'none';
1595
+ data.package_manager = data.package_manager || scanned?.package_manager || 'auto-detect';
1596
+ data.test_framework = data.test_framework || scanned?.test_framework || 'auto-detect';
1597
+ data.max_file_lines = data.max_file_lines || scanned?.max_file_lines || '300';
1598
+ data.framework_details = scanned?.framework_details || [];
1599
+ data.scan_evidence = scanned?.scan_evidence || [];
1600
+ data.app_root = scanned?.app_root || '.';
1601
+
1593
1602
  data.infrastructure = [];
1594
1603
  if (data.uses_docker) data.infrastructure.push('docker');
1595
1604
  if (data.cloud !== 'none') data.infrastructure.push(data.cloud);
@@ -1597,13 +1606,13 @@ async function main() {
1597
1606
  const shouldSetupMcp = !skipMcpSetup;
1598
1607
 
1599
1608
  console.log(`\n${pc.bold(pc.cyan('Generating Files'))}`);
1600
-
1601
- // Shared entry files are written after the .agent folder is available.
1602
-
1603
- // Copy .agent folder
1604
- const { copied, skipped } = copyAgentFolder();
1605
- if (copied > 0) {
1606
- console.log(` ${pc.green('OK')} Copied ${pc.bold('.agent/')} (${copied} file${copied !== 1 ? 's' : ''} added${skipped > 0 ? `, ${skipped} skipped` : ''})`);
1609
+
1610
+ // Shared entry files are written after the .agent folder is available.
1611
+
1612
+ // Copy .agent folder
1613
+ const { copied, skipped } = copyAgentFolder();
1614
+ if (copied > 0) {
1615
+ console.log(` ${pc.green('OK')} Copied ${pc.bold('.agent/')} (${copied} file${copied !== 1 ? 's' : ''} added${skipped > 0 ? `, ${skipped} skipped` : ''})`);
1607
1616
  } else if (skipped > 0) {
1608
1617
  console.log(` ${pc.yellow('~')} ${pc.bold('.agent/')} already exists - ${skipped} file${skipped !== 1 ? 's' : ''} skipped (no overwrite)`);
1609
1618
  }
@@ -1617,16 +1626,17 @@ async function main() {
1617
1626
 
1618
1627
 
1619
1628
  const generatedFiles = [
1620
- ['AGENTS.md', generateSharedAgentsMd(data)],
1621
- ['CLAUDE.md', generateSharedClaudeMd()],
1622
- ['GEMINI.md', generateSharedGeminiMd()],
1623
- [path.join('.agent', 'docs', 'project.md'), generateProjectDoc(data)],
1629
+ ['AGENTS.md', generateSharedAgentsMd(data)],
1630
+ ['CLAUDE.md', generateSharedClaudeMd()],
1631
+ ['GEMINI.md', generateSharedGeminiMd()],
1632
+ ['.cursorrules', generateSharedCursorrules()],
1633
+ [path.join('.agent', 'docs', 'project.md'), generateProjectDoc(data)],
1624
1634
  [path.join('.agent', 'docs', 'architecture.md'), generateArchitectureDoc(data)],
1625
1635
  [path.join('.agent', 'docs', 'conventions.md'), generateConventionsDoc(data)],
1626
1636
  [path.join('.agent', 'docs', 'workflow.md'), generateWorkflowDoc()],
1627
1637
  [path.join('.agent', 'docs', 'tooling.md'), generateToolingDoc(data)]
1628
1638
  ];
1629
-
1639
+
1630
1640
  for (const [relativePath, content] of generatedFiles) {
1631
1641
  const wrote = await writeGeneratedFile(relativePath, content, assumeYes);
1632
1642
  if (wrote) console.log(` ${pc.green('OK')} Generated ${pc.bold(relativePath)}`);
@@ -1642,14 +1652,15 @@ async function main() {
1642
1652
  }
1643
1653
 
1644
1654
  console.log(`\n${pc.bold(pc.green('Done!'))}
1645
-
1646
- ${pc.bold('Project:')} ${data.project_name}
1647
- ${pc.bold('Stack:')} ${data.primary_language} | ${(data.frameworks || []).join(', ') || 'no framework'}
1648
-
1649
- ${pc.bold('Generated:')}
1650
- - ${pc.bold('AGENTS.md')} shared entry for Codex, Antigravity, and Claude Code
1651
- - ${pc.bold('CLAUDE.md')} Claude Code entry that imports AGENTS.md
1655
+
1656
+ ${pc.bold('Project:')} ${data.project_name}
1657
+ ${pc.bold('Stack:')} ${data.primary_language} | ${(data.frameworks || []).join(', ') || 'no framework'}
1658
+
1659
+ ${pc.bold('Generated:')}
1660
+ - ${pc.bold('AGENTS.md')} shared entry for Codex, Antigravity, Claude Code, and Cursor
1661
+ - ${pc.bold('CLAUDE.md')} Claude Code entry that imports AGENTS.md
1652
1662
  - ${pc.bold('GEMINI.md')} Antigravity entry
1663
+ - ${pc.bold('.cursorrules')} Cursor entry
1653
1664
  - ${pc.bold('.agent/docs/')} scan-based project rules
1654
1665
  - ${pc.bold('.agent/')} skills, workflows, agents, and rules
1655
1666
  - ${pc.bold('~/.codex/skills/')} selected Codex skills installed globally (visible in $ menu)
@@ -1664,22 +1675,23 @@ async function main() {
1664
1675
 
1665
1676
  ${pc.bold('Next steps:')}
1666
1677
  1. Copy the prompt below into your AI editor and describe what the project does
1667
- 2. Commit ${pc.bold('AGENTS.md')}, ${pc.bold('CLAUDE.md')}, ${pc.bold('GEMINI.md')}, and ${pc.bold('.agent/')}
1668
- 3. Open the project in Codex, Antigravity, or Claude Code
1678
+ 2. Commit ${pc.bold('AGENTS.md')}, ${pc.bold('CLAUDE.md')}, ${pc.bold('GEMINI.md')}, ${pc.bold('.cursorrules')}, and ${pc.bold('.agent/')}
1679
+ 3. Open the project in Codex, Antigravity, Claude Code, or Cursor
1669
1680
 
1670
1681
  ${pc.bold('Copy this prompt into your AI editor:')}
1671
1682
  ${pc.dim('---')}
1672
1683
  Read AGENTS.md and all files under .agent/docs/.
1673
1684
  Ask me what this project does and any important conventions I want preserved.
1674
1685
  Then scan this repository.
1675
- Update AGENTS.md and .agent/docs/project.md, .agent/docs/architecture.md, .agent/docs/conventions.md, .agent/docs/workflow.md, and .agent/docs/tooling.md with factual project-specific rules.
1686
+ Update AGENTS.md, .cursorrules and .agent/docs/project.md, .agent/docs/architecture.md, .agent/docs/conventions.md, .agent/docs/workflow.md, and .agent/docs/tooling.md with factual project-specific rules.
1676
1687
  Do not implement product code.
1677
1688
  Remove TODO: refine only when backed by evidence from the codebase.
1678
1689
  ${pc.dim('---')}
1679
- `);
1680
- }
1690
+ `);
1691
+ }
1692
+
1693
+ main().catch(err => {
1694
+ console.error(pc.red('\nError during init:'), err);
1695
+ process.exit(1);
1696
+ });
1681
1697
 
1682
- main().catch(err => {
1683
- console.error(pc.red('\nError during init:'), err);
1684
- process.exit(1);
1685
- });