forge-workflow 1.1.2 → 1.2.0
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/.claude/settings.local.json +3 -1
- package/bin/forge.js +117 -21
- package/package.json +1 -1
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
"Bash(git add:*)",
|
|
13
13
|
"Bash(git commit:*)",
|
|
14
14
|
"Bash(git push)",
|
|
15
|
-
"Bash(\"C:\\\\Program Files\\\\nodejs\\\\npm.cmd\" pkg fix)"
|
|
15
|
+
"Bash(\"C:\\\\Program Files\\\\nodejs\\\\npm.cmd\" pkg fix)",
|
|
16
|
+
"WebFetch(domain:www.aihero.dev)",
|
|
17
|
+
"Bash(\"C:\\\\Program Files\\\\nodejs\\\\npm.cmd\" version minor --no-git-tag-version)"
|
|
16
18
|
]
|
|
17
19
|
}
|
|
18
20
|
}
|
package/bin/forge.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Forge v1.
|
|
4
|
+
* Forge v1.2.0 - Universal AI Agent Workflow
|
|
5
5
|
* https://github.com/harshanandak/forge
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* npx forge setup --agents claude,cursor,windsurf
|
|
12
12
|
*
|
|
13
13
|
* CLI Flags:
|
|
14
|
+
* --path, -p <dir> Target project directory (creates if needed)
|
|
14
15
|
* --quick, -q Use all defaults, minimal prompts
|
|
15
16
|
* --skip-external Skip external services configuration
|
|
16
17
|
* --agents <list> Specify agents (--agents claude cursor OR --agents=claude,cursor)
|
|
@@ -19,6 +20,7 @@
|
|
|
19
20
|
*
|
|
20
21
|
* Examples:
|
|
21
22
|
* npx forge setup --quick # All defaults, no prompts
|
|
23
|
+
* npx forge setup -p ./my-project # Setup in specific directory
|
|
22
24
|
* npx forge setup --agents claude cursor # Just these agents
|
|
23
25
|
* npx forge setup --skip-external # No service prompts
|
|
24
26
|
* npx forge setup --agents claude --quick # Quick + specific agent
|
|
@@ -589,6 +591,27 @@ function writeEnvTokens(tokens, preserveExisting = true) {
|
|
|
589
591
|
}
|
|
590
592
|
|
|
591
593
|
// Detect existing project installation status
|
|
594
|
+
// Helper function for yes/no prompts with validation
|
|
595
|
+
async function askYesNo(question, prompt, defaultNo = true) {
|
|
596
|
+
const defaultText = defaultNo ? '[n]' : '[y]';
|
|
597
|
+
while (true) {
|
|
598
|
+
const answer = await question(`${prompt} (y/n) ${defaultText}: `);
|
|
599
|
+
const normalized = answer.trim().toLowerCase();
|
|
600
|
+
|
|
601
|
+
// Handle empty input (use default)
|
|
602
|
+
if (normalized === '') return defaultNo ? false : true;
|
|
603
|
+
|
|
604
|
+
// Accept yes variations
|
|
605
|
+
if (normalized === 'y' || normalized === 'yes') return true;
|
|
606
|
+
|
|
607
|
+
// Accept no variations
|
|
608
|
+
if (normalized === 'n' || normalized === 'no') return false;
|
|
609
|
+
|
|
610
|
+
// Invalid input - re-prompt
|
|
611
|
+
console.log(' Please enter y or n');
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
592
615
|
function detectProjectStatus() {
|
|
593
616
|
const status = {
|
|
594
617
|
type: 'fresh', // 'fresh', 'upgrade', or 'partial'
|
|
@@ -602,10 +625,10 @@ function detectProjectStatus() {
|
|
|
602
625
|
// Determine installation type
|
|
603
626
|
if (status.hasAgentsMd && status.hasClaudeCommands && status.hasDocsWorkflow) {
|
|
604
627
|
status.type = 'upgrade'; // Full forge installation exists
|
|
605
|
-
} else if (status.
|
|
606
|
-
status.type = 'partial'; //
|
|
628
|
+
} else if (status.hasClaudeCommands || status.hasEnvLocal) {
|
|
629
|
+
status.type = 'partial'; // Agent-specific files exist (not just base files from postinstall)
|
|
607
630
|
}
|
|
608
|
-
// else: 'fresh' - new installation
|
|
631
|
+
// else: 'fresh' - new installation (or just postinstall baseline with AGENTS.md)
|
|
609
632
|
|
|
610
633
|
// Parse existing env vars if .env.local exists
|
|
611
634
|
if (status.hasEnvLocal) {
|
|
@@ -639,8 +662,8 @@ async function configureExternalServices(rl, question, selectedAgents = [], proj
|
|
|
639
662
|
}
|
|
640
663
|
console.log('');
|
|
641
664
|
|
|
642
|
-
const reconfigure = await question
|
|
643
|
-
if (reconfigure
|
|
665
|
+
const reconfigure = await askYesNo(question, 'Reconfigure external services?', true);
|
|
666
|
+
if (!reconfigure) {
|
|
644
667
|
console.log('');
|
|
645
668
|
console.log('Keeping existing configuration.');
|
|
646
669
|
return;
|
|
@@ -652,9 +675,9 @@ async function configureExternalServices(rl, question, selectedAgents = [], proj
|
|
|
652
675
|
console.log('(You can also add them later to .env.local)');
|
|
653
676
|
console.log('');
|
|
654
677
|
|
|
655
|
-
const configure = await question
|
|
678
|
+
const configure = await askYesNo(question, 'Configure external services?', false);
|
|
656
679
|
|
|
657
|
-
if (configure
|
|
680
|
+
if (!configure) {
|
|
658
681
|
console.log('');
|
|
659
682
|
console.log('Skipping external services. You can configure them later by editing .env.local');
|
|
660
683
|
return;
|
|
@@ -865,7 +888,7 @@ function showBanner(subtitle = 'Universal AI Agent Workflow') {
|
|
|
865
888
|
console.log(' ██╔══╝ ██║ ██║██╔══██╗██║ ██║██╔══╝ ');
|
|
866
889
|
console.log(' ██║ ╚██████╔╝██║ ██║╚██████╔╝███████╗');
|
|
867
890
|
console.log(' ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝');
|
|
868
|
-
console.log(' v1.
|
|
891
|
+
console.log(' v1.2.0');
|
|
869
892
|
console.log('');
|
|
870
893
|
if (subtitle) {
|
|
871
894
|
console.log(` ${subtitle}`);
|
|
@@ -874,6 +897,23 @@ function showBanner(subtitle = 'Universal AI Agent Workflow') {
|
|
|
874
897
|
|
|
875
898
|
// Minimal installation (postinstall)
|
|
876
899
|
function minimalInstall() {
|
|
900
|
+
// Check if this looks like a project (has package.json)
|
|
901
|
+
const hasPackageJson = fs.existsSync(path.join(projectRoot, 'package.json'));
|
|
902
|
+
|
|
903
|
+
if (!hasPackageJson) {
|
|
904
|
+
console.log('');
|
|
905
|
+
console.log(' ✅ Forge installed successfully!');
|
|
906
|
+
console.log('');
|
|
907
|
+
console.log(' To set up in a project:');
|
|
908
|
+
console.log(' cd your-project');
|
|
909
|
+
console.log(' npx forge setup');
|
|
910
|
+
console.log('');
|
|
911
|
+
console.log(' Or specify a project directory:');
|
|
912
|
+
console.log(' npx forge setup --path ./my-project');
|
|
913
|
+
console.log('');
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
|
|
877
917
|
showBanner();
|
|
878
918
|
console.log('');
|
|
879
919
|
|
|
@@ -1123,6 +1163,11 @@ async function interactiveSetup() {
|
|
|
1123
1163
|
|
|
1124
1164
|
showBanner('Agent Configuration');
|
|
1125
1165
|
|
|
1166
|
+
// Show target directory
|
|
1167
|
+
console.log(` Target directory: ${process.cwd()}`);
|
|
1168
|
+
console.log(' (Use --path <dir> to change target directory)');
|
|
1169
|
+
console.log('');
|
|
1170
|
+
|
|
1126
1171
|
// Check prerequisites first
|
|
1127
1172
|
checkPrerequisites();
|
|
1128
1173
|
console.log('');
|
|
@@ -1159,8 +1204,8 @@ async function interactiveSetup() {
|
|
|
1159
1204
|
|
|
1160
1205
|
// Ask about overwriting AGENTS.md if it exists
|
|
1161
1206
|
if (projectStatus.hasAgentsMd) {
|
|
1162
|
-
const overwriteAgents = await question
|
|
1163
|
-
if (overwriteAgents
|
|
1207
|
+
const overwriteAgents = await askYesNo(question, 'Found existing AGENTS.md. Overwrite?', true);
|
|
1208
|
+
if (!overwriteAgents) {
|
|
1164
1209
|
skipFiles.agentsMd = true;
|
|
1165
1210
|
console.log(' Keeping existing AGENTS.md');
|
|
1166
1211
|
} else {
|
|
@@ -1170,8 +1215,8 @@ async function interactiveSetup() {
|
|
|
1170
1215
|
|
|
1171
1216
|
// Ask about overwriting .claude/commands/ if it exists
|
|
1172
1217
|
if (projectStatus.hasClaudeCommands) {
|
|
1173
|
-
const overwriteCommands = await question
|
|
1174
|
-
if (overwriteCommands
|
|
1218
|
+
const overwriteCommands = await askYesNo(question, 'Found existing .claude/commands/. Overwrite?', true);
|
|
1219
|
+
if (!overwriteCommands) {
|
|
1175
1220
|
skipFiles.claudeCommands = true;
|
|
1176
1221
|
console.log(' Keeping existing .claude/commands/');
|
|
1177
1222
|
} else {
|
|
@@ -1303,7 +1348,7 @@ async function interactiveSetup() {
|
|
|
1303
1348
|
// =============================================
|
|
1304
1349
|
console.log('');
|
|
1305
1350
|
console.log('==============================================');
|
|
1306
|
-
console.log(' Forge v1.
|
|
1351
|
+
console.log(' Forge v1.2.0 Setup Complete!');
|
|
1307
1352
|
console.log('==============================================');
|
|
1308
1353
|
console.log('');
|
|
1309
1354
|
console.log('What\'s installed:');
|
|
@@ -1347,7 +1392,8 @@ function parseFlags() {
|
|
|
1347
1392
|
skipExternal: false,
|
|
1348
1393
|
agents: null,
|
|
1349
1394
|
all: false,
|
|
1350
|
-
help: false
|
|
1395
|
+
help: false,
|
|
1396
|
+
path: null
|
|
1351
1397
|
};
|
|
1352
1398
|
|
|
1353
1399
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -1361,6 +1407,15 @@ function parseFlags() {
|
|
|
1361
1407
|
flags.all = true;
|
|
1362
1408
|
} else if (arg === '--help' || arg === '-h') {
|
|
1363
1409
|
flags.help = true;
|
|
1410
|
+
} else if (arg === '--path' || arg === '-p') {
|
|
1411
|
+
// --path <directory> or -p <directory>
|
|
1412
|
+
if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
1413
|
+
flags.path = args[i + 1];
|
|
1414
|
+
i++; // Skip next arg
|
|
1415
|
+
}
|
|
1416
|
+
} else if (arg.startsWith('--path=')) {
|
|
1417
|
+
// --path=/some/dir format
|
|
1418
|
+
flags.path = arg.replace('--path=', '');
|
|
1364
1419
|
} else if (arg === '--agents') {
|
|
1365
1420
|
// --agents claude cursor format
|
|
1366
1421
|
const agentList = [];
|
|
@@ -1403,6 +1458,8 @@ function showHelp() {
|
|
|
1403
1458
|
console.log(' npx forge Minimal install (AGENTS.md + docs)');
|
|
1404
1459
|
console.log('');
|
|
1405
1460
|
console.log('Options:');
|
|
1461
|
+
console.log(' --path, -p <dir> Target project directory (default: current directory)');
|
|
1462
|
+
console.log(' Creates the directory if it doesn\'t exist');
|
|
1406
1463
|
console.log(' --quick, -q Use all defaults, minimal prompts');
|
|
1407
1464
|
console.log(' Auto-selects: all agents, GitHub Code Quality, ESLint');
|
|
1408
1465
|
console.log(' --skip-external Skip external services configuration');
|
|
@@ -1421,6 +1478,8 @@ function showHelp() {
|
|
|
1421
1478
|
console.log('Examples:');
|
|
1422
1479
|
console.log(' npx forge setup # Interactive setup');
|
|
1423
1480
|
console.log(' npx forge setup --quick # All defaults, no prompts');
|
|
1481
|
+
console.log(' npx forge setup -p ./my-project # Setup in specific directory');
|
|
1482
|
+
console.log(' npx forge setup --path=/home/user/app # Same, different syntax');
|
|
1424
1483
|
console.log(' npx forge setup --agents claude cursor # Just these agents');
|
|
1425
1484
|
console.log(' npx forge setup --agents=claude,cursor # Same, different syntax');
|
|
1426
1485
|
console.log(' npx forge setup --skip-external # No service configuration');
|
|
@@ -1510,7 +1569,7 @@ async function quickSetup(selectedAgents, skipExternal) {
|
|
|
1510
1569
|
// Final summary
|
|
1511
1570
|
console.log('');
|
|
1512
1571
|
console.log('==============================================');
|
|
1513
|
-
console.log(' Forge v1.
|
|
1572
|
+
console.log(' Forge v1.2.0 Quick Setup Complete!');
|
|
1514
1573
|
console.log('==============================================');
|
|
1515
1574
|
console.log('');
|
|
1516
1575
|
console.log('Next steps:');
|
|
@@ -1548,6 +1607,11 @@ async function interactiveSetupWithFlags(flags) {
|
|
|
1548
1607
|
|
|
1549
1608
|
showBanner('Agent Configuration');
|
|
1550
1609
|
|
|
1610
|
+
// Show target directory
|
|
1611
|
+
console.log(` Target directory: ${process.cwd()}`);
|
|
1612
|
+
console.log(' (Use --path <dir> to change target directory)');
|
|
1613
|
+
console.log('');
|
|
1614
|
+
|
|
1551
1615
|
// Check prerequisites first
|
|
1552
1616
|
checkPrerequisites();
|
|
1553
1617
|
console.log('');
|
|
@@ -1584,8 +1648,8 @@ async function interactiveSetupWithFlags(flags) {
|
|
|
1584
1648
|
|
|
1585
1649
|
// Ask about overwriting AGENTS.md if it exists
|
|
1586
1650
|
if (projectStatus.hasAgentsMd) {
|
|
1587
|
-
const overwriteAgents = await question
|
|
1588
|
-
if (overwriteAgents
|
|
1651
|
+
const overwriteAgents = await askYesNo(question, 'Found existing AGENTS.md. Overwrite?', true);
|
|
1652
|
+
if (!overwriteAgents) {
|
|
1589
1653
|
skipFiles.agentsMd = true;
|
|
1590
1654
|
console.log(' Keeping existing AGENTS.md');
|
|
1591
1655
|
} else {
|
|
@@ -1595,8 +1659,8 @@ async function interactiveSetupWithFlags(flags) {
|
|
|
1595
1659
|
|
|
1596
1660
|
// Ask about overwriting .claude/commands/ if it exists
|
|
1597
1661
|
if (projectStatus.hasClaudeCommands) {
|
|
1598
|
-
const overwriteCommands = await question
|
|
1599
|
-
if (overwriteCommands
|
|
1662
|
+
const overwriteCommands = await askYesNo(question, 'Found existing .claude/commands/. Overwrite?', true);
|
|
1663
|
+
if (!overwriteCommands) {
|
|
1600
1664
|
skipFiles.claudeCommands = true;
|
|
1601
1665
|
console.log(' Keeping existing .claude/commands/');
|
|
1602
1666
|
} else {
|
|
@@ -1733,7 +1797,7 @@ async function interactiveSetupWithFlags(flags) {
|
|
|
1733
1797
|
// =============================================
|
|
1734
1798
|
console.log('');
|
|
1735
1799
|
console.log('==============================================');
|
|
1736
|
-
console.log(' Forge v1.
|
|
1800
|
+
console.log(' Forge v1.2.0 Setup Complete!');
|
|
1737
1801
|
console.log('==============================================');
|
|
1738
1802
|
console.log('');
|
|
1739
1803
|
console.log('What\'s installed:');
|
|
@@ -1781,6 +1845,38 @@ async function main() {
|
|
|
1781
1845
|
return;
|
|
1782
1846
|
}
|
|
1783
1847
|
|
|
1848
|
+
// Handle --path option: change to target directory
|
|
1849
|
+
if (flags.path) {
|
|
1850
|
+
const targetPath = path.resolve(flags.path);
|
|
1851
|
+
|
|
1852
|
+
// Create directory if it doesn't exist
|
|
1853
|
+
if (!fs.existsSync(targetPath)) {
|
|
1854
|
+
try {
|
|
1855
|
+
fs.mkdirSync(targetPath, { recursive: true });
|
|
1856
|
+
console.log(`Created directory: ${targetPath}`);
|
|
1857
|
+
} catch (err) {
|
|
1858
|
+
console.error(`Error creating directory: ${err.message}`);
|
|
1859
|
+
process.exit(1);
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
// Verify it's a directory
|
|
1864
|
+
if (!fs.statSync(targetPath).isDirectory()) {
|
|
1865
|
+
console.error(`Error: ${targetPath} is not a directory`);
|
|
1866
|
+
process.exit(1);
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
// Change to target directory
|
|
1870
|
+
try {
|
|
1871
|
+
process.chdir(targetPath);
|
|
1872
|
+
console.log(`Working directory: ${targetPath}`);
|
|
1873
|
+
console.log('');
|
|
1874
|
+
} catch (err) {
|
|
1875
|
+
console.error(`Error changing to directory: ${err.message}`);
|
|
1876
|
+
process.exit(1);
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1784
1880
|
if (command === 'setup') {
|
|
1785
1881
|
// Determine agents to install
|
|
1786
1882
|
let selectedAgents = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forge-workflow",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "9-stage TDD workflow for ALL AI coding agents (Claude, Cursor, Windsurf, Kilo, OpenCode, Copilot, Cline, Roo, Aider, Continue, Antigravity)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"forge": "bin/forge.js"
|