fix: deployment issues with typescript and dist

This commit is contained in:
Ralph Khreish
2025-09-01 21:18:11 +02:00
parent 6c61472103
commit 8f27fd7a69
82 changed files with 144 additions and 46 deletions

View File

@@ -110,14 +110,10 @@
"url": "https://github.com/eyaltoledano/claude-task-master/issues"
},
"files": [
"scripts/**",
"assets/**",
".cursor/**",
"dist/**",
"README-task-master.md",
"index.js",
"bin/**",
"mcp-server/**",
"src/**"
"README.md",
"LICENSE"
],
"overrides": {
"node-fetch": "^2.6.12",

View File

@@ -32,6 +32,9 @@ import {
} from '../src/utils/rule-transformer.js';
import { updateConfigMaxTokens } from './modules/update-config-tokens.js';
// Import asset resolver
import { assetExists, readAsset } from '../src/utils/asset-resolver.js';
import { execSync } from 'child_process';
import {
EXAMPLE_PRD_FILE,
@@ -222,32 +225,14 @@ function createInitialStateFile(targetDir) {
// Function to copy a file from the package to the target directory
function copyTemplateFile(templateName, targetPath, replacements = {}) {
// Get the file content from the appropriate source directory
let sourcePath;
// Map template names to their actual source paths
switch (templateName) {
// case 'scripts_README.md':
// sourcePath = path.join(__dirname, '..', 'assets', 'scripts_README.md');
// break;
// case 'README-task-master.md':
// sourcePath = path.join(__dirname, '..', 'README-task-master.md');
// break;
default:
// For other files like env.example, gitignore, etc. that don't have direct equivalents
sourcePath = path.join(__dirname, '..', 'assets', templateName);
}
// Check if the source file exists
if (!fs.existsSync(sourcePath)) {
// Fall back to templates directory for files that might not have been moved yet
sourcePath = path.join(__dirname, '..', 'assets', templateName);
if (!fs.existsSync(sourcePath)) {
log('error', `Source file not found: ${sourcePath}`);
// Check if the asset exists
if (!assetExists(templateName)) {
log('error', `Source file not found: ${templateName}`);
return;
}
}
let content = fs.readFileSync(sourcePath, 'utf8');
// Read the asset content using the resolver
let content = readAsset(templateName, 'utf8');
// Replace placeholders with actual values
Object.entries(replacements).forEach(([key, value]) => {

View File

@@ -0,0 +1,84 @@
/**
* Asset Resolver Module
* Handles resolving paths to asset files in the package
*
* The public/assets folder is copied to dist/assets during build via tsup's publicDir,
* so we can reliably find it relative to the bundled files.
*/
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
/**
* Get the assets directory path
* When bundled, assets are in dist/assets
* When in development, assets are in public/assets
* @returns {string} Path to the assets directory
*/
export function getAssetsDir() {
// Check multiple possible locations
const possiblePaths = [
// When running from dist (bundled) - assets are in dist/assets
path.join(__dirname, 'assets'),
path.join(__dirname, '..', 'assets'),
// When running from source in development - now in public/assets
path.join(__dirname, '..', '..', 'public', 'assets'),
// When installed as npm package - assets at package root
path.join(process.cwd(), 'assets'),
// For npx usage - check node_modules
path.join(process.cwd(), 'node_modules', 'task-master-ai', 'dist', 'assets'),
path.join(process.cwd(), 'node_modules', 'task-master-ai', 'assets')
];
// Find the first existing assets directory
for (const assetPath of possiblePaths) {
if (fs.existsSync(assetPath)) {
// Verify it's actually the assets directory by checking for known files
const testFile = path.join(assetPath, 'rules', 'taskmaster.mdc');
if (fs.existsSync(testFile)) {
return assetPath;
}
}
}
// If no assets directory found, throw an error
throw new Error('Assets directory not found. This is likely a packaging issue.');
}
/**
* Get path to a specific asset file
* @param {string} relativePath - Path relative to assets directory
* @returns {string} Full path to the asset file
*/
export function getAssetPath(relativePath) {
const assetsDir = getAssetsDir();
return path.join(assetsDir, relativePath);
}
/**
* Check if an asset file exists
* @param {string} relativePath - Path relative to assets directory
* @returns {boolean} True if the asset exists
*/
export function assetExists(relativePath) {
try {
const assetPath = getAssetPath(relativePath);
return fs.existsSync(assetPath);
} catch (error) {
return false;
}
}
/**
* Read an asset file
* @param {string} relativePath - Path relative to assets directory
* @param {string} encoding - File encoding (default: 'utf8')
* @returns {string|Buffer} File contents
*/
export function readAsset(relativePath, encoding = 'utf8') {
const assetPath = getAssetPath(relativePath);
return fs.readFileSync(assetPath, encoding);
}

View File

@@ -7,9 +7,11 @@
*/
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { log } from '../../scripts/modules/utils.js';
// Import asset resolver
import { assetExists, readAsset, getAssetsDir } from './asset-resolver.js';
// Import the shared MCP configuration helper
import {
setupMCPConfiguration,
@@ -199,11 +201,7 @@ export function convertRuleToProfileRule(sourcePath, targetPath, profile) {
* Convert all Cursor rules to profile rules for a specific profile
*/
export function convertAllRulesToProfileRules(projectRoot, profile) {
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const sourceDir = path.join(__dirname, '..', '..', 'assets', 'rules');
const targetDir = path.join(projectRoot, profile.rulesDir);
const assetsDir = path.join(__dirname, '..', '..', 'assets');
let success = 0;
let failed = 0;
@@ -211,6 +209,7 @@ export function convertAllRulesToProfileRules(projectRoot, profile) {
// 1. Call onAddRulesProfile first (for pre-processing like copying assets)
if (typeof profile.onAddRulesProfile === 'function') {
try {
const assetsDir = getAssetsDir();
profile.onAddRulesProfile(projectRoot, assetsDir);
log(
'debug',
@@ -238,14 +237,11 @@ export function convertAllRulesToProfileRules(projectRoot, profile) {
const isAssetFile = !sourceFile.startsWith('rules/');
try {
// Use explicit path from fileMap - assets/ is the base directory
const sourcePath = path.join(assetsDir, sourceFile);
// Check if source file exists
if (!fs.existsSync(sourcePath)) {
// Check if source file exists using asset resolver
if (!assetExists(sourceFile)) {
log(
'warn',
`[Rule Transformer] Source file not found: ${sourcePath}, skipping`
`[Rule Transformer] Source file not found: ${sourceFile}, skipping`
);
continue;
}
@@ -259,8 +255,8 @@ export function convertAllRulesToProfileRules(projectRoot, profile) {
fs.mkdirSync(targetFileDir, { recursive: true });
}
// Read source content
let content = fs.readFileSync(sourcePath, 'utf8');
// Read source content using asset resolver
let content = readAsset(sourceFile, 'utf8');
// Apply transformations (only if this is a rule file, not an asset file)
if (!isAssetFile) {
@@ -308,6 +304,7 @@ export function convertAllRulesToProfileRules(projectRoot, profile) {
// 4. Call post-conversion hook (for finalization)
if (typeof profile.onPostConvertRulesProfile === 'function') {
try {
const assetsDir = getAssetsDir();
profile.onPostConvertRulesProfile(projectRoot, assetsDir);
log(
'debug',
@@ -386,11 +383,46 @@ export function removeProfileRules(projectRoot, profile) {
);
// Get all files in the rules directory
const allFiles = fs.readdirSync(targetDir, { recursive: true });
// For root-level directories, we need to be careful to avoid circular symlinks
let allFiles = [];
if (targetDir === projectRoot || profile.rulesDir === '.') {
// For root directory, manually read without recursion into problematic directories
const items = fs.readdirSync(targetDir);
for (const item of items) {
// Skip directories that can cause issues or are irrelevant
if (item === 'node_modules' || item === '.git' || item === 'dist') {
continue;
}
const itemPath = path.join(targetDir, item);
try {
const stats = fs.lstatSync(itemPath);
if (stats.isFile()) {
allFiles.push(item);
} else if (stats.isDirectory() && !stats.isSymbolicLink()) {
// Only recurse into safe directories
const subFiles = fs.readdirSync(itemPath, { recursive: true });
subFiles.forEach(subFile => {
allFiles.push(path.join(item, subFile.toString()));
});
}
} catch (err) {
// Silently skip files we can't access
}
}
} else {
// For non-root directories, use normal recursive read
allFiles = fs.readdirSync(targetDir, { recursive: true });
}
const allFilePaths = allFiles
.filter((file) => {
const fullPath = path.join(targetDir, file);
return fs.statSync(fullPath).isFile();
try {
const stats = fs.statSync(fullPath);
return stats.isFile();
} catch (err) {
return false;
}
})
.map((file) => file.toString()); // Ensure it's a string

View File

@@ -12,6 +12,7 @@ export default defineConfig({
clean: true,
bundle: true, // Bundle everything into one file
outDir: 'dist',
publicDir: 'public',
// Handle TypeScript imports transparently
loader: {
'.js': 'jsx',