@defai.digital/ax-cli 2.3.1 → 2.4.1
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/.ax-cli/CUSTOM.md +111 -89
- package/.ax-cli/index.json +4 -3
- package/README.md +43 -16
- package/config/prompts.yaml +9 -0
- package/config/settings.yaml +2 -0
- package/dist/agent/llm-agent.d.ts +17 -0
- package/dist/agent/llm-agent.js +151 -52
- package/dist/agent/llm-agent.js.map +1 -1
- package/dist/commands/init/wizard.d.ts +66 -0
- package/dist/commands/init/wizard.js +310 -0
- package/dist/commands/init/wizard.js.map +1 -0
- package/dist/commands/init.js +145 -31
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mcp.js +3 -2
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/memory.d.ts +5 -0
- package/dist/commands/memory.js +257 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/setup.js +1 -1
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/templates.d.ts +5 -0
- package/dist/commands/templates.js +244 -0
- package/dist/commands/templates.js.map +1 -0
- package/dist/commands/update.js +9 -2
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/usage.js +1 -1
- package/dist/commands/usage.js.map +1 -1
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +2 -0
- package/dist/constants.js.map +1 -1
- package/dist/hooks/use-input-handler.js +18 -4
- package/dist/hooks/use-input-handler.js.map +1 -1
- package/dist/index.js +147 -20
- package/dist/index.js.map +1 -1
- package/dist/llm/client.d.ts +5 -0
- package/dist/llm/client.js +45 -39
- package/dist/llm/client.js.map +1 -1
- package/dist/schemas/index.d.ts +69 -0
- package/dist/schemas/index.js +29 -0
- package/dist/schemas/index.js.map +1 -1
- package/dist/schemas/yaml-schemas.d.ts +10 -0
- package/dist/schemas/yaml-schemas.js +2 -0
- package/dist/schemas/yaml-schemas.js.map +1 -1
- package/dist/tools/search.js +7 -1
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/text-editor.js +24 -14
- package/dist/tools/text-editor.js.map +1 -1
- package/dist/tools/todo-tool.js +62 -21
- package/dist/tools/todo-tool.js.map +1 -1
- package/dist/types/template.d.ts +53 -0
- package/dist/types/template.js +5 -0
- package/dist/types/template.js.map +1 -0
- package/dist/ui/components/chat-interface.js +5 -1
- package/dist/ui/components/chat-interface.js.map +1 -1
- package/dist/ui/components/command-suggestions.js +2 -2
- package/dist/ui/components/command-suggestions.js.map +1 -1
- package/dist/utils/cache.d.ts +1 -0
- package/dist/utils/cache.js +39 -5
- package/dist/utils/cache.js.map +1 -1
- package/dist/utils/config-loader.d.ts +2 -0
- package/dist/utils/config-loader.js +2 -1
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/confirmation-service.js +6 -3
- package/dist/utils/confirmation-service.js.map +1 -1
- package/dist/utils/error-handler.d.ts +5 -0
- package/dist/utils/error-handler.js +9 -3
- package/dist/utils/error-handler.js.map +1 -1
- package/dist/utils/init-previewer.d.ts +56 -0
- package/dist/utils/init-previewer.js +217 -0
- package/dist/utils/init-previewer.js.map +1 -0
- package/dist/utils/init-validator.d.ts +61 -0
- package/dist/utils/init-validator.js +248 -0
- package/dist/utils/init-validator.js.map +1 -0
- package/dist/utils/onboarding-manager.js +34 -9
- package/dist/utils/onboarding-manager.js.map +1 -1
- package/dist/utils/path-utils.d.ts +83 -0
- package/dist/utils/path-utils.js +122 -0
- package/dist/utils/path-utils.js.map +1 -0
- package/dist/utils/progress-tracker.d.ts +51 -0
- package/dist/utils/progress-tracker.js +152 -0
- package/dist/utils/progress-tracker.js.map +1 -0
- package/dist/utils/project-analyzer.js +8 -14
- package/dist/utils/project-analyzer.js.map +1 -1
- package/dist/utils/settings-manager.d.ts +3 -3
- package/dist/utils/settings-manager.js +6 -13
- package/dist/utils/settings-manager.js.map +1 -1
- package/dist/utils/string-utils.d.ts +19 -0
- package/dist/utils/string-utils.js +28 -0
- package/dist/utils/string-utils.js.map +1 -0
- package/dist/utils/template-manager.d.ts +54 -0
- package/dist/utils/template-manager.js +421 -0
- package/dist/utils/template-manager.js.map +1 -0
- package/dist/utils/text-utils.js +3 -1
- package/dist/utils/text-utils.js.map +1 -1
- package/package.json +2 -1
- package/vitest.config.ts +6 -0
- package/dist/utils/model-config.d.ts +0 -28
- package/dist/utils/model-config.js +0 -43
- package/dist/utils/model-config.js.map +0 -1
- package/dist/utils/tool-helpers.d.ts +0 -25
- package/dist/utils/tool-helpers.js +0 -53
- package/dist/utils/tool-helpers.js.map +0 -1
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation utilities for init command
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { parseJson, parseJsonFile } from './json-utils.js';
|
|
7
|
+
export class InitValidator {
|
|
8
|
+
projectRoot;
|
|
9
|
+
constructor(projectRoot) {
|
|
10
|
+
this.projectRoot = projectRoot;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Run all validation checks
|
|
14
|
+
*/
|
|
15
|
+
validate(projectInfo) {
|
|
16
|
+
const result = {
|
|
17
|
+
valid: true,
|
|
18
|
+
warnings: [],
|
|
19
|
+
errors: [],
|
|
20
|
+
suggestions: [],
|
|
21
|
+
};
|
|
22
|
+
// Check for package.json
|
|
23
|
+
this.checkPackageJson(result);
|
|
24
|
+
// Check for git repository
|
|
25
|
+
this.checkGitRepo(result);
|
|
26
|
+
// Check for existing AX CLI config
|
|
27
|
+
this.checkExistingConfig(result);
|
|
28
|
+
// Check project structure
|
|
29
|
+
this.checkProjectStructure(result);
|
|
30
|
+
// Check if project has minimum files
|
|
31
|
+
this.checkMinimumFiles(result);
|
|
32
|
+
// Validate project info if provided
|
|
33
|
+
if (projectInfo) {
|
|
34
|
+
this.validateProjectInfo(projectInfo, result);
|
|
35
|
+
}
|
|
36
|
+
// Set overall validity
|
|
37
|
+
result.valid = result.errors.length === 0;
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check for package.json
|
|
42
|
+
*/
|
|
43
|
+
checkPackageJson(result) {
|
|
44
|
+
const packageJsonPath = path.join(this.projectRoot, 'package.json');
|
|
45
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
46
|
+
result.warnings.push('No package.json found - may not be a Node.js project');
|
|
47
|
+
result.suggestions.push('Run: npm init (if this is a Node.js project)');
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
try {
|
|
51
|
+
const content = fs.readFileSync(packageJsonPath, 'utf-8');
|
|
52
|
+
// Check for empty file
|
|
53
|
+
if (!content || content.trim() === '') {
|
|
54
|
+
result.errors.push('package.json is empty');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const parseResult = parseJson(content);
|
|
58
|
+
if (!parseResult.success) {
|
|
59
|
+
result.errors.push(`Invalid package.json - ${parseResult.error}`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const packageJson = parseResult.data;
|
|
63
|
+
// Check if package.json is actually an object
|
|
64
|
+
if (typeof packageJson !== 'object' || packageJson === null) {
|
|
65
|
+
result.errors.push('package.json is not a valid JSON object');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Check for common issues
|
|
69
|
+
if (!packageJson.name) {
|
|
70
|
+
result.warnings.push('package.json missing "name" field');
|
|
71
|
+
}
|
|
72
|
+
if (!packageJson.version) {
|
|
73
|
+
result.warnings.push('package.json missing "version" field');
|
|
74
|
+
}
|
|
75
|
+
// Check for type: module (ESM)
|
|
76
|
+
if (packageJson.type !== 'module') {
|
|
77
|
+
result.suggestions.push('Consider adding "type": "module" for ESM support');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
result.errors.push(`Invalid package.json - ${error instanceof Error ? error.message : 'File read error'}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check for git repository
|
|
87
|
+
*/
|
|
88
|
+
checkGitRepo(result) {
|
|
89
|
+
const gitDir = path.join(this.projectRoot, '.git');
|
|
90
|
+
if (!fs.existsSync(gitDir)) {
|
|
91
|
+
result.warnings.push('Not a git repository');
|
|
92
|
+
result.suggestions.push('Run: git init (for version control)');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Check for existing AX CLI configuration
|
|
97
|
+
*/
|
|
98
|
+
checkExistingConfig(result) {
|
|
99
|
+
const axCliDir = path.join(this.projectRoot, '.ax-cli');
|
|
100
|
+
const customMdPath = path.join(axCliDir, 'CUSTOM.md');
|
|
101
|
+
const indexPath = path.join(axCliDir, 'index.json');
|
|
102
|
+
if (fs.existsSync(customMdPath)) {
|
|
103
|
+
result.warnings.push('Existing CUSTOM.md found - will be overwritten unless --force is used');
|
|
104
|
+
}
|
|
105
|
+
if (fs.existsSync(indexPath)) {
|
|
106
|
+
const parseResult = parseJsonFile(indexPath);
|
|
107
|
+
if (parseResult.success) {
|
|
108
|
+
const indexData = parseResult.data;
|
|
109
|
+
const lastUpdated = indexData.lastAnalyzed || indexData.templateAppliedAt;
|
|
110
|
+
if (lastUpdated) {
|
|
111
|
+
const date = new Date(lastUpdated);
|
|
112
|
+
const daysSince = Math.floor((Date.now() - date.getTime()) / (1000 * 60 * 60 * 24));
|
|
113
|
+
if (daysSince > 30) {
|
|
114
|
+
result.suggestions.push(`CUSTOM.md is ${daysSince} days old - consider refreshing`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
result.warnings.push('Existing index.json is invalid');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Check project structure
|
|
125
|
+
*/
|
|
126
|
+
checkProjectStructure(result) {
|
|
127
|
+
const commonDirs = ['src', 'lib', 'dist', 'build', 'test', 'tests', '__tests__'];
|
|
128
|
+
const foundDirs = commonDirs.filter(dir => fs.existsSync(path.join(this.projectRoot, dir)));
|
|
129
|
+
if (foundDirs.length === 0) {
|
|
130
|
+
result.warnings.push('No standard project directories found (src/, lib/, etc.)');
|
|
131
|
+
result.suggestions.push('Project may be empty or have non-standard structure');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Check for minimum files
|
|
136
|
+
*/
|
|
137
|
+
checkMinimumFiles(result) {
|
|
138
|
+
try {
|
|
139
|
+
const files = fs.readdirSync(this.projectRoot);
|
|
140
|
+
const nonHiddenFiles = files.filter(f => !f.startsWith('.'));
|
|
141
|
+
if (nonHiddenFiles.length === 0) {
|
|
142
|
+
result.errors.push('Project directory is empty');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (nonHiddenFiles.length === 1 && nonHiddenFiles[0] === 'package.json') {
|
|
146
|
+
result.warnings.push('Project only contains package.json - no source files found');
|
|
147
|
+
result.suggestions.push('Add source files before initializing AX CLI');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
result.errors.push(`Cannot read project directory: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Validate project info
|
|
156
|
+
*/
|
|
157
|
+
validateProjectInfo(projectInfo, result) {
|
|
158
|
+
// Check if project type was detected
|
|
159
|
+
if (projectInfo.projectType === 'unknown' || projectInfo.projectType === 'application') {
|
|
160
|
+
result.warnings.push('Could not determine specific project type');
|
|
161
|
+
result.suggestions.push('Consider using a template: ax-cli init --template <type>');
|
|
162
|
+
}
|
|
163
|
+
// Check if primary language was detected
|
|
164
|
+
if (projectInfo.primaryLanguage === 'Unknown') {
|
|
165
|
+
result.warnings.push('Could not determine primary programming language');
|
|
166
|
+
}
|
|
167
|
+
// Check if tech stack was detected
|
|
168
|
+
if (projectInfo.techStack.length === 0) {
|
|
169
|
+
result.warnings.push('No tech stack detected');
|
|
170
|
+
result.suggestions.push('Ensure package.json has dependencies listed');
|
|
171
|
+
}
|
|
172
|
+
// Check entry point
|
|
173
|
+
if (!projectInfo.entryPoint) {
|
|
174
|
+
result.warnings.push('No entry point detected');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Validate custom instructions content
|
|
179
|
+
*/
|
|
180
|
+
static validateCustomInstructions(content) {
|
|
181
|
+
const result = {
|
|
182
|
+
valid: true,
|
|
183
|
+
warnings: [],
|
|
184
|
+
errors: [],
|
|
185
|
+
suggestions: [],
|
|
186
|
+
};
|
|
187
|
+
// Check minimum length
|
|
188
|
+
if (content.length < 100) {
|
|
189
|
+
result.errors.push('CUSTOM.md is too short (< 100 characters)');
|
|
190
|
+
}
|
|
191
|
+
// Check for required sections
|
|
192
|
+
const requiredSections = [
|
|
193
|
+
'## 🎯 Critical Rules',
|
|
194
|
+
'## 📋 Project Overview',
|
|
195
|
+
'## 🔧 Code Patterns',
|
|
196
|
+
];
|
|
197
|
+
for (const section of requiredSections) {
|
|
198
|
+
if (!content.includes(section)) {
|
|
199
|
+
result.warnings.push(`Missing recommended section: ${section}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// Check token count (rough estimate)
|
|
203
|
+
const estimatedTokens = Math.ceil(content.length / 4);
|
|
204
|
+
if (estimatedTokens > 2000) {
|
|
205
|
+
result.warnings.push(`CUSTOM.md is large (~${estimatedTokens} tokens)`);
|
|
206
|
+
result.suggestions.push('Consider using template imports or reducing content');
|
|
207
|
+
}
|
|
208
|
+
// Check for common issues
|
|
209
|
+
if (content.includes('TODO') || content.includes('FIXME')) {
|
|
210
|
+
result.warnings.push('CUSTOM.md contains TODO/FIXME markers');
|
|
211
|
+
}
|
|
212
|
+
if (content.includes('__placeholder__') || content.includes('<insert')) {
|
|
213
|
+
result.errors.push('CUSTOM.md contains placeholder text');
|
|
214
|
+
}
|
|
215
|
+
result.valid = result.errors.length === 0;
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Check if force flag is needed
|
|
220
|
+
*/
|
|
221
|
+
needsForceFlag() {
|
|
222
|
+
const customMdPath = path.join(this.projectRoot, '.ax-cli', 'CUSTOM.md');
|
|
223
|
+
return fs.existsSync(customMdPath);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Get validation summary string
|
|
227
|
+
*/
|
|
228
|
+
static formatValidationResult(result) {
|
|
229
|
+
const parts = [];
|
|
230
|
+
if (result.errors.length > 0) {
|
|
231
|
+
parts.push('❌ Errors:');
|
|
232
|
+
result.errors.forEach(e => parts.push(` - ${e}`));
|
|
233
|
+
}
|
|
234
|
+
if (result.warnings.length > 0) {
|
|
235
|
+
parts.push('⚠️ Warnings:');
|
|
236
|
+
result.warnings.forEach(w => parts.push(` - ${w}`));
|
|
237
|
+
}
|
|
238
|
+
if (result.suggestions.length > 0) {
|
|
239
|
+
parts.push('💡 Suggestions:');
|
|
240
|
+
result.suggestions.forEach(s => parts.push(` - ${s}`));
|
|
241
|
+
}
|
|
242
|
+
if (result.valid && result.warnings.length === 0 && result.suggestions.length === 0) {
|
|
243
|
+
parts.push('✅ All validation checks passed');
|
|
244
|
+
}
|
|
245
|
+
return parts.join('\n');
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=init-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-validator.js","sourceRoot":"","sources":["../../src/utils/init-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
import * as fs from 'fs';
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import * as os from 'os';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import { parseJsonFile } from './json-utils.js';
|
|
7
9
|
export class OnboardingManager {
|
|
8
10
|
static FIRST_RUN_MARKER = '.first-run-complete';
|
|
9
11
|
static USER_CONFIG_DIR = '.ax-cli';
|
|
@@ -43,7 +45,24 @@ export class OnboardingManager {
|
|
|
43
45
|
completedAt: new Date().toISOString(),
|
|
44
46
|
version: this.getVersion(),
|
|
45
47
|
};
|
|
46
|
-
|
|
48
|
+
// Atomic write using temp file
|
|
49
|
+
const tmpPath = `${markerPath}.tmp`;
|
|
50
|
+
try {
|
|
51
|
+
fs.writeFileSync(tmpPath, JSON.stringify(state, null, 2), 'utf-8');
|
|
52
|
+
fs.renameSync(tmpPath, markerPath); // Atomic on POSIX systems
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
// Cleanup temp file on error
|
|
56
|
+
if (fs.existsSync(tmpPath)) {
|
|
57
|
+
try {
|
|
58
|
+
fs.unlinkSync(tmpPath);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Ignore cleanup errors
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
47
66
|
}
|
|
48
67
|
/**
|
|
49
68
|
* Get current onboarding state
|
|
@@ -57,11 +76,8 @@ export class OnboardingManager {
|
|
|
57
76
|
version: this.getVersion(),
|
|
58
77
|
};
|
|
59
78
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return JSON.parse(content);
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
79
|
+
const parseResult = parseJsonFile(markerPath);
|
|
80
|
+
if (!parseResult.success) {
|
|
65
81
|
// If marker file is corrupted, treat as first run
|
|
66
82
|
return {
|
|
67
83
|
isFirstRun: true,
|
|
@@ -69,6 +85,7 @@ export class OnboardingManager {
|
|
|
69
85
|
version: this.getVersion(),
|
|
70
86
|
};
|
|
71
87
|
}
|
|
88
|
+
return parseResult.data;
|
|
72
89
|
}
|
|
73
90
|
/**
|
|
74
91
|
* Reset onboarding state (useful for testing)
|
|
@@ -90,10 +107,18 @@ export class OnboardingManager {
|
|
|
90
107
|
*/
|
|
91
108
|
static getVersion() {
|
|
92
109
|
try {
|
|
93
|
-
|
|
110
|
+
// Use import.meta.url to find the actual CLI installation path
|
|
111
|
+
const currentModulePath = fileURLToPath(import.meta.url);
|
|
112
|
+
const cliRootPath = path.join(path.dirname(currentModulePath), '../..');
|
|
113
|
+
const packageJsonPath = path.join(cliRootPath, 'package.json');
|
|
94
114
|
if (fs.existsSync(packageJsonPath)) {
|
|
95
|
-
const
|
|
96
|
-
|
|
115
|
+
const parseResult = parseJsonFile(packageJsonPath);
|
|
116
|
+
if (parseResult.success) {
|
|
117
|
+
const pkg = parseResult.data;
|
|
118
|
+
if (pkg && typeof pkg === 'object' && 'version' in pkg && typeof pkg.version === 'string') {
|
|
119
|
+
return pkg.version;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
97
122
|
}
|
|
98
123
|
}
|
|
99
124
|
catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onboarding-manager.js","sourceRoot":"","sources":["../../src/utils/onboarding-manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"onboarding-manager.js","sourceRoot":"","sources":["../../src/utils/onboarding-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform path utility functions
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities for handling file paths consistently
|
|
5
|
+
* across different operating systems (Windows, macOS, Linux).
|
|
6
|
+
*
|
|
7
|
+
* @module path-utils
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Normalize path separators to forward slashes (for display and logging)
|
|
11
|
+
*
|
|
12
|
+
* This function converts all path separators to forward slashes, which is
|
|
13
|
+
* useful for consistent display across platforms and for comparison in tests.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // Windows
|
|
17
|
+
* normalizePath('C:\\Users\\foo\\bar') // => 'C:/Users/foo/bar'
|
|
18
|
+
*
|
|
19
|
+
* // Unix
|
|
20
|
+
* normalizePath('/Users/foo/bar') // => '/Users/foo/bar'
|
|
21
|
+
*
|
|
22
|
+
* @param filePath - The path to normalize
|
|
23
|
+
* @returns Path with forward slashes (empty string if input is falsy)
|
|
24
|
+
*/
|
|
25
|
+
export declare function normalizePath(filePath: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Convert path to platform-native format (for filesystem operations)
|
|
28
|
+
*
|
|
29
|
+
* This function normalizes the path to use the platform's native separator,
|
|
30
|
+
* which is necessary for filesystem operations.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // Windows
|
|
34
|
+
* platformPath('foo/bar/baz') // => 'foo\\bar\\baz'
|
|
35
|
+
*
|
|
36
|
+
* // Unix
|
|
37
|
+
* platformPath('foo/bar/baz') // => 'foo/bar/baz'
|
|
38
|
+
*
|
|
39
|
+
* @param filePath - The path to convert
|
|
40
|
+
* @returns Path with platform-native separators (empty string if input is falsy)
|
|
41
|
+
*/
|
|
42
|
+
export declare function platformPath(filePath: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* Check if running on Windows
|
|
45
|
+
*
|
|
46
|
+
* @returns True if running on Windows platform
|
|
47
|
+
*/
|
|
48
|
+
export declare function isWindows(): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Compare two paths for equality (ignoring separator differences)
|
|
51
|
+
*
|
|
52
|
+
* This function compares two paths by normalizing both to forward slashes
|
|
53
|
+
* and then comparing case-insensitively on Windows.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* // Windows
|
|
57
|
+
* pathsEqual('foo/bar', 'foo\\bar') // => true
|
|
58
|
+
* pathsEqual('Foo/Bar', 'foo/bar') // => true
|
|
59
|
+
*
|
|
60
|
+
* // Unix
|
|
61
|
+
* pathsEqual('foo/bar', 'foo/bar') // => true
|
|
62
|
+
* pathsEqual('Foo/Bar', 'foo/bar') // => false
|
|
63
|
+
*
|
|
64
|
+
* @param path1 - First path to compare
|
|
65
|
+
* @param path2 - Second path to compare
|
|
66
|
+
* @returns True if paths are equal
|
|
67
|
+
*/
|
|
68
|
+
export declare function pathsEqual(path1: string, path2: string): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Check if a path contains a segment (cross-platform)
|
|
71
|
+
*
|
|
72
|
+
* This function checks if a full path contains a specific segment,
|
|
73
|
+
* normalizing both paths before comparison.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* pathContains('/foo/bar/baz', 'bar/baz') // => true
|
|
77
|
+
* pathContains('C:\\foo\\bar', 'bar') // => true
|
|
78
|
+
*
|
|
79
|
+
* @param fullPath - Full path to search in
|
|
80
|
+
* @param segment - Segment to search for
|
|
81
|
+
* @returns True if fullPath contains segment
|
|
82
|
+
*/
|
|
83
|
+
export declare function pathContains(fullPath: string, segment: string): boolean;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform path utility functions
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities for handling file paths consistently
|
|
5
|
+
* across different operating systems (Windows, macOS, Linux).
|
|
6
|
+
*
|
|
7
|
+
* @module path-utils
|
|
8
|
+
*/
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import os from 'node:os';
|
|
11
|
+
import { equalsIgnoreCase, containsIgnoreCase } from './string-utils.js';
|
|
12
|
+
/**
|
|
13
|
+
* Normalize path separators to forward slashes (for display and logging)
|
|
14
|
+
*
|
|
15
|
+
* This function converts all path separators to forward slashes, which is
|
|
16
|
+
* useful for consistent display across platforms and for comparison in tests.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Windows
|
|
20
|
+
* normalizePath('C:\\Users\\foo\\bar') // => 'C:/Users/foo/bar'
|
|
21
|
+
*
|
|
22
|
+
* // Unix
|
|
23
|
+
* normalizePath('/Users/foo/bar') // => '/Users/foo/bar'
|
|
24
|
+
*
|
|
25
|
+
* @param filePath - The path to normalize
|
|
26
|
+
* @returns Path with forward slashes (empty string if input is falsy)
|
|
27
|
+
*/
|
|
28
|
+
export function normalizePath(filePath) {
|
|
29
|
+
if (!filePath)
|
|
30
|
+
return '';
|
|
31
|
+
// Replace all backslashes with forward slashes
|
|
32
|
+
// This works consistently across all platforms
|
|
33
|
+
return filePath.replace(/\\/g, '/');
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Convert path to platform-native format (for filesystem operations)
|
|
37
|
+
*
|
|
38
|
+
* This function normalizes the path to use the platform's native separator,
|
|
39
|
+
* which is necessary for filesystem operations.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* // Windows
|
|
43
|
+
* platformPath('foo/bar/baz') // => 'foo\\bar\\baz'
|
|
44
|
+
*
|
|
45
|
+
* // Unix
|
|
46
|
+
* platformPath('foo/bar/baz') // => 'foo/bar/baz'
|
|
47
|
+
*
|
|
48
|
+
* @param filePath - The path to convert
|
|
49
|
+
* @returns Path with platform-native separators (empty string if input is falsy)
|
|
50
|
+
*/
|
|
51
|
+
export function platformPath(filePath) {
|
|
52
|
+
if (!filePath)
|
|
53
|
+
return '';
|
|
54
|
+
return path.normalize(filePath);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Check if running on Windows
|
|
58
|
+
*
|
|
59
|
+
* @returns True if running on Windows platform
|
|
60
|
+
*/
|
|
61
|
+
export function isWindows() {
|
|
62
|
+
return os.platform() === 'win32';
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Compare two paths for equality (ignoring separator differences)
|
|
66
|
+
*
|
|
67
|
+
* This function compares two paths by normalizing both to forward slashes
|
|
68
|
+
* and then comparing case-insensitively on Windows.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* // Windows
|
|
72
|
+
* pathsEqual('foo/bar', 'foo\\bar') // => true
|
|
73
|
+
* pathsEqual('Foo/Bar', 'foo/bar') // => true
|
|
74
|
+
*
|
|
75
|
+
* // Unix
|
|
76
|
+
* pathsEqual('foo/bar', 'foo/bar') // => true
|
|
77
|
+
* pathsEqual('Foo/Bar', 'foo/bar') // => false
|
|
78
|
+
*
|
|
79
|
+
* @param path1 - First path to compare
|
|
80
|
+
* @param path2 - Second path to compare
|
|
81
|
+
* @returns True if paths are equal
|
|
82
|
+
*/
|
|
83
|
+
export function pathsEqual(path1, path2) {
|
|
84
|
+
// Handle null/undefined/empty cases
|
|
85
|
+
if (!path1 || !path2) {
|
|
86
|
+
return path1 === path2;
|
|
87
|
+
}
|
|
88
|
+
const normalized1 = normalizePath(path1);
|
|
89
|
+
const normalized2 = normalizePath(path2);
|
|
90
|
+
// Windows is case-insensitive
|
|
91
|
+
if (isWindows()) {
|
|
92
|
+
return equalsIgnoreCase(normalized1, normalized2);
|
|
93
|
+
}
|
|
94
|
+
return normalized1 === normalized2;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Check if a path contains a segment (cross-platform)
|
|
98
|
+
*
|
|
99
|
+
* This function checks if a full path contains a specific segment,
|
|
100
|
+
* normalizing both paths before comparison.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* pathContains('/foo/bar/baz', 'bar/baz') // => true
|
|
104
|
+
* pathContains('C:\\foo\\bar', 'bar') // => true
|
|
105
|
+
*
|
|
106
|
+
* @param fullPath - Full path to search in
|
|
107
|
+
* @param segment - Segment to search for
|
|
108
|
+
* @returns True if fullPath contains segment
|
|
109
|
+
*/
|
|
110
|
+
export function pathContains(fullPath, segment) {
|
|
111
|
+
if (!fullPath || !segment) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
const normalizedFull = normalizePath(fullPath);
|
|
115
|
+
const normalizedSegment = normalizePath(segment);
|
|
116
|
+
// Windows is case-insensitive
|
|
117
|
+
if (isWindows()) {
|
|
118
|
+
return containsIgnoreCase(normalizedFull, normalizedSegment);
|
|
119
|
+
}
|
|
120
|
+
return normalizedFull.includes(normalizedSegment);
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=path-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-utils.js","sourceRoot":"","sources":["../../src/utils/path-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IACzB,+CAA+C;IAC/C,+CAA+C;IAC/C,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IACzB,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,EAAE,CAAC,QAAQ,EAAE,KAAK,OAAO,CAAC;AACnC,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,KAAa;IACrD,oCAAoC;IACpC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,KAAK,KAAK,KAAK,CAAC;IACzB,CAAC;IAED,MAAM,WAAW,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEzC,8BAA8B;IAC9B,IAAI,SAAS,EAAE,EAAE,CAAC;QAChB,OAAO,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,WAAW,KAAK,WAAW,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,OAAe;IAC5D,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,cAAc,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,iBAAiB,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IAEjD,8BAA8B;IAC9B,IAAI,SAAS,EAAE,EAAE,CAAC;QAChB,OAAO,kBAAkB,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO,cAAc,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progress tracking utility for init command
|
|
3
|
+
*/
|
|
4
|
+
export interface ProgressStep {
|
|
5
|
+
name: string;
|
|
6
|
+
status: 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
7
|
+
startTime?: number;
|
|
8
|
+
endTime?: number;
|
|
9
|
+
details?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class ProgressTracker {
|
|
12
|
+
private steps;
|
|
13
|
+
private spinner?;
|
|
14
|
+
private currentStep?;
|
|
15
|
+
/**
|
|
16
|
+
* Add a step to track
|
|
17
|
+
*/
|
|
18
|
+
addStep(id: string, name: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Start a step
|
|
21
|
+
*/
|
|
22
|
+
startStep(id: string, message?: string): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Complete a step
|
|
25
|
+
*/
|
|
26
|
+
completeStep(id: string, details?: string): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Fail a step
|
|
29
|
+
*/
|
|
30
|
+
failStep(id: string, error: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Update step message
|
|
33
|
+
*/
|
|
34
|
+
updateMessage(message: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Format duration in human-readable form
|
|
37
|
+
*/
|
|
38
|
+
private formatDuration;
|
|
39
|
+
/**
|
|
40
|
+
* Get summary of all steps
|
|
41
|
+
*/
|
|
42
|
+
getSummary(): string;
|
|
43
|
+
/**
|
|
44
|
+
* Stop any active spinner
|
|
45
|
+
*/
|
|
46
|
+
stop(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Cleanup and destroy tracker
|
|
49
|
+
*/
|
|
50
|
+
destroy(): void;
|
|
51
|
+
}
|