claude-autopm 1.18.0 → 1.20.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.
Files changed (108) hide show
  1. package/README.md +159 -0
  2. package/autopm/.claude/agents/README.md +1 -1
  3. package/autopm/.claude/agents/core/mcp-manager.md +1 -1
  4. package/autopm/.claude/agents/decision-matrices/python-backend-selection.md +25 -25
  5. package/autopm/.claude/agents/decision-matrices/ui-framework-selection.md +43 -43
  6. package/autopm/.claude/agents/devops/github-operations-specialist.md +1 -1
  7. package/autopm/.claude/agents/frameworks/README.md +5 -5
  8. package/autopm/.claude/agents/frameworks/e2e-test-engineer.md +1 -1
  9. package/autopm/.claude/agents/frameworks/nats-messaging-expert.md +1 -1
  10. package/autopm/.claude/agents/frameworks/react-frontend-engineer.md +1 -1
  11. package/autopm/.claude/agents/frameworks/react-ui-expert.md +3 -3
  12. package/autopm/.claude/agents/frameworks/tailwindcss-expert.md +3 -3
  13. package/autopm/.claude/agents/frameworks/ux-design-expert.md +3 -3
  14. package/autopm/.claude/commands/infrastructure/traefik-setup.md +1 -1
  15. package/autopm/.claude/commands/playwright/test-scaffold.md +1 -1
  16. package/autopm/.claude/commands/pm/context.md +11 -0
  17. package/autopm/.claude/commands/pm/epic-decompose.md +25 -2
  18. package/autopm/.claude/commands/pm/epic-oneshot.md +13 -0
  19. package/autopm/.claude/commands/pm/epic-start.md +19 -0
  20. package/autopm/.claude/commands/pm/epic-sync-modular.md +10 -10
  21. package/autopm/.claude/commands/pm/epic-sync.md +14 -14
  22. package/autopm/.claude/commands/pm/issue-start.md +50 -5
  23. package/autopm/.claude/commands/pm/issue-sync.md +15 -15
  24. package/autopm/.claude/commands/pm/what-next.md +11 -0
  25. package/autopm/.claude/commands/ui/bootstrap-scaffold.md +6 -5
  26. package/autopm/.claude/commands/ui/tailwind-system.md +1 -1
  27. package/autopm/.claude/examples/mcp/playwright-mcp.md +2 -2
  28. package/autopm/.claude/examples/mcp-servers.example.json +2 -2
  29. package/autopm/.claude/hooks/docker-first-enforcement.sh +1 -1
  30. package/autopm/.claude/mcp/MCP-REGISTRY.md +1 -1
  31. package/autopm/.claude/mcp/playwright-mcp.md +2 -2
  32. package/autopm/.claude/rules/agent-coordination.md +26 -24
  33. package/autopm/.claude/rules/docker-first-development.md +1 -1
  34. package/autopm/.claude/rules/infrastructure-pipeline.md +1 -1
  35. package/autopm/.claude/rules/ui-development-standards.md +1 -1
  36. package/autopm/.claude/rules/visual-testing.md +3 -3
  37. package/autopm/.claude/scripts/azure/active-work.js +2 -2
  38. package/autopm/.claude/scripts/azure/blocked.js +13 -13
  39. package/autopm/.claude/scripts/azure/daily.js +1 -1
  40. package/autopm/.claude/scripts/azure/dashboard.js +1 -1
  41. package/autopm/.claude/scripts/azure/feature-list.js +2 -2
  42. package/autopm/.claude/scripts/azure/feature-status.js +1 -1
  43. package/autopm/.claude/scripts/azure/next-task.js +1 -1
  44. package/autopm/.claude/scripts/azure/search.js +1 -1
  45. package/autopm/.claude/scripts/azure/setup.js +15 -15
  46. package/autopm/.claude/scripts/azure/sprint-report.js +2 -2
  47. package/autopm/.claude/scripts/azure/sync.js +1 -1
  48. package/autopm/.claude/scripts/azure/us-list.js +1 -1
  49. package/autopm/.claude/scripts/azure/us-status.js +1 -1
  50. package/autopm/.claude/scripts/azure/validate.js +13 -13
  51. package/autopm/.claude/scripts/lib/frontmatter-utils.sh +42 -7
  52. package/autopm/.claude/scripts/lib/logging-utils.sh +20 -16
  53. package/autopm/.claude/scripts/lib/validation-utils.sh +1 -1
  54. package/autopm/.claude/scripts/pm/context.js +338 -0
  55. package/autopm/.claude/scripts/pm/issue-sync/format-comment.sh +3 -3
  56. package/autopm/.claude/scripts/pm/lib/README.md +85 -0
  57. package/autopm/.claude/scripts/pm/lib/logger.js +78 -0
  58. package/autopm/.claude/scripts/pm/next.js +25 -1
  59. package/autopm/.claude/scripts/pm/what-next.js +660 -0
  60. package/autopm/.claude/teams.json +3 -5
  61. package/autopm/.claude/templates/claude-templates/addons/devops-agents.md +2 -2
  62. package/autopm/.claude/templates/claude-templates/addons/docker-agents.md +4 -4
  63. package/autopm/.claude/templates/claude-templates/addons/minimal-agents.md +1 -1
  64. package/autopm/.claude/templates/issue-decomposition/api.yaml +2 -2
  65. package/autopm/.claude/templates/issue-decomposition/auth.yaml +4 -4
  66. package/autopm/.claude/templates/issue-decomposition/crud.yaml +3 -3
  67. package/autopm/.claude/templates/issue-decomposition/default.yaml +1 -1
  68. package/autopm/.claude/templates/issue-decomposition/ui-feature.yaml +2 -2
  69. package/bin/autopm.js +25 -0
  70. package/package.json +1 -2
  71. package/lib/agentExecutor.js.deprecated +0 -101
  72. package/lib/azure/cache.js +0 -80
  73. package/lib/azure/client.js +0 -77
  74. package/lib/azure/formatter.js +0 -177
  75. package/lib/commandHelpers.js +0 -177
  76. package/lib/context/manager.js +0 -290
  77. package/lib/documentation/manager.js +0 -528
  78. package/lib/github/workflow-manager.js +0 -546
  79. package/lib/helpers/azure-batch-api.js +0 -133
  80. package/lib/helpers/azure-cache-manager.js +0 -287
  81. package/lib/helpers/azure-parallel-processor.js +0 -158
  82. package/lib/helpers/azure-work-item-create.js +0 -278
  83. package/lib/helpers/gh-issue-create.js +0 -250
  84. package/lib/helpers/interactive-prompt.js +0 -336
  85. package/lib/helpers/output-manager.js +0 -335
  86. package/lib/helpers/progress-indicator.js +0 -258
  87. package/lib/performance/benchmarker.js +0 -429
  88. package/lib/pm/epic-decomposer.js +0 -273
  89. package/lib/pm/epic-syncer.js +0 -221
  90. package/lib/prdMetadata.js +0 -270
  91. package/lib/providers/azure/index.js +0 -234
  92. package/lib/providers/factory.js +0 -87
  93. package/lib/providers/github/index.js +0 -204
  94. package/lib/providers/interface.js +0 -73
  95. package/lib/python/scaffold-manager.js +0 -576
  96. package/lib/react/scaffold-manager.js +0 -745
  97. package/lib/regression/analyzer.js +0 -578
  98. package/lib/release/manager.js +0 -324
  99. package/lib/tailwind/manager.js +0 -486
  100. package/lib/traefik/manager.js +0 -484
  101. package/lib/utils/colors.js +0 -126
  102. package/lib/utils/config.js +0 -317
  103. package/lib/utils/filesystem.js +0 -316
  104. package/lib/utils/logger.js +0 -135
  105. package/lib/utils/prompts.js +0 -294
  106. package/lib/utils/shell.js +0 -237
  107. package/lib/validators/email-validator.js +0 -337
  108. package/lib/workflow/manager.js +0 -449
