aiwf 0.3.17 ā 0.3.19
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.ko.md +84 -0
- package/README.md +87 -0
- package/ai-tools/README.md +105 -0
- package/ai-tools/augment/README.md +371 -0
- package/ai-tools/augment/config.json +30 -0
- package/ai-tools/augment/template/.augment/aiwf-integration.md +387 -0
- package/ai-tools/augment/template/.augment/augment.yaml +347 -0
- package/ai-tools/augment/template/augment.config.json +64 -0
- package/ai-tools/claude-code/README.md +151 -0
- package/ai-tools/claude-code/config.json +28 -0
- package/ai-tools/claude-code/template/CLAUDE.md +91 -0
- package/ai-tools/cursor/README.md +314 -0
- package/ai-tools/cursor/config.json +29 -0
- package/ai-tools/cursor/template/.cursorrules +362 -0
- package/ai-tools/github-copilot/README.md +195 -0
- package/ai-tools/github-copilot/config.json +24 -0
- package/ai-tools/github-copilot/template/.github/copilot-instructions.md +202 -0
- package/ai-tools/windsurf/README.md +355 -0
- package/ai-tools/windsurf/config.json +29 -0
- package/ai-tools/windsurf/template/.windsurf/aiwf-rules.md +260 -0
- package/ai-tools/windsurf/template/.windsurf/windsurf.config.js +312 -0
- package/ai-tools/windsurf/template/windsurf.config.json +63 -0
- package/docs/CODE_CLEANUP_GUIDE.ko.md +415 -0
- package/docs/CODE_CLEANUP_GUIDE.md +415 -0
- package/docs/VALIDATOR_API.ko.md +324 -0
- package/docs/VALIDATOR_API.md +324 -0
- package/package.json +3 -2
- package/src/cli/index.js +338 -0
- package/src/config/file-lists.js +5 -5
- package/src/lib/backup-manager.js +4 -3
- package/src/lib/installer.js +126 -3
- package/src/lib/validator.js +78 -313
- package/src/utils/messages.js +16 -2
- package/src/utils/paths.js +1 -20
- package/templates/README.md +0 -78
- package/templates/api-server/config.json +0 -64
- package/templates/api-server/template/.aiwf/config.json +0 -56
- package/templates/api-server/template/.aiwf/feature-ledger.json +0 -42
- package/templates/api-server/template/.aiwf/personas/backend-engineer.json +0 -40
- package/templates/api-server/template/.aiwf/scripts/cli.js +0 -111
- package/templates/api-server/template/.env.example +0 -29
- package/templates/api-server/template/.eslintrc.json +0 -23
- package/templates/api-server/template/README.md +0 -171
- package/templates/api-server/template/jest.config.js +0 -26
- package/templates/api-server/template/nodemon.json +0 -9
- package/templates/api-server/template/package.json +0 -61
- package/templates/api-server/template/src/app.ts +0 -60
- package/templates/api-server/template/src/config/swagger.ts +0 -38
- package/templates/api-server/template/src/controllers/aiwfController.ts +0 -54
- package/templates/api-server/template/src/controllers/authController.ts +0 -128
- package/templates/api-server/template/src/controllers/statusController.ts +0 -28
- package/templates/api-server/template/src/index.ts +0 -28
- package/templates/api-server/template/src/middleware/aiwfMiddleware.ts +0 -50
- package/templates/api-server/template/src/middleware/authMiddleware.ts +0 -41
- package/templates/api-server/template/src/middleware/errorHandler.ts +0 -42
- package/templates/api-server/template/src/middleware/notFoundHandler.ts +0 -14
- package/templates/api-server/template/src/middleware/requestLogger.ts +0 -20
- package/templates/api-server/template/src/routes/aiwf.ts +0 -31
- package/templates/api-server/template/src/routes/index.ts +0 -13
- package/templates/api-server/template/src/routes/v1/index.ts +0 -67
- package/templates/api-server/template/src/utils/logger.ts +0 -37
- package/templates/api-server/template/tests/app.test.ts +0 -40
- package/templates/api-server/template/tsconfig.json +0 -43
- package/templates/npm-library/config.json +0 -61
- package/templates/npm-library/template/LICENSE +0 -21
- package/templates/npm-library/template/README.md +0 -201
- package/templates/npm-library/template/package.json +0 -78
- package/templates/web-app/config.json +0 -53
- package/templates/web-app/template/.aiwf/config.json +0 -54
- package/templates/web-app/template/.aiwf/feature-ledger.json +0 -37
- package/templates/web-app/template/.aiwf/personas/fullstack-developer.json +0 -40
- package/templates/web-app/template/.aiwf/scripts/cli.js +0 -110
- package/templates/web-app/template/.eslintrc.cjs +0 -20
- package/templates/web-app/template/README.md +0 -151
- package/templates/web-app/template/index.html +0 -14
- package/templates/web-app/template/package.json +0 -44
- package/templates/web-app/template/postcss.config.js +0 -6
- package/templates/web-app/template/public/vite.svg +0 -1
- package/templates/web-app/template/src/App.tsx +0 -21
- package/templates/web-app/template/src/components/Layout.tsx +0 -57
- package/templates/web-app/template/src/components/aiwf/ContextStatus.tsx +0 -107
- package/templates/web-app/template/src/components/aiwf/TokenUsage.tsx +0 -71
- package/templates/web-app/template/src/index.css +0 -60
- package/templates/web-app/template/src/main.tsx +0 -10
- package/templates/web-app/template/src/pages/AiwfDashboard.tsx +0 -57
- package/templates/web-app/template/src/pages/HomePage.tsx +0 -89
- package/templates/web-app/template/src/pages/NotFound.tsx +0 -25
- package/templates/web-app/template/src/stores/aiwfStore.ts +0 -126
- package/templates/web-app/template/src/types/global.d.ts +0 -9
- package/templates/web-app/template/src/vite-env.d.ts +0 -1
- package/templates/web-app/template/tailwind.config.js +0 -30
- package/templates/web-app/template/tsconfig.json +0 -37
- package/templates/web-app/template/tsconfig.node.json +0 -10
- package/templates/web-app/template/vite.config.ts +0 -23
- /package/rules/global/{code-style-guide.md ā aiwf-code-style-guide.md} +0 -0
- /package/rules/global/{coding-principles.md ā aiwf-coding-principles.md} +0 -0
- /package/rules/global/{development-process.md ā aiwf-development-process.md} +0 -0
- /package/rules/global/{global-rules.md ā aiwf-global-rules.md} +0 -0
- /package/rules/manual/{generate-plan-docs.md ā aiwf-generate-plan-docs.md} +0 -0
package/src/cli/index.js
CHANGED
|
@@ -555,6 +555,69 @@ checkpoint
|
|
|
555
555
|
}
|
|
556
556
|
});
|
|
557
557
|
|
|
558
|
+
checkpoint
|
|
559
|
+
.command('add [type]')
|
|
560
|
+
.alias('create')
|
|
561
|
+
.description('Create a checkpoint / 첓ķ¬ķ¬ģøķø ģģ±')
|
|
562
|
+
.option('-m, --message <text>', 'Description for the checkpoint / 첓ķ¬ķ¬ģøķø ģ¤ėŖ
')
|
|
563
|
+
.option('--meta <json>', 'Additional metadata as JSON / ģ¶ź° ė©ķė°ģ“ķ°(JSON)')
|
|
564
|
+
.option('--cleanup <n>', 'Keep only last N checkpoints after creating / ģģ± ķ ģµź·¼ Nź°ė§ 볓씓')
|
|
565
|
+
.action(async (type, options) => {
|
|
566
|
+
try {
|
|
567
|
+
const fs = await import('fs/promises');
|
|
568
|
+
const path = await import('path');
|
|
569
|
+
let currentDir = process.cwd();
|
|
570
|
+
|
|
571
|
+
// ķė”ģ ķø ė£Øķø ķģ (.aiwf źø°ģ¤)
|
|
572
|
+
while (currentDir !== path.parse(currentDir).root) {
|
|
573
|
+
try {
|
|
574
|
+
await fs.access(path.join(currentDir, '.aiwf'));
|
|
575
|
+
break;
|
|
576
|
+
} catch {
|
|
577
|
+
currentDir = path.dirname(currentDir);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const manager = new CheckpointManager(currentDir);
|
|
582
|
+
await manager.initialize();
|
|
583
|
+
|
|
584
|
+
// ė©ķė°ģ“ķ° źµ¬ģ±
|
|
585
|
+
const metadata = {};
|
|
586
|
+
if (options.message) metadata.message = options.message;
|
|
587
|
+
if (options.meta) {
|
|
588
|
+
try {
|
|
589
|
+
const parsed = JSON.parse(options.meta);
|
|
590
|
+
Object.assign(metadata, parsed);
|
|
591
|
+
} catch (e) {
|
|
592
|
+
console.error(chalk.red('ā --meta ź°ģ“ ģ¬ė°ė„ø JSON ķģģ“ ģėėė¤.'));
|
|
593
|
+
process.exit(1);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
const cpType = type || 'manual';
|
|
598
|
+
const checkpointId = await manager.createCheckpoint(cpType, metadata);
|
|
599
|
+
|
|
600
|
+
console.log(chalk.green('ā
첓ķ¬ķ¬ģøķø ģģ± ģė£!'));
|
|
601
|
+
console.log(` ID: ${chalk.cyan(checkpointId)} ģ ķ: ${chalk.yellow(cpType)}`);
|
|
602
|
+
if (metadata.message) {
|
|
603
|
+
console.log(` ė©ģģ§: ${chalk.blue(metadata.message)}`);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
if (options.cleanup) {
|
|
607
|
+
const keep = parseInt(options.cleanup, 10);
|
|
608
|
+
if (!Number.isNaN(keep) && keep > 0) {
|
|
609
|
+
await manager.cleanup(keep);
|
|
610
|
+
console.log(`š§¹ ģµź·¼ ${chalk.cyan(keep)}ź°ė§ 볓씓ķėė” ģ 리ķģµėė¤.`);
|
|
611
|
+
} else {
|
|
612
|
+
console.log(chalk.yellow('ā ļø --cleanup ź°ģ“ ģ ķØķģ§ ģģ ģ 리넼 걓ėėėė¤. ģ ģė” ģ
ė „ķģøģ.'));
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
} catch (error) {
|
|
616
|
+
console.error(chalk.red('ā 첓ķ¬ķ¬ģøķø ģģ± ģ¤ķØ:'), error.message);
|
|
617
|
+
process.exit(1);
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
|
|
558
621
|
checkpoint
|
|
559
622
|
.command('restore <checkpointId>')
|
|
560
623
|
.description('Restore from checkpoint / 첓ķ¬ķ¬ģøķøģģ 복구')
|
|
@@ -632,6 +695,281 @@ checkpoint
|
|
|
632
695
|
}
|
|
633
696
|
});
|
|
634
697
|
|
|
698
|
+
// 첓ķ¬ķ¬ģøķø 리ķ¬ķø ģģ±
|
|
699
|
+
checkpoint
|
|
700
|
+
.command('report')
|
|
701
|
+
.description('Generate progress report / ģ§ķ ģķ© ė¦¬ķ¬ķø ģģ±')
|
|
702
|
+
.action(async () => {
|
|
703
|
+
try {
|
|
704
|
+
const fs = await import('fs/promises');
|
|
705
|
+
const path = await import('path');
|
|
706
|
+
let currentDir = process.cwd();
|
|
707
|
+
|
|
708
|
+
while (currentDir !== path.parse(currentDir).root) {
|
|
709
|
+
try {
|
|
710
|
+
await fs.access(path.join(currentDir, '.aiwf'));
|
|
711
|
+
break;
|
|
712
|
+
} catch {
|
|
713
|
+
currentDir = path.dirname(currentDir);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
const manager = new CheckpointManager(currentDir);
|
|
718
|
+
await manager.loadState();
|
|
719
|
+
|
|
720
|
+
console.log(chalk.blue('š ģ§ķ ģķ© ė¦¬ķ¬ķø ģģ± ģ¤...'));
|
|
721
|
+
console.log('');
|
|
722
|
+
|
|
723
|
+
const report = await manager.generateProgressReport();
|
|
724
|
+
|
|
725
|
+
console.log(chalk.bold('šÆ YOLO ģøģ
리ķ¬ķø'));
|
|
726
|
+
console.log(''.padEnd(50, '='));
|
|
727
|
+
console.log('');
|
|
728
|
+
|
|
729
|
+
// ģøģ
ģ 볓
|
|
730
|
+
console.log(chalk.bold('š ģøģ
ģ 볓:'));
|
|
731
|
+
console.log(` ID: ${chalk.cyan(report.session.id)}`);
|
|
732
|
+
console.log(` ģģ: ${chalk.gray(new Date(report.session.started).toLocaleString())}`);
|
|
733
|
+
console.log(` ģ¤ķ린ķø: ${chalk.blue(report.session.sprint || 'N/A')}`);
|
|
734
|
+
console.log('');
|
|
735
|
+
|
|
736
|
+
// ģ§ķ ģķ©
|
|
737
|
+
console.log(chalk.bold('š ģ§ķ ģķ©:'));
|
|
738
|
+
console.log(` ģė£: ${chalk.green(report.progress.completed)}ź°`);
|
|
739
|
+
console.log(` ģ¤ķØ: ${chalk.red(report.progress.failed)}ź°`);
|
|
740
|
+
console.log(` 걓ėė: ${chalk.yellow(report.progress.skipped)}ź°`);
|
|
741
|
+
console.log('');
|
|
742
|
+
|
|
743
|
+
// ģ±ė„ ģ§ķ
|
|
744
|
+
console.log(chalk.bold('ā±ļø ģ±ė„ ģ§ķ:'));
|
|
745
|
+
console.log(` ģ“ ģź°: ${chalk.blue(report.performance.total_time)}`);
|
|
746
|
+
console.log(` ķź· ķģ¤ķ¬ ģź°: ${chalk.blue(report.performance.avg_task_time)}`);
|
|
747
|
+
console.log(` ģ±ź³µė„ : ${chalk.green(report.performance.success_rate)}`);
|
|
748
|
+
|
|
749
|
+
} catch (error) {
|
|
750
|
+
console.error(chalk.red('ā 리ķ¬ķø ģģ± ģ¤ķØ:'), error.message);
|
|
751
|
+
process.exit(1);
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
// 첓ķ¬ķ¬ģøķø ģ 리
|
|
756
|
+
checkpoint
|
|
757
|
+
.command('clean')
|
|
758
|
+
.description('Clean old checkpoints / ģ¤ėė 첓ķ¬ķ¬ģøķø ģ 리')
|
|
759
|
+
.option('--keep <n>', 'Number of checkpoints to keep / ģ ģ§ķ 첓ķ¬ķ¬ģøķø ģ', '10')
|
|
760
|
+
.option('--dry-run', 'Preview without deletion / ģ¤ģ ģģ ģģ“ ėÆøė¦¬ė³“źø°')
|
|
761
|
+
.action(async (options) => {
|
|
762
|
+
try {
|
|
763
|
+
const fs = await import('fs/promises');
|
|
764
|
+
const path = await import('path');
|
|
765
|
+
let currentDir = process.cwd();
|
|
766
|
+
|
|
767
|
+
while (currentDir !== path.parse(currentDir).root) {
|
|
768
|
+
try {
|
|
769
|
+
await fs.access(path.join(currentDir, '.aiwf'));
|
|
770
|
+
break;
|
|
771
|
+
} catch {
|
|
772
|
+
currentDir = path.dirname(currentDir);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
const manager = new CheckpointManager(currentDir);
|
|
777
|
+
const keepLast = parseInt(options.keep);
|
|
778
|
+
|
|
779
|
+
console.log(chalk.blue(`𧹠첓ķ¬ķ¬ģøķø ģ 리 ģ¤... (ģµź·¼ ${keepLast}ź° ģ ģ§)`));
|
|
780
|
+
|
|
781
|
+
if (options.dryRun) {
|
|
782
|
+
console.log(chalk.yellow('š ėė¼ģ“ė° ėŖØė: ģ¤ģ ģģ ė ģķķģ§ ģģµėė¤.'));
|
|
783
|
+
const checkpoints = await manager.listCheckpoints();
|
|
784
|
+
if (checkpoints.length <= keepLast) {
|
|
785
|
+
console.log(chalk.green('ā
ģ 리ķ 첓ķ¬ķ¬ģøķøź° ģģµėė¤.'));
|
|
786
|
+
} else {
|
|
787
|
+
const toDelete = checkpoints.slice(keepLast);
|
|
788
|
+
console.log(chalk.yellow(`ģģ ģģ 첓ķ¬ķ¬ģøķø (${toDelete.length}ź°):`));
|
|
789
|
+
for (const cp of toDelete) {
|
|
790
|
+
console.log(` ${chalk.red('šļø')} ${chalk.cyan(cp.id)}`);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
} else {
|
|
794
|
+
await manager.cleanup(keepLast);
|
|
795
|
+
console.log(chalk.green('ā
첓ķ¬ķ¬ģøķø ģ 리 ģė£!'));
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
} catch (error) {
|
|
799
|
+
console.error(chalk.red('ā 첓ķ¬ķ¬ģøķø ģ 리 ģ¤ķØ:'), error.message);
|
|
800
|
+
process.exit(1);
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
// Engineering Guard commands (ģ¤ė²ģģ§ėģ“ė§ ė°©ģ§)
|
|
805
|
+
const guard = program.command('guard');
|
|
806
|
+
guard.description('Engineering guard for overengineering prevention / ģ¤ė²ģģ§ėģ“ė§ ė°©ģ§ ź°ė');
|
|
807
|
+
|
|
808
|
+
guard
|
|
809
|
+
.command('check [path]')
|
|
810
|
+
.description('Check project complexity / ķė”ģ ķø ė³µģ”ė ź²ģ¬')
|
|
811
|
+
.option('--config <path>', 'YOLO config file path / YOLO ģ¤ģ ķģ¼ ź²½ė”', '.aiwf/yolo-config.yaml')
|
|
812
|
+
.action(async (targetPath, options) => {
|
|
813
|
+
try {
|
|
814
|
+
const { EngineeringGuard } = await import('../utils/engineering-guard.js');
|
|
815
|
+
const guard = new EngineeringGuard();
|
|
816
|
+
|
|
817
|
+
// ģ¤ģ ķģ¼ ė”ė
|
|
818
|
+
await guard.loadConfig(options.config);
|
|
819
|
+
|
|
820
|
+
const checkPath = targetPath || process.cwd();
|
|
821
|
+
console.log(chalk.blue(`š ė³µģ”ė ź²ģ¬ ģ¤: ${checkPath}`));
|
|
822
|
+
console.log('');
|
|
823
|
+
|
|
824
|
+
const report = await guard.checkProject(checkPath);
|
|
825
|
+
|
|
826
|
+
// ź²°ź³¼ ģ¶ė „
|
|
827
|
+
console.log(chalk.bold('š ė³µģ”ė ė¶ģ ź²°ź³¼:'));
|
|
828
|
+
console.log(` ģ“ ģė°ģ¬ķ: ${chalk.yellow(report.summary.total_violations)}`);
|
|
829
|
+
console.log(` ėģ ģ¬ź°ė: ${chalk.red(report.summary.high_severity)}`);
|
|
830
|
+
console.log(` ģ¤ź° ģ¬ź°ė: ${chalk.yellow(report.summary.medium_severity)}`);
|
|
831
|
+
console.log(` ź²½ź³ ģ¬ķ: ${chalk.blue(report.summary.warnings)}`);
|
|
832
|
+
console.log('');
|
|
833
|
+
|
|
834
|
+
if (report.violations && report.violations.length > 0) {
|
|
835
|
+
console.log(chalk.bold('šØ ģė°ģ¬ķ:'));
|
|
836
|
+
for (const violation of report.violations.slice(0, 10)) {
|
|
837
|
+
const icon = violation.severity === 'high' ? 'ā' :
|
|
838
|
+
violation.severity === 'medium' ? 'ā ļø' : 'š”';
|
|
839
|
+
console.log(` ${icon} ${chalk.cyan(violation.type)}: ${violation.file || violation.message}`);
|
|
840
|
+
if (violation.details) {
|
|
841
|
+
console.log(` ${chalk.gray(violation.details)}`);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
console.log('');
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
if (report.recommendations && report.recommendations.length > 0) {
|
|
848
|
+
console.log(chalk.bold('š” ź¶ģ„ģ¬ķ:'));
|
|
849
|
+
for (const rec of report.recommendations) {
|
|
850
|
+
console.log(` ⢠${chalk.green(rec)}`);
|
|
851
|
+
}
|
|
852
|
+
console.log('');
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// ķµź³¼/ģ¤ķØ ķģ
|
|
856
|
+
if (report.passed) {
|
|
857
|
+
console.log(chalk.green('ā
ė³µģ”ė źø°ģ¤ ķµź³¼'));
|
|
858
|
+
} else {
|
|
859
|
+
console.log(chalk.red('ā ė³µģ”ė źø°ģ¤ ģ“ź³¼ - 리ķ©ķ ė§ ķģ'));
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
} catch (error) {
|
|
863
|
+
console.error(chalk.red('ā ė³µģ”ė ź²ģ¬ ģ¤ķØ:'), error.message);
|
|
864
|
+
process.exit(1);
|
|
865
|
+
}
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
guard
|
|
869
|
+
.command('quick [path]')
|
|
870
|
+
.description('Quick complexity check / ė¹ ė„ø ė³µģ”ė 첓ķ¬')
|
|
871
|
+
.action(async (targetPath) => {
|
|
872
|
+
try {
|
|
873
|
+
const { quickCheck } = await import('../utils/engineering-guard.js');
|
|
874
|
+
|
|
875
|
+
const checkPath = targetPath || process.cwd();
|
|
876
|
+
console.log(chalk.blue(`ā” ė¹ ė„ø ė³µģ”ė 첓ķ¬: ${checkPath}`));
|
|
877
|
+
|
|
878
|
+
const report = await quickCheck(checkPath);
|
|
879
|
+
|
|
880
|
+
if (report.summary.high_severity > 0) {
|
|
881
|
+
console.log(chalk.red('ā ļø ģ¤ė²ģģ§ėģ“ė§ ģķ ź°ģ§!'));
|
|
882
|
+
console.log('ź¶ģ„ģ¬ķ:', report.recommendations.join(', '));
|
|
883
|
+
} else {
|
|
884
|
+
console.log(chalk.green('ā
ė³µģ”ė ģķø'));
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
} catch (error) {
|
|
888
|
+
console.error(chalk.red('ā ė¹ ė„ø ģ²“ķ¬ ģ¤ķØ:'), error.message);
|
|
889
|
+
process.exit(1);
|
|
890
|
+
}
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
guard
|
|
894
|
+
.command('init')
|
|
895
|
+
.description('Initialize YOLO config with guard settings / YOLO ģ¤ģ ģ“źø°ķ')
|
|
896
|
+
.action(async () => {
|
|
897
|
+
try {
|
|
898
|
+
const fs = await import('fs/promises');
|
|
899
|
+
const path = await import('path');
|
|
900
|
+
const yaml = await import('js-yaml');
|
|
901
|
+
|
|
902
|
+
const configPath = path.join(process.cwd(), '.aiwf', 'yolo-config.yaml');
|
|
903
|
+
|
|
904
|
+
// źø°ė³ø ģ¤ģ ģģ±
|
|
905
|
+
const defaultConfig = {
|
|
906
|
+
engineering_level: 'minimal',
|
|
907
|
+
focus_rules: ['requirement_first', 'simple_solution', 'no_gold_plating', 'stay_on_track'],
|
|
908
|
+
overengineering_prevention: {
|
|
909
|
+
max_file_lines: 300,
|
|
910
|
+
max_function_lines: 50,
|
|
911
|
+
max_nesting_depth: 4,
|
|
912
|
+
max_abstraction_layers: 3,
|
|
913
|
+
limit_design_patterns: true,
|
|
914
|
+
no_future_proofing: true,
|
|
915
|
+
enforce_yagni: true
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
// .aiwf ėė ķ 리 ģģ±
|
|
920
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
921
|
+
|
|
922
|
+
// ģ¤ģ ķģ¼ ģ°źø°
|
|
923
|
+
await fs.writeFile(configPath, yaml.dump(defaultConfig), 'utf-8');
|
|
924
|
+
|
|
925
|
+
console.log(chalk.green('ā
YOLO ģ¤ģ ķģ¼ ģģ± ģė£!'));
|
|
926
|
+
console.log(` ź²½ė”: ${chalk.cyan(configPath)}`);
|
|
927
|
+
console.log('');
|
|
928
|
+
console.log(chalk.bold('š”ļø ģ¤ė²ģģ§ėģ“ė§ ė°©ģ§ ģ¤ģ :'));
|
|
929
|
+
console.log(` ķģ¼ ķ¬źø° ģ ķ: ${chalk.yellow('300')}ģ¤`);
|
|
930
|
+
console.log(` ķØģ ķ¬źø° ģ ķ: ${chalk.yellow('50')}ģ¤`);
|
|
931
|
+
console.log(` ģ¤ģ²© ź¹ģ“ ģ ķ: ${chalk.yellow('4')}ė 벨`);
|
|
932
|
+
console.log(` YAGNI ģģ¹: ${chalk.green('ģ ģ©')}`);
|
|
933
|
+
|
|
934
|
+
} catch (error) {
|
|
935
|
+
console.error(chalk.red('ā ģ¤ģ ģ“źø°ķ ģ¤ķØ:'), error.message);
|
|
936
|
+
process.exit(1);
|
|
937
|
+
}
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
guard
|
|
941
|
+
.command('feedback [area]')
|
|
942
|
+
.description('Get engineering feedback for area / ķ¹ģ ģģ ķ¼ėė°± ė°źø°')
|
|
943
|
+
.action(async (area) => {
|
|
944
|
+
try {
|
|
945
|
+
const { EngineeringGuard } = await import('../utils/engineering-guard.js');
|
|
946
|
+
const guard = new EngineeringGuard();
|
|
947
|
+
|
|
948
|
+
// ģ¤ģ ķģ¼ ė”ė ģė
|
|
949
|
+
await guard.loadConfig('.aiwf/yolo-config.yaml');
|
|
950
|
+
|
|
951
|
+
const targetArea = area || 'current_task_area';
|
|
952
|
+
console.log(chalk.blue(`š” ģģ§ėģ“ė§ ķ¼ėė°± ģ ź³µ: ${targetArea}`));
|
|
953
|
+
console.log('');
|
|
954
|
+
|
|
955
|
+
const feedback = await guard.provideFeedback(targetArea);
|
|
956
|
+
|
|
957
|
+
if (feedback && feedback.length > 0) {
|
|
958
|
+
for (const item of feedback) {
|
|
959
|
+
const icon = item.level === 'error' ? 'ā' :
|
|
960
|
+
item.level === 'warning' ? 'ā ļø' : 'š”';
|
|
961
|
+
console.log(`${icon} ${item.message}`);
|
|
962
|
+
}
|
|
963
|
+
} else {
|
|
964
|
+
console.log(chalk.green('ā
ķģ¬ ģģģ ė³µģ”ė źø°ģ¤ģ ė§ģ”±ķ©ėė¤.'));
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
} catch (error) {
|
|
968
|
+
console.error(chalk.red('ā ķ¼ėė°± ģģ± ģ¤ķØ:'), error.message);
|
|
969
|
+
process.exit(1);
|
|
970
|
+
}
|
|
971
|
+
});
|
|
972
|
+
|
|
635
973
|
// GitHub integration commands
|
|
636
974
|
const github = program.command('github');
|
|
637
975
|
github.description('GitHub integration / GitHub ķµķ©');
|
package/src/config/file-lists.js
CHANGED
|
@@ -66,15 +66,15 @@ export const COMMAND_FILES = [
|
|
|
66
66
|
|
|
67
67
|
// źøė”ė² ė£° ķģ¼ ėŖ©ė”
|
|
68
68
|
export const GLOBAL_RULES_FILES = [
|
|
69
|
-
'code-style-guide.md',
|
|
70
|
-
'coding-principles.md',
|
|
71
|
-
'development-process.md',
|
|
72
|
-
'global-rules.md'
|
|
69
|
+
'aiwf-code-style-guide.md',
|
|
70
|
+
'aiwf-coding-principles.md',
|
|
71
|
+
'aiwf-development-process.md',
|
|
72
|
+
'aiwf-global-rules.md'
|
|
73
73
|
];
|
|
74
74
|
|
|
75
75
|
// ģė 룰 ķģ¼ ėŖ©ė”
|
|
76
76
|
export const MANUAL_RULES_FILES = [
|
|
77
|
-
'generate-plan-docs.md'
|
|
77
|
+
'aiwf-generate-plan-docs.md'
|
|
78
78
|
];
|
|
79
79
|
|
|
80
80
|
// ķ
ķ릿 ķģ¼ ėŖ©ė” (ķ„ķ ģ¶ź° ģģ )
|
|
@@ -5,8 +5,7 @@ import chalk from 'chalk';
|
|
|
5
5
|
import {
|
|
6
6
|
TOOL_DIRS,
|
|
7
7
|
AIWF_DIRS,
|
|
8
|
-
FILES
|
|
9
|
-
getBackupDirName as getBackupDirNamePath
|
|
8
|
+
FILES
|
|
10
9
|
} from '../utils/paths.js';
|
|
11
10
|
|
|
12
11
|
let BACKUP_DIR = null;
|
|
@@ -16,7 +15,9 @@ let BACKUP_DIR = null;
|
|
|
16
15
|
* @returns {string} Backup directory name
|
|
17
16
|
*/
|
|
18
17
|
function getBackupDirName() {
|
|
19
|
-
|
|
18
|
+
const now = new Date();
|
|
19
|
+
const timestamp = now.toISOString().replace(/[:.]/g, '-').slice(0, -5);
|
|
20
|
+
return `backup-${timestamp}`;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/**
|
package/src/lib/installer.js
CHANGED
|
@@ -34,7 +34,6 @@ import {
|
|
|
34
34
|
import {
|
|
35
35
|
FILES,
|
|
36
36
|
TOOL_DIRS,
|
|
37
|
-
TEMP_DIRS,
|
|
38
37
|
AIWF_DIRS,
|
|
39
38
|
BASE_DIRS,
|
|
40
39
|
getAllAiwfDirectories,
|
|
@@ -507,14 +506,112 @@ async function updateCommands(languagePath, spinner, msg, debugLog) {
|
|
|
507
506
|
}
|
|
508
507
|
}
|
|
509
508
|
|
|
509
|
+
/**
|
|
510
|
+
* Check if tool directories exist and handle them
|
|
511
|
+
* @param {Object} spinner - Ora spinner instance
|
|
512
|
+
* @param {Object} msg - Localized messages
|
|
513
|
+
* @param {boolean} debugLog - Debug mode flag
|
|
514
|
+
* @returns {Promise<Object>} Directory status info
|
|
515
|
+
*/
|
|
516
|
+
async function checkAndHandleExistingToolDirs(spinner, msg, debugLog) {
|
|
517
|
+
const toolDirStatus = {
|
|
518
|
+
cursor: {
|
|
519
|
+
exists: false,
|
|
520
|
+
hadFiles: false,
|
|
521
|
+
backedUp: false
|
|
522
|
+
},
|
|
523
|
+
windsurf: {
|
|
524
|
+
exists: false,
|
|
525
|
+
hadFiles: false,
|
|
526
|
+
backedUp: false
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
// Check Cursor directory
|
|
531
|
+
try {
|
|
532
|
+
await fs.access(TOOL_DIRS.CURSOR_RULES);
|
|
533
|
+
toolDirStatus.cursor.exists = true;
|
|
534
|
+
|
|
535
|
+
const cursorFiles = await fs.readdir(TOOL_DIRS.CURSOR_RULES);
|
|
536
|
+
const mdcFiles = cursorFiles.filter(file => file.endsWith('.mdc'));
|
|
537
|
+
|
|
538
|
+
if (mdcFiles.length > 0) {
|
|
539
|
+
toolDirStatus.cursor.hadFiles = true;
|
|
540
|
+
logWithSpinner(spinner, `${msg.foundExistingCursor} (${mdcFiles.length} files)`, debugLog);
|
|
541
|
+
|
|
542
|
+
// Backup existing files
|
|
543
|
+
logWithSpinner(spinner, msg.backingUpToolFiles, debugLog);
|
|
544
|
+
const backupDir = path.join(TOOL_DIRS.CURSOR_RULES, `backup_${Date.now()}`);
|
|
545
|
+
await fs.mkdir(backupDir, { recursive: true });
|
|
546
|
+
|
|
547
|
+
for (const file of mdcFiles) {
|
|
548
|
+
const srcPath = path.join(TOOL_DIRS.CURSOR_RULES, file);
|
|
549
|
+
const backupPath = path.join(backupDir, file);
|
|
550
|
+
await fs.copyFile(srcPath, backupPath);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
toolDirStatus.cursor.backedUp = true;
|
|
554
|
+
logWithSpinner(spinner, `${msg.toolBackupCreated}: ${backupDir}`, debugLog);
|
|
555
|
+
|
|
556
|
+
// Remove existing files
|
|
557
|
+
for (const file of mdcFiles) {
|
|
558
|
+
await fs.unlink(path.join(TOOL_DIRS.CURSOR_RULES, file));
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
} catch (error) {
|
|
562
|
+
// Directory doesn't exist, that's fine
|
|
563
|
+
logWithSpinner(spinner, `Cursor rules directory not found, will create new`, debugLog);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// Check Windsurf directory
|
|
567
|
+
try {
|
|
568
|
+
await fs.access(TOOL_DIRS.WINDSURF_RULES);
|
|
569
|
+
toolDirStatus.windsurf.exists = true;
|
|
570
|
+
|
|
571
|
+
const windsurfFiles = await fs.readdir(TOOL_DIRS.WINDSURF_RULES);
|
|
572
|
+
const mdFiles = windsurfFiles.filter(file => file.endsWith('.md'));
|
|
573
|
+
|
|
574
|
+
if (mdFiles.length > 0) {
|
|
575
|
+
toolDirStatus.windsurf.hadFiles = true;
|
|
576
|
+
logWithSpinner(spinner, `${msg.foundExistingWindsurf} (${mdFiles.length} files)`, debugLog);
|
|
577
|
+
|
|
578
|
+
// Backup existing files
|
|
579
|
+
logWithSpinner(spinner, msg.backingUpToolFiles, debugLog);
|
|
580
|
+
const backupDir = path.join(TOOL_DIRS.WINDSURF_RULES, `backup_${Date.now()}`);
|
|
581
|
+
await fs.mkdir(backupDir, { recursive: true });
|
|
582
|
+
|
|
583
|
+
for (const file of mdFiles) {
|
|
584
|
+
const srcPath = path.join(TOOL_DIRS.WINDSURF_RULES, file);
|
|
585
|
+
const backupPath = path.join(backupDir, file);
|
|
586
|
+
await fs.copyFile(srcPath, backupPath);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
toolDirStatus.windsurf.backedUp = true;
|
|
590
|
+
logWithSpinner(spinner, `${msg.toolBackupCreated}: ${backupDir}`, debugLog);
|
|
591
|
+
|
|
592
|
+
// Remove existing files
|
|
593
|
+
for (const file of mdFiles) {
|
|
594
|
+
await fs.unlink(path.join(TOOL_DIRS.WINDSURF_RULES, file));
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
} catch (error) {
|
|
598
|
+
// Directory doesn't exist, that's fine
|
|
599
|
+
logWithSpinner(spinner, `Windsurf rules directory not found, will create new`, debugLog);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
return toolDirStatus;
|
|
603
|
+
}
|
|
604
|
+
|
|
510
605
|
/**
|
|
511
606
|
* Download and process rules
|
|
512
607
|
* @param {Object} spinner - Ora spinner instance
|
|
513
|
-
{{ ... }}
|
|
514
608
|
* @param {Object} msg - Localized messages
|
|
515
609
|
* @param {boolean} debugLog - Debug mode flag
|
|
516
610
|
*/
|
|
517
611
|
async function downloadAndProcessRules(spinner, msg, debugLog) {
|
|
612
|
+
// Check and handle existing tool directories first
|
|
613
|
+
logWithSpinner(spinner, msg.checkingExistingTools, debugLog);
|
|
614
|
+
const toolDirStatus = await checkAndHandleExistingToolDirs(spinner, msg, debugLog);
|
|
518
615
|
// Try to download from GitHub first, fallback to local files
|
|
519
616
|
const tmpRulesGlobal = path.join(os.tmpdir(), 'aiwf-rules-global');
|
|
520
617
|
const tmpRulesManual = path.join(os.tmpdir(), 'aiwf-rules-manual');
|
|
@@ -670,6 +767,32 @@ async function downloadAndProcessRules(spinner, msg, debugLog) {
|
|
|
670
767
|
} catch (error) {
|
|
671
768
|
logWithSpinner(spinner, `No rules/manual directory found`, debugLog);
|
|
672
769
|
}
|
|
770
|
+
|
|
771
|
+
// Success message for tool rules installation
|
|
772
|
+
logWithSpinner(spinner, msg.toolRulesInstalled, debugLog);
|
|
773
|
+
|
|
774
|
+
// Display installation results for tool directories
|
|
775
|
+
if (toolDirStatus.cursor.backedUp || toolDirStatus.windsurf.backedUp) {
|
|
776
|
+
console.log(chalk.cyan(`\nš Tool Directory Installation Results:`));
|
|
777
|
+
|
|
778
|
+
if (toolDirStatus.cursor.backedUp) {
|
|
779
|
+
console.log(chalk.yellow(` ⢠Cursor: Existing rules backed up and replaced`));
|
|
780
|
+
} else if (toolDirStatus.cursor.exists) {
|
|
781
|
+
console.log(chalk.green(` ⢠Cursor: Rules installed (directory was empty)`));
|
|
782
|
+
} else {
|
|
783
|
+
console.log(chalk.green(` ⢠Cursor: Rules installed (new directory)`));
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
if (toolDirStatus.windsurf.backedUp) {
|
|
787
|
+
console.log(chalk.yellow(` ⢠Windsurf: Existing rules backed up and replaced`));
|
|
788
|
+
} else if (toolDirStatus.windsurf.exists) {
|
|
789
|
+
console.log(chalk.green(` ⢠Windsurf: Rules installed (directory was empty)`));
|
|
790
|
+
} else {
|
|
791
|
+
console.log(chalk.green(` ⢠Windsurf: Rules installed (new directory)`));
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
return toolDirStatus;
|
|
673
796
|
}
|
|
674
797
|
|
|
675
798
|
/**
|
|
@@ -819,7 +942,7 @@ export async function installAIWF(options = {}) {
|
|
|
819
942
|
await updateCommands(languagePath, spinner, msg, debugLog);
|
|
820
943
|
|
|
821
944
|
// Download and process rules
|
|
822
|
-
await downloadAndProcessRules(spinner, msg, debugLog);
|
|
945
|
+
const toolDirStatus = await downloadAndProcessRules(spinner, msg, debugLog);
|
|
823
946
|
|
|
824
947
|
// Restore project files if needed
|
|
825
948
|
if (projectBackupDir) {
|