fix: deployment issues with typescript and dist
This commit is contained in:
10
package.json
10
package.json
@@ -110,14 +110,10 @@
|
|||||||
"url": "https://github.com/eyaltoledano/claude-task-master/issues"
|
"url": "https://github.com/eyaltoledano/claude-task-master/issues"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"scripts/**",
|
"dist/**",
|
||||||
"assets/**",
|
|
||||||
".cursor/**",
|
|
||||||
"README-task-master.md",
|
"README-task-master.md",
|
||||||
"index.js",
|
"README.md",
|
||||||
"bin/**",
|
"LICENSE"
|
||||||
"mcp-server/**",
|
|
||||||
"src/**"
|
|
||||||
],
|
],
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"node-fetch": "^2.6.12",
|
"node-fetch": "^2.6.12",
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ import {
|
|||||||
} from '../src/utils/rule-transformer.js';
|
} from '../src/utils/rule-transformer.js';
|
||||||
import { updateConfigMaxTokens } from './modules/update-config-tokens.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 { execSync } from 'child_process';
|
||||||
import {
|
import {
|
||||||
EXAMPLE_PRD_FILE,
|
EXAMPLE_PRD_FILE,
|
||||||
@@ -222,32 +225,14 @@ function createInitialStateFile(targetDir) {
|
|||||||
// Function to copy a file from the package to the target directory
|
// Function to copy a file from the package to the target directory
|
||||||
function copyTemplateFile(templateName, targetPath, replacements = {}) {
|
function copyTemplateFile(templateName, targetPath, replacements = {}) {
|
||||||
// Get the file content from the appropriate source directory
|
// Get the file content from the appropriate source directory
|
||||||
let sourcePath;
|
// Check if the asset exists
|
||||||
|
if (!assetExists(templateName)) {
|
||||||
// Map template names to their actual source paths
|
log('error', `Source file not found: ${templateName}`);
|
||||||
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}`);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let content = fs.readFileSync(sourcePath, 'utf8');
|
// Read the asset content using the resolver
|
||||||
|
let content = readAsset(templateName, 'utf8');
|
||||||
|
|
||||||
// Replace placeholders with actual values
|
// Replace placeholders with actual values
|
||||||
Object.entries(replacements).forEach(([key, value]) => {
|
Object.entries(replacements).forEach(([key, value]) => {
|
||||||
|
|||||||
84
src/utils/asset-resolver.js
Normal file
84
src/utils/asset-resolver.js
Normal 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);
|
||||||
|
}
|
||||||
@@ -7,9 +7,11 @@
|
|||||||
*/
|
*/
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
import { log } from '../../scripts/modules/utils.js';
|
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 the shared MCP configuration helper
|
||||||
import {
|
import {
|
||||||
setupMCPConfiguration,
|
setupMCPConfiguration,
|
||||||
@@ -199,11 +201,7 @@ export function convertRuleToProfileRule(sourcePath, targetPath, profile) {
|
|||||||
* Convert all Cursor rules to profile rules for a specific profile
|
* Convert all Cursor rules to profile rules for a specific profile
|
||||||
*/
|
*/
|
||||||
export function convertAllRulesToProfileRules(projectRoot, 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 targetDir = path.join(projectRoot, profile.rulesDir);
|
||||||
const assetsDir = path.join(__dirname, '..', '..', 'assets');
|
|
||||||
|
|
||||||
let success = 0;
|
let success = 0;
|
||||||
let failed = 0;
|
let failed = 0;
|
||||||
@@ -211,6 +209,7 @@ export function convertAllRulesToProfileRules(projectRoot, profile) {
|
|||||||
// 1. Call onAddRulesProfile first (for pre-processing like copying assets)
|
// 1. Call onAddRulesProfile first (for pre-processing like copying assets)
|
||||||
if (typeof profile.onAddRulesProfile === 'function') {
|
if (typeof profile.onAddRulesProfile === 'function') {
|
||||||
try {
|
try {
|
||||||
|
const assetsDir = getAssetsDir();
|
||||||
profile.onAddRulesProfile(projectRoot, assetsDir);
|
profile.onAddRulesProfile(projectRoot, assetsDir);
|
||||||
log(
|
log(
|
||||||
'debug',
|
'debug',
|
||||||
@@ -238,14 +237,11 @@ export function convertAllRulesToProfileRules(projectRoot, profile) {
|
|||||||
const isAssetFile = !sourceFile.startsWith('rules/');
|
const isAssetFile = !sourceFile.startsWith('rules/');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Use explicit path from fileMap - assets/ is the base directory
|
// Check if source file exists using asset resolver
|
||||||
const sourcePath = path.join(assetsDir, sourceFile);
|
if (!assetExists(sourceFile)) {
|
||||||
|
|
||||||
// Check if source file exists
|
|
||||||
if (!fs.existsSync(sourcePath)) {
|
|
||||||
log(
|
log(
|
||||||
'warn',
|
'warn',
|
||||||
`[Rule Transformer] Source file not found: ${sourcePath}, skipping`
|
`[Rule Transformer] Source file not found: ${sourceFile}, skipping`
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -259,8 +255,8 @@ export function convertAllRulesToProfileRules(projectRoot, profile) {
|
|||||||
fs.mkdirSync(targetFileDir, { recursive: true });
|
fs.mkdirSync(targetFileDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read source content
|
// Read source content using asset resolver
|
||||||
let content = fs.readFileSync(sourcePath, 'utf8');
|
let content = readAsset(sourceFile, 'utf8');
|
||||||
|
|
||||||
// Apply transformations (only if this is a rule file, not an asset file)
|
// Apply transformations (only if this is a rule file, not an asset file)
|
||||||
if (!isAssetFile) {
|
if (!isAssetFile) {
|
||||||
@@ -308,6 +304,7 @@ export function convertAllRulesToProfileRules(projectRoot, profile) {
|
|||||||
// 4. Call post-conversion hook (for finalization)
|
// 4. Call post-conversion hook (for finalization)
|
||||||
if (typeof profile.onPostConvertRulesProfile === 'function') {
|
if (typeof profile.onPostConvertRulesProfile === 'function') {
|
||||||
try {
|
try {
|
||||||
|
const assetsDir = getAssetsDir();
|
||||||
profile.onPostConvertRulesProfile(projectRoot, assetsDir);
|
profile.onPostConvertRulesProfile(projectRoot, assetsDir);
|
||||||
log(
|
log(
|
||||||
'debug',
|
'debug',
|
||||||
@@ -386,11 +383,46 @@ export function removeProfileRules(projectRoot, profile) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Get all files in the rules directory
|
// 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
|
const allFilePaths = allFiles
|
||||||
.filter((file) => {
|
.filter((file) => {
|
||||||
const fullPath = path.join(targetDir, 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
|
.map((file) => file.toString()); // Ensure it's a string
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export default defineConfig({
|
|||||||
clean: true,
|
clean: true,
|
||||||
bundle: true, // Bundle everything into one file
|
bundle: true, // Bundle everything into one file
|
||||||
outDir: 'dist',
|
outDir: 'dist',
|
||||||
|
publicDir: 'public',
|
||||||
// Handle TypeScript imports transparently
|
// Handle TypeScript imports transparently
|
||||||
loader: {
|
loader: {
|
||||||
'.js': 'jsx',
|
'.js': 'jsx',
|
||||||
|
|||||||
Reference in New Issue
Block a user