@@ -1,317 +0,0 @@
1
- /**
2
- * Configuration management utility
3
- * Handles loading and saving configuration files
4
- */
5
-
6
- const fs = require('fs-extra');
7
- const path = require('path');
8
- const yaml = require('js-yaml');
9
- const dotenv = require('dotenv');
10
-
11
- class Config {
12
- constructor(logger) {
13
- this.logger = logger;
14
- this.configDir = '.claude';
15
- this.configFile = 'config.json';
16
- }
17
-
18
- /**
19
- * Get config file path
20
- */
21
- getConfigPath(projectPath = process.cwd()) {
22
- return path.join(projectPath, this.configDir, this.configFile);
23
- }
24
-
25
- /**
26
- * Load configuration
27
- */
28
- async load(projectPath = process.cwd()) {
29
- const configPath = this.getConfigPath(projectPath);
30
-
31
- try {
32
- if (await fs.pathExists(configPath)) {
33
- const config = await fs.readJson(configPath);
34
- this.logger.debug(`Loaded configuration from: ${configPath}`);
35
- return config;
36
- }
37
-
38
- this.logger.debug('No configuration file found, using defaults');
39
- return this.getDefaultConfig();
40
- } catch (error) {
41
- this.logger.error('Failed to load configuration', error);
42
- return this.getDefaultConfig();
43
- }
44
- }
45
-
46
- /**
47
- * Save configuration
48
- */
49
- async save(config, projectPath = process.cwd()) {
50
- const configPath = this.getConfigPath(projectPath);
51
-
52
- try {
53
- await fs.ensureDir(path.dirname(configPath));
54
- await fs.writeJson(configPath, config, { spaces: 2 });
55
- this.logger.success(`Configuration saved to: ${configPath}`);
56
- return true;
57
- } catch (error) {
58
- this.logger.error('Failed to save configuration', error);
59
- throw error;
60
- }
61
- }
62
-
63
- /**
64
- * Get default configuration
65
- */
66
- getDefaultConfig() {
67
- return {
68
- version: '1.0.0',
69
- provider: 'github',
70
- executionStrategy: 'adaptive',
71
- features: {
72
- docker_first_development: false,
73
- kubernetes_devops_testing: false,
74
- github_actions_k8s: false,
75
- enforce_docker_tests: false,
76
- integration_tests: true
77
- },
78
- paths: {
79
- epics: '.claude/epics',
80
- prds: '.claude/prds',
81
- context: '.claude/context'
82
- },
83
- settings: {
84
- verbose: false,
85
- autoSync: false,
86
- parallelExecution: true
87
- }
88
- };
89
- }
90
-
91
- /**
92
- * Merge configurations
93
- */
94
- mergeConfig(base, updates) {
95
- return {
96
- ...base,
97
- ...updates,
98
- features: {
99
- ...base.features,
100
- ...(updates.features || {})
101
- },
102
- paths: {
103
- ...base.paths,
104
- ...(updates.paths || {})
105
- },
106
- settings: {
107
- ...base.settings,
108
- ...(updates.settings || {})
109
- }
110
- };
111
- }
112
-
113
- /**
114
- * Load environment variables
115
- */
116
- async loadEnv(projectPath = process.cwd()) {
117
- const envPath = path.join(projectPath, this.configDir, '.env');
118
-
119
- try {
120
- if (await fs.pathExists(envPath)) {
121
- dotenv.config({ path: envPath });
122
- this.logger.debug(`Loaded environment variables from: ${envPath}`);
123
- return true;
124
- }
125
-
126
- this.logger.debug('No .env file found');
127
- return false;
128
- } catch (error) {
129
- this.logger.error('Failed to load .env file', error);
130
- return false;
131
- }
132
- }
133
-
134
- /**
135
- * Save environment variables
136
- */
137
- async saveEnv(variables, projectPath = process.cwd()) {
138
- const envPath = path.join(projectPath, this.configDir, '.env');
139
-
140
- try {
141
- await fs.ensureDir(path.dirname(envPath));
142
-
143
- const envContent = Object.entries(variables)
144
- .map(([key, value]) => `${key}="${value}"`)
145
- .join('\n');
146
-
147
- await fs.writeFile(envPath, envContent);
148
- await fs.chmod(envPath, 0o600); // Secure permissions
149
-
150
- this.logger.success(`Environment variables saved to: ${envPath}`);
151
- return true;
152
- } catch (error) {
153
- this.logger.error('Failed to save .env file', error);
154
- throw error;
155
- }
156
- }
157
-
158
- /**
159
- * Get configuration presets
160
- */
161
- getPresets() {
162
- return {
163
- minimal: {
164
- executionStrategy: 'sequential',
165
- features: {
166
- docker_first_development: false,
167
- kubernetes_devops_testing: false,
168
- github_actions_k8s: false,
169
- enforce_docker_tests: false,
170
- integration_tests: true
171
- }
172
- },
173
- docker: {
174
- executionStrategy: 'adaptive',
175
- features: {
176
- docker_first_development: true,
177
- kubernetes_devops_testing: false,
178
- github_actions_k8s: false,
179
- enforce_docker_tests: true,
180
- integration_tests: true
181
- }
182
- },
183
- devops: {
184
- executionStrategy: 'adaptive',
185
- features: {
186
- docker_first_development: true,
187
- kubernetes_devops_testing: true,
188
- github_actions_k8s: true,
189
- enforce_docker_tests: true,
190
- integration_tests: true
191
- }
192
- },
193
- performance: {
194
- executionStrategy: 'hybrid-parallel',
195
- features: {
196
- docker_first_development: false,
197
- kubernetes_devops_testing: false,
198
- github_actions_k8s: false,
199
- enforce_docker_tests: false,
200
- integration_tests: true
201
- },
202
- settings: {
203
- parallelExecution: true
204
- }
205
- }
206
- };
207
- }
208
-
209
- /**
210
- * Apply preset configuration
211
- */
212
- applyPreset(presetName) {
213
- const presets = this.getPresets();
214
- const preset = presets[presetName];
215
-
216
- if (!preset) {
217
- throw new Error(`Unknown preset: ${presetName}`);
218
- }
219
-
220
- const defaultConfig = this.getDefaultConfig();
221
- return this.mergeConfig(defaultConfig, preset);
222
- }
223
-
224
- /**
225
- * Validate configuration
226
- */
227
- validateConfig(config) {
228
- const errors = [];
229
-
230
- // Check required fields
231
- if (!config.version) {
232
- errors.push('Missing version field');
233
- }
234
-
235
- if (!config.provider) {
236
- errors.push('Missing provider field');
237
- }
238
-
239
- if (!['github', 'azure'].includes(config.provider)) {
240
- errors.push(`Invalid provider: ${config.provider}`);
241
- }
242
-
243
- if (!config.executionStrategy) {
244
- errors.push('Missing executionStrategy field');
245
- }
246
-
247
- const validStrategies = ['sequential', 'adaptive', 'hybrid-parallel'];
248
- if (!validStrategies.includes(config.executionStrategy)) {
249
- errors.push(`Invalid executionStrategy: ${config.executionStrategy}`);
250
- }
251
-
252
- return {
253
- valid: errors.length === 0,
254
- errors
255
- };
256
- }
257
-
258
- /**
259
- * Load YAML configuration
260
- */
261
- async loadYaml(filepath) {
262
- try {
263
- const content = await fs.readFile(filepath, 'utf8');
264
- return yaml.load(content);
265
- } catch (error) {
266
- this.logger.error(`Failed to load YAML file: ${filepath}`, error);
267
- throw error;
268
- }
269
- }
270
-
271
- /**
272
- * Save YAML configuration
273
- */
274
- async saveYaml(filepath, data) {
275
- try {
276
- const content = yaml.dump(data, { indent: 2 });
277
- await fs.writeFile(filepath, content);
278
- this.logger.debug(`Saved YAML file: ${filepath}`);
279
- return true;
280
- } catch (error) {
281
- this.logger.error(`Failed to save YAML file: ${filepath}`, error);
282
- throw error;
283
- }
284
- }
285
-
286
- /**
287
- * Check if project is configured
288
- */
289
- async isConfigured(projectPath = process.cwd()) {
290
- const configPath = this.getConfigPath(projectPath);
291
- return fs.pathExists(configPath);
292
- }
293
-
294
- /**
295
- * Get provider-specific settings
296
- */
297
- getProviderSettings(config) {
298
- switch (config.provider) {
299
- case 'github':
300
- return {
301
- useSubIssues: true,
302
- labelsPrefix: 'pm:',
303
- ...config.github
304
- };
305
- case 'azure':
306
- return {
307
- organization: process.env.AZURE_DEVOPS_ORG,
308
- project: process.env.AZURE_DEVOPS_PROJECT,
309
- ...config.azure
310
- };
311
- default:
312
- return {};
313
- }
314
- }
315
- }
316
-
317
- module.exports = Config;
@@ -1,316 +0,0 @@
1
- /**
2
- * Filesystem utility for cross-platform file operations
3
- * Wraps fs-extra with additional safety and logging
4
- */
5
-
6
- const fs = require('fs-extra');
7
- const path = require('path');
8
- const { glob } = require('glob');
9
-
10
- class FileSystem {
11
- constructor(logger) {
12
- this.logger = logger;
13
- }
14
-
15
- /**
16
- * Check if a path exists
17
- */
18
- async exists(filepath) {
19
- try {
20
- await fs.access(filepath);
21
- return true;
22
- } catch {
23
- return false;
24
- }
25
- }
26
-
27
- /**
28
- * Create directory with parents if needed
29
- */
30
- async ensureDir(dirPath) {
31
- try {
32
- await fs.ensureDir(dirPath);
33
- this.logger.debug(`Created directory: ${dirPath}`);
34
- return true;
35
- } catch (error) {
36
- this.logger.error(`Failed to create directory: ${dirPath}`, error);
37
- throw error;
38
- }
39
- }
40
-
41
- /**
42
- * Copy file or directory
43
- */
44
- async copy(src, dest, options = {}) {
45
- try {
46
- await fs.copy(src, dest, options);
47
- this.logger.debug(`Copied: ${src} → ${dest}`);
48
- return true;
49
- } catch (error) {
50
- this.logger.error(`Failed to copy: ${src} → ${dest}`, error);
51
- const newError = new Error(`Failed to copy: ${error.message}`);
52
- newError.code = error.code;
53
- newError.src = src;
54
- newError.dest = dest;
55
- throw newError;
56
- }
57
- }
58
-
59
- /**
60
- * Move file or directory
61
- */
62
- async move(src, dest, options = {}) {
63
- try {
64
- await fs.move(src, dest, options);
65
- this.logger.debug(`Moved: ${src} → ${dest}`);
66
- return true;
67
- } catch (error) {
68
- this.logger.error(`Failed to move: ${src} → ${dest}`, error);
69
- throw error;
70
- }
71
- }
72
-
73
- /**
74
- * Remove file or directory
75
- */
76
- async remove(filepath) {
77
- try {
78
- await fs.remove(filepath);
79
- this.logger.debug(`Removed: ${filepath}`);
80
- return true;
81
- } catch (error) {
82
- this.logger.error(`Failed to remove: ${filepath}`, error);
83
- throw error;
84
- }
85
- }
86
-
87
- /**
88
- * Read file content
89
- */
90
- async readFile(filepath, encoding = 'utf8') {
91
- try {
92
- const content = await fs.readFile(filepath, encoding);
93
- this.logger.debug(`Read file: ${filepath}`);
94
- return content;
95
- } catch (error) {
96
- this.logger.error(`Failed to read file: ${filepath}`, error);
97
- const newError = new Error(`Failed to read file: ${error.message}`);
98
- newError.code = error.code;
99
- newError.path = error.path;
100
- throw newError;
101
- }
102
- }
103
-
104
- /**
105
- * Write file content
106
- */
107
- async writeFile(filepath, content, options = {}) {
108
- try {
109
- await fs.writeFile(filepath, content, options);
110
- this.logger.debug(`Wrote file: ${filepath}`);
111
- return true;
112
- } catch (error) {
113
- this.logger.error(`Failed to write file: ${filepath}`, error);
114
- throw error;
115
- }
116
- }
117
-
118
- /**
119
- * Read JSON file
120
- */
121
- async readJson(filepath) {
122
- try {
123
- const data = await fs.readJson(filepath);
124
- this.logger.debug(`Read JSON: ${filepath}`);
125
- return data;
126
- } catch (error) {
127
- this.logger.error(`Failed to read JSON: ${filepath}`, error);
128
- const newError = new Error(`Failed to read JSON: ${error.message}`);
129
- newError.code = error.code;
130
- newError.path = filepath;
131
- throw newError;
132
- }
133
- }
134
-
135
- /**
136
- * Write JSON file
137
- */
138
- async writeJson(filepath, data, options = { spaces: 2 }) {
139
- try {
140
- await fs.writeJson(filepath, data, options);
141
- this.logger.debug(`Wrote JSON: ${filepath}`);
142
- return true;
143
- } catch (error) {
144
- this.logger.error(`Failed to write JSON: ${filepath}`, error);
145
- throw error;
146
- }
147
- }
148
-
149
- /**
150
- * List directory contents
151
- */
152
- async listDir(dirPath, options = {}) {
153
- try {
154
- const items = await fs.readdir(dirPath, options);
155
- this.logger.debug(`Listed directory: ${dirPath}`);
156
- return items;
157
- } catch (error) {
158
- this.logger.error(`Failed to list directory: ${dirPath}`, error);
159
- const newError = new Error(`Failed to list directory: ${error.message}`);
160
- newError.code = error.code;
161
- newError.path = error.path;
162
- throw newError;
163
- }
164
- }
165
-
166
- /**
167
- * Find files using glob pattern
168
- */
169
- async findFiles(pattern, options = {}) {
170
- try {
171
- const files = await glob(pattern, options);
172
- this.logger.debug(`Found ${files.length} files matching: ${pattern}`);
173
- return files;
174
- } catch (error) {
175
- this.logger.error(`Failed to find files: ${pattern}`, error);
176
- const newError = new Error(`Failed to find files: ${error.message}`);
177
- newError.code = error.code;
178
- newError.pattern = pattern;
179
- throw newError;
180
- }
181
- }
182
-
183
- /**
184
- * Get file stats
185
- */
186
- async stat(filepath) {
187
- try {
188
- const stats = await fs.stat(filepath);
189
- this.logger.debug(`Got stats for: ${filepath}`);
190
- return stats;
191
- } catch (error) {
192
- this.logger.error(`Failed to get stats: ${filepath}`, error);
193
- const newError = new Error(`Failed to get stats: ${error.message}`);
194
- newError.code = error.code;
195
- newError.path = error.path;
196
- throw newError;
197
- }
198
- }
199
-
200
- /**
201
- * Check if path is a directory
202
- */
203
- async isDirectory(filepath) {
204
- try {
205
- const stats = await this.stat(filepath);
206
- return stats.isDirectory();
207
- } catch {
208
- return false;
209
- }
210
- }
211
-
212
- /**
213
- * Check if path is a file
214
- */
215
- async isFile(filepath) {
216
- try {
217
- const stats = await this.stat(filepath);
218
- return stats.isFile();
219
- } catch {
220
- return false;
221
- }
222
- }
223
-
224
- /**
225
- * Create backup with timestamp
226
- */
227
- async backup(filepath) {
228
- if (!await this.exists(filepath)) {
229
- return null;
230
- }
231
-
232
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
233
- const backupPath = `${filepath}.backup-${timestamp}`;
234
-
235
- try {
236
- await this.copy(filepath, backupPath);
237
- this.logger.info(`Created backup: ${backupPath}`);
238
- return backupPath;
239
- } catch (error) {
240
- this.logger.error(`Failed to create backup: ${filepath}`, error);
241
- throw error;
242
- }
243
- }
244
-
245
- /**
246
- * Set file permissions
247
- */
248
- async chmod(filepath, mode) {
249
- try {
250
- await fs.chmod(filepath, mode);
251
- this.logger.debug(`Changed permissions: ${filepath} to ${mode.toString(8)}`);
252
- return true;
253
- } catch (error) {
254
- this.logger.error(`Failed to change permissions: ${filepath}`, error);
255
- throw error;
256
- }
257
- }
258
-
259
- /**
260
- * Create symbolic link
261
- */
262
- async symlink(target, linkPath) {
263
- try {
264
- await fs.ensureSymlink(target, linkPath);
265
- this.logger.debug(`Created symlink: ${linkPath} → ${target}`);
266
- return true;
267
- } catch (error) {
268
- this.logger.error(`Failed to create symlink: ${linkPath}`, error);
269
- throw error;
270
- }
271
- }
272
-
273
- /**
274
- * Get absolute path
275
- */
276
- resolvePath(...paths) {
277
- return path.resolve(...paths);
278
- }
279
-
280
- /**
281
- * Get relative path
282
- */
283
- relativePath(from, to) {
284
- return path.relative(from, to);
285
- }
286
-
287
- /**
288
- * Join paths
289
- */
290
- joinPath(...paths) {
291
- return path.join(...paths);
292
- }
293
-
294
- /**
295
- * Get directory name
296
- */
297
- dirname(filepath) {
298
- return path.dirname(filepath);
299
- }
300
-
301
- /**
302
- * Get base name
303
- */
304
- basename(filepath, ext) {
305
- return path.basename(filepath, ext);
306
- }
307
-
308
- /**
309
- * Get extension
310
- */
311
- extname(filepath) {
312
- return path.extname(filepath);
313
- }
314
- }
315
-
316
- module.exports = FileSystem;