@pennyfarthing/core 7.7.0 → 7.8.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/README.md +1 -1
- package/package.json +1 -1
- package/packages/core/dist/cli/commands/doctor.d.ts +3 -0
- package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/doctor.js +134 -9
- package/packages/core/dist/cli/commands/doctor.js.map +1 -1
- package/pennyfarthing-dist/agents/sm-setup.md +37 -2
- package/pennyfarthing-dist/agents/sm.md +68 -22
- package/pennyfarthing-dist/agents/workflow-status-check.md +11 -1
- package/pennyfarthing-dist/commands/git-cleanup.md +43 -308
- package/pennyfarthing-dist/commands/solo.md +31 -0
- package/pennyfarthing-dist/guides/patterns/approval-gates-pattern.md +1 -1
- package/pennyfarthing-dist/personas/themes/gilligans-island.yaml +83 -83
- package/pennyfarthing-dist/personas/themes/the-expanse.yaml +11 -11
- package/pennyfarthing-dist/scripts/core/agent-session.sh +2 -2
- package/pennyfarthing-dist/scripts/core/check-context.sh +3 -0
- package/pennyfarthing-dist/scripts/core/handoff-marker.sh +13 -2
- package/pennyfarthing-dist/scripts/core/prime.sh +3 -157
- package/pennyfarthing-dist/scripts/core/run.sh +9 -0
- package/pennyfarthing-dist/scripts/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/scripts/hooks/question_reflector_check.py +117 -20
- package/pennyfarthing-dist/scripts/jira/README.md +10 -7
- package/pennyfarthing-dist/scripts/misc/add-short-names.sh +13 -0
- package/pennyfarthing-dist/scripts/misc/add_short_names.py +226 -0
- package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +6 -5
- package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +319 -0
- package/pennyfarthing-dist/scripts/sprint/import-epic-to-future.sh +6 -5
- package/pennyfarthing-dist/scripts/sprint/import_epic_to_future.py +270 -0
- package/pennyfarthing-dist/scripts/test/ensure-swebench-data.sh +59 -0
- package/pennyfarthing-dist/scripts/theme/compute-theme-tiers.sh +8 -6
- package/pennyfarthing-dist/scripts/theme/compute_theme_tiers.py +402 -0
- package/pennyfarthing-dist/scripts/workflow/check.sh +3 -476
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.py +61 -0
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +13 -0
- package/pennyfarthing-dist/skills/judge/SKILL.md +57 -0
- package/pennyfarthing-dist/skills/sprint/scripts/sync-epic-jira.sh +4 -22
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-01-analyze.md +83 -0
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-02-categorize.md +116 -0
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-03-execute.md +210 -0
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-04-verify.md +88 -0
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-05-complete.md +71 -0
- package/pennyfarthing-dist/workflows/git-cleanup.yaml +59 -0
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.mjs +0 -393
- package/pennyfarthing-dist/scripts/hooks/tests/question-reflector.test.mjs +0 -545
- package/pennyfarthing-dist/scripts/jira/jira-bidirectional-sync.mjs +0 -327
- package/pennyfarthing-dist/scripts/jira/jira-bidirectional-sync.test.mjs +0 -503
- package/pennyfarthing-dist/scripts/jira/jira-lib.mjs +0 -443
- package/pennyfarthing-dist/scripts/jira/jira-sync-story.mjs +0 -208
- package/pennyfarthing-dist/scripts/jira/jira-sync.mjs +0 -198
- package/pennyfarthing-dist/scripts/misc/add-short-names.mjs +0 -264
- package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.mjs +0 -474
- package/pennyfarthing-dist/scripts/sprint/import-epic-to-future.mjs +0 -377
- package/pennyfarthing-dist/scripts/theme/compute-theme-tiers.js +0 -492
- /package/pennyfarthing-dist/guides/{AGENT-COORDINATION.md → agent-coordination.md} +0 -0
- /package/pennyfarthing-dist/guides/{HOOKS.md → hooks.md} +0 -0
- /package/pennyfarthing-dist/guides/{PROMPT-PATTERNS.md → prompt-patterns.md} +0 -0
- /package/pennyfarthing-dist/guides/{SESSION-ARTIFACTS.md → session-artifacts.md} +0 -0
- /package/pennyfarthing-dist/guides/{XML-TAGS.md → xml-tags.md} +0 -0
|
@@ -1,474 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* migrate-bmad-workflow.mjs - Migrate BMAD workflows to Pennyfarthing format
|
|
4
|
-
*
|
|
5
|
-
* Story MSSCI-12132: BMAD to Pennyfarthing migration script
|
|
6
|
-
*
|
|
7
|
-
* Converts BMAD workflow format to Pennyfarthing stepped workflow format:
|
|
8
|
-
* - Parses BMAD workflow.md with YAML frontmatter
|
|
9
|
-
* - Extracts step files and their frontmatter
|
|
10
|
-
* - Converts variable syntax ({var-name} → {var_name})
|
|
11
|
-
* - Generates workflow.yaml with Pennyfarthing schema
|
|
12
|
-
* - Preserves tri-modal structure (steps-c, steps-v, steps-e)
|
|
13
|
-
*
|
|
14
|
-
* Usage: node migrate-bmad-workflow.mjs [--dry-run] <source-dir> [target-dir]
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import fs from 'fs';
|
|
18
|
-
import path from 'path';
|
|
19
|
-
import { fileURLToPath } from 'url';
|
|
20
|
-
|
|
21
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
-
const __dirname = path.dirname(__filename);
|
|
23
|
-
|
|
24
|
-
// =============================================================================
|
|
25
|
-
// Colors
|
|
26
|
-
// =============================================================================
|
|
27
|
-
|
|
28
|
-
const colors = {
|
|
29
|
-
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
30
|
-
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
31
|
-
yellow: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
32
|
-
blue: (s) => `\x1b[34m${s}\x1b[0m`,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const log = {
|
|
36
|
-
info: (msg) => console.log(`${colors.blue('INFO')}: ${msg}`),
|
|
37
|
-
success: (msg) => console.log(`${colors.green('SUCCESS')}: ${msg}`),
|
|
38
|
-
warn: (msg) => console.log(`${colors.yellow('WARN')}: ${msg}`),
|
|
39
|
-
error: (msg) => console.error(`${colors.red('ERROR')}: ${msg}`),
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
// =============================================================================
|
|
43
|
-
// YAML Frontmatter Parsing
|
|
44
|
-
// =============================================================================
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Extract YAML frontmatter from markdown content
|
|
48
|
-
* Returns { frontmatter: object, content: string }
|
|
49
|
-
*/
|
|
50
|
-
function extractFrontmatter(content) {
|
|
51
|
-
const lines = content.split('\n');
|
|
52
|
-
|
|
53
|
-
// Check for opening ---
|
|
54
|
-
if (lines[0]?.trim() !== '---') {
|
|
55
|
-
return { frontmatter: {}, content };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Find closing ---
|
|
59
|
-
let endIndex = -1;
|
|
60
|
-
for (let i = 1; i < lines.length; i++) {
|
|
61
|
-
if (lines[i].trim() === '---') {
|
|
62
|
-
endIndex = i;
|
|
63
|
-
break;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (endIndex === -1) {
|
|
68
|
-
return { frontmatter: {}, content };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Parse frontmatter as simple key-value pairs
|
|
72
|
-
const frontmatterLines = lines.slice(1, endIndex);
|
|
73
|
-
const frontmatter = {};
|
|
74
|
-
|
|
75
|
-
for (const line of frontmatterLines) {
|
|
76
|
-
const match = line.match(/^([a-zA-Z_][a-zA-Z0-9_]*):\s*(.*)$/);
|
|
77
|
-
if (match) {
|
|
78
|
-
let [, key, value] = match;
|
|
79
|
-
// Remove quotes
|
|
80
|
-
value = value.replace(/^['"]|['"]$/g, '').trim();
|
|
81
|
-
frontmatter[key] = value;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Rest of content
|
|
86
|
-
const restContent = lines.slice(endIndex + 1).join('\n');
|
|
87
|
-
|
|
88
|
-
return { frontmatter, content: restContent };
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// =============================================================================
|
|
92
|
-
// Variable Conversion
|
|
93
|
-
// =============================================================================
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Convert BMAD-style dashed variables to Pennyfarthing underscore style
|
|
97
|
-
* {var-name} → {var_name}
|
|
98
|
-
*/
|
|
99
|
-
function convertVariables(text) {
|
|
100
|
-
// Repeatedly convert dashed variables until none remain
|
|
101
|
-
// This handles multi-segment variables like {user-skill-level}
|
|
102
|
-
let result = text;
|
|
103
|
-
let prev;
|
|
104
|
-
|
|
105
|
-
do {
|
|
106
|
-
prev = result;
|
|
107
|
-
result = result.replace(/\{([a-zA-Z0-9_]+)-([a-zA-Z0-9_-]+)\}/g, (match, p1, p2) => {
|
|
108
|
-
// Convert all dashes in p2 to underscores
|
|
109
|
-
const converted = p2.replace(/-/g, '_');
|
|
110
|
-
return `{${p1}_${converted}}`;
|
|
111
|
-
});
|
|
112
|
-
} while (result !== prev);
|
|
113
|
-
|
|
114
|
-
return result;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// =============================================================================
|
|
118
|
-
// Directory Helpers
|
|
119
|
-
// =============================================================================
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Check if workflow is tri-modal (has steps-c, steps-v, or steps-e)
|
|
123
|
-
*/
|
|
124
|
-
function isTrimodal(sourceDir) {
|
|
125
|
-
return (
|
|
126
|
-
fs.existsSync(path.join(sourceDir, 'steps-c')) ||
|
|
127
|
-
fs.existsSync(path.join(sourceDir, 'steps-v')) ||
|
|
128
|
-
fs.existsSync(path.join(sourceDir, 'steps-e'))
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Get step directories to process
|
|
134
|
-
*/
|
|
135
|
-
function getStepDirectories(sourceDir) {
|
|
136
|
-
const dirs = [];
|
|
137
|
-
|
|
138
|
-
if (isTrimodal(sourceDir)) {
|
|
139
|
-
for (const dir of ['steps-c', 'steps-v', 'steps-e']) {
|
|
140
|
-
if (fs.existsSync(path.join(sourceDir, dir))) {
|
|
141
|
-
dirs.push(dir);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
} else if (fs.existsSync(path.join(sourceDir, 'steps'))) {
|
|
145
|
-
dirs.push('steps');
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return dirs;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Get supporting directories (templates, data, etc.)
|
|
153
|
-
*/
|
|
154
|
-
function getSupportingDirectories(sourceDir) {
|
|
155
|
-
const dirs = [];
|
|
156
|
-
|
|
157
|
-
for (const dir of ['templates', 'data', 'assets']) {
|
|
158
|
-
if (fs.existsSync(path.join(sourceDir, dir))) {
|
|
159
|
-
dirs.push(dir);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return dirs;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Get root-level template files (e.g., project-context-template.md)
|
|
168
|
-
*/
|
|
169
|
-
function getRootTemplateFiles(sourceDir) {
|
|
170
|
-
const files = [];
|
|
171
|
-
|
|
172
|
-
try {
|
|
173
|
-
const entries = fs.readdirSync(sourceDir, { withFileTypes: true });
|
|
174
|
-
for (const entry of entries) {
|
|
175
|
-
if (entry.isFile() && entry.name.includes('-template') && entry.name.endsWith('.md')) {
|
|
176
|
-
files.push(entry.name);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
} catch {
|
|
180
|
-
// Ignore errors
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return files;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Recursively copy directory with file transformation
|
|
188
|
-
*/
|
|
189
|
-
function copyDirWithTransform(srcDir, destDir, transform, dryRun) {
|
|
190
|
-
if (!fs.existsSync(srcDir)) return;
|
|
191
|
-
|
|
192
|
-
if (!dryRun) {
|
|
193
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const entries = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
197
|
-
|
|
198
|
-
for (const entry of entries) {
|
|
199
|
-
const srcPath = path.join(srcDir, entry.name);
|
|
200
|
-
const destPath = path.join(destDir, entry.name);
|
|
201
|
-
|
|
202
|
-
if (entry.isDirectory()) {
|
|
203
|
-
copyDirWithTransform(srcPath, destPath, transform, dryRun);
|
|
204
|
-
} else if (entry.isFile()) {
|
|
205
|
-
if (dryRun) {
|
|
206
|
-
const content = fs.readFileSync(srcPath, 'utf-8');
|
|
207
|
-
const transformed = transform(content, srcPath);
|
|
208
|
-
if (content !== transformed) {
|
|
209
|
-
log.info(`[DRY-RUN] Would convert variables in: ${path.relative(process.cwd(), srcPath)}`);
|
|
210
|
-
}
|
|
211
|
-
} else {
|
|
212
|
-
const content = fs.readFileSync(srcPath, 'utf-8');
|
|
213
|
-
const transformed = transform(content, srcPath);
|
|
214
|
-
fs.writeFileSync(destPath, transformed, 'utf-8');
|
|
215
|
-
log.success(`Copied: ${path.relative(destDir, destPath)}`);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// =============================================================================
|
|
222
|
-
// Workflow Generation
|
|
223
|
-
// =============================================================================
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Generate workflow.yaml content
|
|
227
|
-
*/
|
|
228
|
-
function generateWorkflowYaml(name, description, trimodal) {
|
|
229
|
-
const convertedDesc = convertVariables(description);
|
|
230
|
-
|
|
231
|
-
let stepConfig;
|
|
232
|
-
let modesConfig = '';
|
|
233
|
-
|
|
234
|
-
if (trimodal) {
|
|
235
|
-
stepConfig = ` path: ./steps-c/
|
|
236
|
-
pattern: step-*.md`;
|
|
237
|
-
modesConfig = `
|
|
238
|
-
# Tri-modal workflow paths
|
|
239
|
-
modes:
|
|
240
|
-
create: ./steps-c/
|
|
241
|
-
validate: ./steps-v/
|
|
242
|
-
edit: ./steps-e/`;
|
|
243
|
-
} else {
|
|
244
|
-
stepConfig = ` path: ./steps/
|
|
245
|
-
pattern: step-*.md`;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return `# ${name} Workflow - Migrated from BMAD format
|
|
249
|
-
# Generated by migrate-bmad-workflow.mjs
|
|
250
|
-
|
|
251
|
-
workflow:
|
|
252
|
-
name: ${name}
|
|
253
|
-
description: ${convertedDesc}
|
|
254
|
-
version: "1.0.0"
|
|
255
|
-
type: stepped
|
|
256
|
-
|
|
257
|
-
# Step configuration
|
|
258
|
-
steps:
|
|
259
|
-
${stepConfig}
|
|
260
|
-
${modesConfig}
|
|
261
|
-
# Variables available in step files
|
|
262
|
-
variables:
|
|
263
|
-
project_root: .
|
|
264
|
-
planning_artifacts: ./artifacts
|
|
265
|
-
output_file: artifacts/${name}.md
|
|
266
|
-
|
|
267
|
-
# Agent assignment (customize as needed)
|
|
268
|
-
agent: architect
|
|
269
|
-
|
|
270
|
-
# Triggers - when to suggest this workflow
|
|
271
|
-
triggers:
|
|
272
|
-
types: [${name}]
|
|
273
|
-
tags: [${name}, stepped]
|
|
274
|
-
`;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// =============================================================================
|
|
278
|
-
// Main
|
|
279
|
-
// =============================================================================
|
|
280
|
-
|
|
281
|
-
function showHelp() {
|
|
282
|
-
console.log(`
|
|
283
|
-
Usage: migrate-bmad-workflow.mjs [--dry-run] <source-dir> [target-dir]
|
|
284
|
-
|
|
285
|
-
Migrate BMAD workflows to Pennyfarthing stepped workflow format.
|
|
286
|
-
|
|
287
|
-
Arguments:
|
|
288
|
-
source-dir Path to BMAD workflow directory (must contain workflow.md)
|
|
289
|
-
target-dir Path to output directory (default: current directory)
|
|
290
|
-
|
|
291
|
-
Options:
|
|
292
|
-
--dry-run Show what would be done without making changes
|
|
293
|
-
-h, --help Show this help message
|
|
294
|
-
|
|
295
|
-
Examples:
|
|
296
|
-
# Migrate PRD workflow to ./prd/
|
|
297
|
-
migrate-bmad-workflow.mjs ~/BMAD-METHOD/workflows/prd ./prd
|
|
298
|
-
|
|
299
|
-
# Preview migration without writing files
|
|
300
|
-
migrate-bmad-workflow.mjs --dry-run ~/BMAD-METHOD/workflows/prd ./prd
|
|
301
|
-
`);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
function main() {
|
|
305
|
-
const args = process.argv.slice(2);
|
|
306
|
-
|
|
307
|
-
// Parse flags
|
|
308
|
-
let dryRun = false;
|
|
309
|
-
const positional = [];
|
|
310
|
-
|
|
311
|
-
for (const arg of args) {
|
|
312
|
-
if (arg === '--dry-run') {
|
|
313
|
-
dryRun = true;
|
|
314
|
-
} else if (arg === '-h' || arg === '--help') {
|
|
315
|
-
showHelp();
|
|
316
|
-
process.exit(0);
|
|
317
|
-
} else if (!arg.startsWith('-')) {
|
|
318
|
-
positional.push(arg);
|
|
319
|
-
} else {
|
|
320
|
-
log.error(`Unknown option: ${arg}`);
|
|
321
|
-
process.exit(1);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// Validate arguments
|
|
326
|
-
const [sourceDir, targetDir = '.'] = positional;
|
|
327
|
-
|
|
328
|
-
if (!sourceDir) {
|
|
329
|
-
log.error('Source directory required');
|
|
330
|
-
showHelp();
|
|
331
|
-
process.exit(1);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
if (!fs.existsSync(sourceDir)) {
|
|
335
|
-
log.error(`Source directory not found: ${sourceDir}`);
|
|
336
|
-
process.exit(1);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
const workflowMdPath = path.join(sourceDir, 'workflow.md');
|
|
340
|
-
if (!fs.existsSync(workflowMdPath)) {
|
|
341
|
-
log.error(`workflow.md not found in ${sourceDir}`);
|
|
342
|
-
process.exit(1);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Header
|
|
346
|
-
log.info('BMAD Workflow Migration');
|
|
347
|
-
log.info('=======================');
|
|
348
|
-
log.info(`Source: ${sourceDir}`);
|
|
349
|
-
log.info(`Target: ${targetDir}`);
|
|
350
|
-
|
|
351
|
-
if (dryRun) {
|
|
352
|
-
log.warn('DRY-RUN MODE - No changes will be made');
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
console.log('');
|
|
356
|
-
|
|
357
|
-
// Parse workflow.md
|
|
358
|
-
const workflowContent = fs.readFileSync(workflowMdPath, 'utf-8');
|
|
359
|
-
const { frontmatter } = extractFrontmatter(workflowContent);
|
|
360
|
-
|
|
361
|
-
const name = frontmatter.name;
|
|
362
|
-
const description = frontmatter.description || '';
|
|
363
|
-
|
|
364
|
-
if (!name) {
|
|
365
|
-
log.error('Could not extract workflow name from workflow.md');
|
|
366
|
-
process.exit(1);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
log.info(`Parsed workflow: ${name}`);
|
|
370
|
-
log.info(`Description: ${description}`);
|
|
371
|
-
|
|
372
|
-
console.log('');
|
|
373
|
-
|
|
374
|
-
// Create target directory
|
|
375
|
-
if (!dryRun) {
|
|
376
|
-
fs.mkdirSync(targetDir, { recursive: true });
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
// Generate workflow.yaml
|
|
380
|
-
log.info('Generating workflow.yaml');
|
|
381
|
-
|
|
382
|
-
const trimodal = isTrimodal(sourceDir);
|
|
383
|
-
const workflowYaml = generateWorkflowYaml(name, description, trimodal);
|
|
384
|
-
|
|
385
|
-
if (dryRun) {
|
|
386
|
-
log.info('[DRY-RUN] Would create: workflow.yaml');
|
|
387
|
-
} else {
|
|
388
|
-
fs.writeFileSync(path.join(targetDir, 'workflow.yaml'), workflowYaml, 'utf-8');
|
|
389
|
-
log.success('Created workflow.yaml');
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
console.log('');
|
|
393
|
-
|
|
394
|
-
// Copy step directories
|
|
395
|
-
const stepDirs = getStepDirectories(sourceDir);
|
|
396
|
-
|
|
397
|
-
for (const dir of stepDirs) {
|
|
398
|
-
log.info(`Processing step directory: ${dir}`);
|
|
399
|
-
|
|
400
|
-
if (dryRun) {
|
|
401
|
-
log.info(`[DRY-RUN] Would copy and transform: ${dir}/`);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
copyDirWithTransform(
|
|
405
|
-
path.join(sourceDir, dir),
|
|
406
|
-
path.join(targetDir, dir),
|
|
407
|
-
(content, filePath) => {
|
|
408
|
-
// Only convert variables in markdown files
|
|
409
|
-
if (filePath.endsWith('.md')) {
|
|
410
|
-
return convertVariables(content);
|
|
411
|
-
}
|
|
412
|
-
return content;
|
|
413
|
-
},
|
|
414
|
-
dryRun
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
console.log('');
|
|
419
|
-
|
|
420
|
-
// Copy supporting directories
|
|
421
|
-
const supportDirs = getSupportingDirectories(sourceDir);
|
|
422
|
-
|
|
423
|
-
for (const dir of supportDirs) {
|
|
424
|
-
log.info(`Processing supporting directory: ${dir}`);
|
|
425
|
-
|
|
426
|
-
if (dryRun) {
|
|
427
|
-
log.info(`[DRY-RUN] Would copy: ${dir}/`);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
copyDirWithTransform(
|
|
431
|
-
path.join(sourceDir, dir),
|
|
432
|
-
path.join(targetDir, dir),
|
|
433
|
-
(content, filePath) => {
|
|
434
|
-
if (filePath.endsWith('.md')) {
|
|
435
|
-
return convertVariables(content);
|
|
436
|
-
}
|
|
437
|
-
return content;
|
|
438
|
-
},
|
|
439
|
-
dryRun
|
|
440
|
-
);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
console.log('');
|
|
444
|
-
|
|
445
|
-
// Copy root-level template files
|
|
446
|
-
const templateFiles = getRootTemplateFiles(sourceDir);
|
|
447
|
-
|
|
448
|
-
for (const file of templateFiles) {
|
|
449
|
-
log.info(`Processing root template file: ${file}`);
|
|
450
|
-
|
|
451
|
-
const srcPath = path.join(sourceDir, file);
|
|
452
|
-
const destPath = path.join(targetDir, file);
|
|
453
|
-
|
|
454
|
-
if (dryRun) {
|
|
455
|
-
log.info(`[DRY-RUN] Would copy: ${file}`);
|
|
456
|
-
} else {
|
|
457
|
-
const content = fs.readFileSync(srcPath, 'utf-8');
|
|
458
|
-
const transformed = convertVariables(content);
|
|
459
|
-
fs.writeFileSync(destPath, transformed, 'utf-8');
|
|
460
|
-
log.success(`Copied: ${file}`);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
console.log('');
|
|
465
|
-
|
|
466
|
-
if (dryRun) {
|
|
467
|
-
log.info('DRY-RUN complete. No files were modified.');
|
|
468
|
-
} else {
|
|
469
|
-
log.success('Migration complete!');
|
|
470
|
-
log.info(`Output directory: ${targetDir}`);
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
main();
|