@relipa/ai-flow-kit 0.1.2 → 0.1.4-beta.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/README.md +139 -0
- package/bin/aiflow.js +89 -2
- package/custom/harness/playwright/.env.example +10 -0
- package/custom/harness/playwright/playwright.config.ts +34 -0
- package/custom/harness/playwright/tests/e2e/auth.setup.ts +25 -0
- package/custom/harness/playwright/tests/e2e/fixtures/test.ts +6 -0
- package/custom/harness/playwright/tests/e2e/pages/BasePage.ts +9 -0
- package/custom/harness/playwright/tests/e2e/support/auth.ts +5 -0
- package/custom/mcp-presets/playwright.json +8 -0
- package/custom/rules/test-patterns.md +70 -0
- package/custom/skills/automation-testing/SKILL.md +239 -0
- package/custom/skills/automation-testing/templates/BasePage.ts +29 -0
- package/custom/skills/automation-testing/templates/PageObject.example.ts +29 -0
- package/custom/skills/automation-testing/templates/playwright.config.ts +39 -0
- package/custom/skills/automation-testing/templates/spec.example.ts +29 -0
- package/custom/skills/ba-skills/skill-ba-phan-tich-ban-dau-v1.md +44 -0
- package/custom/skills/ba-skills/skill-ba-prototype-v1.md +35 -0
- package/custom/skills/ba-skills/skill-ba-qa-template-v1.md +21 -0
- package/custom/skills/ba-skills/skill-ba-qa-v1.md +35 -0
- package/custom/skills/ba-skills/skill-ba-template-phan-tich-ban-dau-v1.md +30 -0
- package/custom/skills/ba-skills/skill-ba-template-uc-v1.md +83 -0
- package/custom/skills/ba-skills/skill-ba-ve-luong-mermaid-v1.md +35 -0
- package/custom/skills/ba-skills/skill-ba-viet-spec-uc-v1.md +38 -0
- package/custom/skills/ba-skills/skill-ba-xay-dung-business-rules-v1.md +39 -0
- package/custom/skills/coverage-check/SKILL.md +202 -0
- package/custom/skills/evidence-aggregation/SKILL.md +246 -0
- package/custom/skills/execute-flow/SKILL.md +499 -0
- package/custom/skills/execute-flow/templates/playwright.config.ts +39 -0
- package/custom/skills/gate-review/SKILL.md +195 -0
- package/custom/skills/generate-test-report/SKILL.md +99 -0
- package/custom/skills/generate-test-report/templates/test-report.md +58 -0
- package/custom/skills/generate-testcase/SKILL.md +350 -0
- package/custom/skills/generate-testcase/templates/testcase.md +88 -0
- package/custom/skills/log-bug/SKILL.md +131 -0
- package/custom/skills/pr-impact-analysis/SKILL.md +180 -0
- package/custom/skills/retest-orchestration/SKILL.md +191 -0
- package/custom/skills/script-sync/SKILL.md +208 -0
- package/custom/skills/test-analysis/SKILL.md +300 -0
- package/custom/skills/test-skills/categories/00-core/00.01.requirement-analysis.md +111 -0
- package/custom/skills/test-skills/categories/00-core/00.02.risk-analysis.md +24 -0
- package/custom/skills/test-skills/categories/00-core/00.03.test-scenario-builder.md +90 -0
- package/custom/skills/test-skills/categories/00-core/00.04.testcase-review.md +68 -0
- package/custom/skills/test-skills/categories/01-test-design/01.01.boundary-value-analysis.md +30 -0
- package/custom/skills/test-skills/categories/01-test-design/01.02.equivalence.partitioning.md +27 -0
- package/custom/skills/test-skills/categories/01-test-design/01.03.decision-table.md +26 -0
- package/custom/skills/test-skills/categories/01-test-design/01.04.state.transition.md +26 -0
- package/custom/skills/test-skills/categories/01-test-design/01.05.pairwise.md +25 -0
- package/custom/skills/test-skills/categories/01-test-design/01.06.error-guessing.md +28 -0
- package/custom/skills/test-skills/categories/02-ui-testing/02.01.UI-layout.md +29 -0
- package/custom/skills/test-skills/categories/02-ui-testing/02.02.form-validation.md +57 -0
- package/custom/skills/test-skills/categories/02-ui-testing/02.03.navigation.md +27 -0
- package/custom/skills/test-skills/categories/02-ui-testing/02.04.localization.md +27 -0
- package/custom/skills/test-skills/categories/02-ui-testing/02.05.accessibility.md +27 -0
- package/custom/skills/test-skills/categories/03-business-testing/03.01.CRUD-testing.md +51 -0
- package/custom/skills/test-skills/categories/03-business-testing/03.02.workflow-testing.md +44 -0
- package/custom/skills/test-skills/categories/03-business-testing/03.03.permission-testing.md +41 -0
- package/custom/skills/test-skills/categories/03-business-testing/03.04.dependency-validation.md +40 -0
- package/custom/skills/test-skills/categories/03-business-testing/03.05.notification-testing.md +43 -0
- package/custom/skills/test-skills/categories/03-business-testing/03.06.calculation.testing.md +44 -0
- package/custom/skills/test-skills/categories/04-data-testing/04.01.database-testing.md +43 -0
- package/custom/skills/test-skills/categories/04-data-testing/04.02.import-export-testing.md +43 -0
- package/custom/skills/test-skills/categories/04-data-testing/04.03.data-mapping.md +39 -0
- package/custom/skills/test-skills/categories/04-data-testing/04.04.duplicate-handling.md +39 -0
- package/custom/skills/test-skills/categories/04-data-testing/04.05.migration.md +42 -0
- package/custom/skills/test-skills/categories/05-integration/05.01.API-testing.md +37 -0
- package/custom/skills/test-skills/categories/05-integration/05.02.third-party-integration.md +36 -0
- package/custom/skills/test-skills/categories/05-integration/05.03.batch-processing.md +38 -0
- package/custom/skills/test-skills/categories/05-integration/05.04.file-upload-download.md +40 -0
- package/custom/skills/test-skills/categories/08-domain-skills/CMS.md +34 -0
- package/custom/skills/test-skills/categories/08-domain-skills/Ecommerce.md +35 -0
- package/custom/skills/test-skills/categories/99-review/99.01.coverage-review.md +35 -0
- package/custom/skills/test-skills/categories/99-review/99.02.knowledge-learning.md +34 -0
- package/custom/skills/test-skills/categories/99-review/99.03.repository-update.md +33 -0
- package/custom/skills/test-skills/categories/99-review/99.04.change-history.md +38 -0
- package/custom/skills/test-skills/rules/Directory_and_Naming_Convention.md +257 -0
- package/custom/skills/test-skills/rules/QA_Writing_Standards.md +49 -0
- package/custom/skills/test-skills/template/template_testcase.md +92 -0
- package/custom/templates/shared/create-spec-workflow.md +441 -0
- package/custom/templates/shared/create-testcase-workflow.md +470 -0
- package/custom/templates/shared/gate-workflow.md +421 -11
- package/docs/common/CHANGELOG.md +52 -0
- package/docs/common/QUICK_START.md +30 -0
- package/docs/common/cli-reference.md +48 -7
- package/package.json +2 -2
- package/scripts/create-score-excel.js +37 -14
- package/scripts/detect.js +10 -0
- package/scripts/guide.js +9 -0
- package/scripts/init.js +48 -1
- package/scripts/prompt.js +36 -0
- package/scripts/review.js +91 -0
- package/scripts/scaffold-playwright.js +106 -0
- package/scripts/task.js +21 -7
- package/scripts/update.js +127 -124
- package/scripts/use.js +36 -12
package/scripts/update.js
CHANGED
|
@@ -1,124 +1,127 @@
|
|
|
1
|
-
const fs = require('fs-extra');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const chalk = require('chalk');
|
|
4
|
-
const { confirm, select } = require('@inquirer/prompts');
|
|
5
|
-
|
|
6
|
-
const PKG_DIR = path.join(__dirname, '..');
|
|
7
|
-
const PKG_VERSION = require('../package.json').version;
|
|
8
|
-
|
|
9
|
-
// Same language map as init.js
|
|
10
|
-
const FRAMEWORK_LANGUAGE = {
|
|
11
|
-
'laravel': 'php',
|
|
12
|
-
'spring-boot': 'java',
|
|
13
|
-
'reactjs': 'javascript',
|
|
14
|
-
'nextjs': 'javascript',
|
|
15
|
-
'vue-nuxt': 'javascript',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
module.exports = async function update(options = {}) {
|
|
19
|
-
const projectDir = process.cwd();
|
|
20
|
-
const aiflowDir = path.join(projectDir, '.aiflow');
|
|
21
|
-
const stateFile = path.join(aiflowDir, 'state.json');
|
|
22
|
-
|
|
23
|
-
if (!(await fs.pathExists(stateFile))) {
|
|
24
|
-
console.log(chalk.red('Project is not initialized. Please run `aiflow init` first.'));
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const state = await fs.readJson(stateFile);
|
|
29
|
-
const currentVersion = state.current_version;
|
|
30
|
-
|
|
31
|
-
if (currentVersion === PKG_VERSION && !options.force) {
|
|
32
|
-
console.log(chalk.cyan(`You are already on v${PKG_VERSION}. Syncing latest assets and instruction files...`));
|
|
33
|
-
} else {
|
|
34
|
-
console.log(chalk.blue(`Updating from v${currentVersion} to v${PKG_VERSION}...`));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const newVersionDir = path.join(aiflowDir, 'versions', PKG_VERSION);
|
|
38
|
-
await fs.ensureDir(newVersionDir);
|
|
39
|
-
|
|
40
|
-
// Merge skills
|
|
41
|
-
const upstreamSkills = path.join(PKG_DIR, 'upstream', 'skills');
|
|
42
|
-
const customSkills = path.join(PKG_DIR, 'custom', 'skills');
|
|
43
|
-
|
|
44
|
-
await fs.ensureDir(path.join(newVersionDir, 'skills'));
|
|
45
|
-
if (await fs.pathExists(upstreamSkills)) {
|
|
46
|
-
await fs.copy(upstreamSkills, path.join(newVersionDir, 'skills'), { overwrite: true });
|
|
47
|
-
}
|
|
48
|
-
if (await fs.pathExists(customSkills)) {
|
|
49
|
-
await fs.copy(customSkills, path.join(newVersionDir, 'skills'), { overwrite: true });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Copy rules: common first, then language-specific overlay (mirrors init.js logic)
|
|
53
|
-
const rulesTarget = path.join(newVersionDir, 'rules');
|
|
54
|
-
const commonRules = path.join(PKG_DIR, 'custom', 'rules', 'common');
|
|
55
|
-
const allRules = path.join(PKG_DIR, 'custom', 'rules');
|
|
56
|
-
const primaryFramework = (state.frameworks || (state.framework ? [state.framework] : []))[0] || null;
|
|
57
|
-
|
|
58
|
-
await fs.ensureDir(rulesTarget);
|
|
59
|
-
if (await fs.pathExists(commonRules)) {
|
|
60
|
-
await fs.copy(commonRules, rulesTarget, { overwrite: true });
|
|
61
|
-
} else if (await fs.pathExists(allRules)) {
|
|
62
|
-
const entries = await fs.readdir(allRules, { withFileTypes: true });
|
|
63
|
-
for (const entry of entries) {
|
|
64
|
-
if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
65
|
-
await fs.copy(path.join(allRules, entry.name), path.join(rulesTarget, entry.name), { overwrite: true });
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (primaryFramework) {
|
|
71
|
-
const lang = FRAMEWORK_LANGUAGE[primaryFramework];
|
|
72
|
-
if (lang) {
|
|
73
|
-
const langRules = path.join(PKG_DIR, 'custom', 'rules', lang);
|
|
74
|
-
if (await fs.pathExists(langRules)) {
|
|
75
|
-
await fs.copy(langRules, rulesTarget, { overwrite: true });
|
|
76
|
-
console.log(chalk.gray(` ✓ Applied ${lang} rules`));
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
console.log(chalk.green(`✓ Downloaded assets for v${PKG_VERSION} into the project.`));
|
|
82
|
-
|
|
83
|
-
// Only offer to delete old version when it's a different version.
|
|
84
|
-
// When --force re-copies the same version, old === new === newVersionDir,
|
|
85
|
-
// so deleting "old" would immediately break the copy step below.
|
|
86
|
-
const isSameVersion = currentVersion === PKG_VERSION;
|
|
87
|
-
if (!isSameVersion) {
|
|
88
|
-
const deleteOld = await confirm({ message: `Do you want to delete the old version (v${currentVersion})?` });
|
|
89
|
-
if (deleteOld) {
|
|
90
|
-
await fs.remove(path.join(aiflowDir, 'versions', currentVersion));
|
|
91
|
-
console.log(chalk.gray(`Deleted v${currentVersion}.`));
|
|
92
|
-
} else {
|
|
93
|
-
console.log(chalk.gray(`Kept v${currentVersion}. You can switch back using 'aiflow use ${currentVersion}'.`));
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Switch to new version — copy skills without wiping the whole .claude dir
|
|
98
|
-
// (wiping would destroy settings.json which holds the hooks configuration)
|
|
99
|
-
const claudeDir = path.join(projectDir, '.claude');
|
|
100
|
-
const claudeSkillsDir = path.join(claudeDir, 'skills');
|
|
101
|
-
await fs.emptyDir(claudeSkillsDir);
|
|
102
|
-
await fs.copy(path.join(newVersionDir, 'skills'), claudeSkillsDir, { overwrite: true });
|
|
103
|
-
|
|
104
|
-
const rulesDir = path.join(projectDir, '.rules');
|
|
105
|
-
await fs.emptyDir(rulesDir);
|
|
106
|
-
await fs.copy(path.join(newVersionDir, 'rules'), rulesDir, { overwrite: true });
|
|
107
|
-
|
|
108
|
-
state.current_version = PKG_VERSION;
|
|
109
|
-
await fs.writeJson(stateFile, state);
|
|
110
|
-
|
|
111
|
-
// Sync instruction files with the updated skills.
|
|
112
|
-
// Support both old 'framework' (singular string) and new 'frameworks' (array).
|
|
113
|
-
const { setupFramework, AI_TOOL_FILES, ensureAiflowGitignored } = require('./init');
|
|
114
|
-
const frameworks = state.frameworks || (state.framework ? [state.framework] : []);
|
|
115
|
-
const selectedTools = state.aiTools || Object.keys(AI_TOOL_FILES);
|
|
116
|
-
for (const fw of frameworks) {
|
|
117
|
-
await setupFramework(projectDir, fw, frameworks.length > 1, selectedTools, { force: true });
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
await
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const { confirm, select } = require('@inquirer/prompts');
|
|
5
|
+
|
|
6
|
+
const PKG_DIR = path.join(__dirname, '..');
|
|
7
|
+
const PKG_VERSION = require('../package.json').version;
|
|
8
|
+
|
|
9
|
+
// Same language map as init.js
|
|
10
|
+
const FRAMEWORK_LANGUAGE = {
|
|
11
|
+
'laravel': 'php',
|
|
12
|
+
'spring-boot': 'java',
|
|
13
|
+
'reactjs': 'javascript',
|
|
14
|
+
'nextjs': 'javascript',
|
|
15
|
+
'vue-nuxt': 'javascript',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
module.exports = async function update(options = {}) {
|
|
19
|
+
const projectDir = process.cwd();
|
|
20
|
+
const aiflowDir = path.join(projectDir, '.aiflow');
|
|
21
|
+
const stateFile = path.join(aiflowDir, 'state.json');
|
|
22
|
+
|
|
23
|
+
if (!(await fs.pathExists(stateFile))) {
|
|
24
|
+
console.log(chalk.red('Project is not initialized. Please run `aiflow init` first.'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const state = await fs.readJson(stateFile);
|
|
29
|
+
const currentVersion = state.current_version;
|
|
30
|
+
|
|
31
|
+
if (currentVersion === PKG_VERSION && !options.force) {
|
|
32
|
+
console.log(chalk.cyan(`You are already on v${PKG_VERSION}. Syncing latest assets and instruction files...`));
|
|
33
|
+
} else {
|
|
34
|
+
console.log(chalk.blue(`Updating from v${currentVersion} to v${PKG_VERSION}...`));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const newVersionDir = path.join(aiflowDir, 'versions', PKG_VERSION);
|
|
38
|
+
await fs.ensureDir(newVersionDir);
|
|
39
|
+
|
|
40
|
+
// Merge skills
|
|
41
|
+
const upstreamSkills = path.join(PKG_DIR, 'upstream', 'skills');
|
|
42
|
+
const customSkills = path.join(PKG_DIR, 'custom', 'skills');
|
|
43
|
+
|
|
44
|
+
await fs.ensureDir(path.join(newVersionDir, 'skills'));
|
|
45
|
+
if (await fs.pathExists(upstreamSkills)) {
|
|
46
|
+
await fs.copy(upstreamSkills, path.join(newVersionDir, 'skills'), { overwrite: true });
|
|
47
|
+
}
|
|
48
|
+
if (await fs.pathExists(customSkills)) {
|
|
49
|
+
await fs.copy(customSkills, path.join(newVersionDir, 'skills'), { overwrite: true });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Copy rules: common first, then language-specific overlay (mirrors init.js logic)
|
|
53
|
+
const rulesTarget = path.join(newVersionDir, 'rules');
|
|
54
|
+
const commonRules = path.join(PKG_DIR, 'custom', 'rules', 'common');
|
|
55
|
+
const allRules = path.join(PKG_DIR, 'custom', 'rules');
|
|
56
|
+
const primaryFramework = (state.frameworks || (state.framework ? [state.framework] : []))[0] || null;
|
|
57
|
+
|
|
58
|
+
await fs.ensureDir(rulesTarget);
|
|
59
|
+
if (await fs.pathExists(commonRules)) {
|
|
60
|
+
await fs.copy(commonRules, rulesTarget, { overwrite: true });
|
|
61
|
+
} else if (await fs.pathExists(allRules)) {
|
|
62
|
+
const entries = await fs.readdir(allRules, { withFileTypes: true });
|
|
63
|
+
for (const entry of entries) {
|
|
64
|
+
if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
65
|
+
await fs.copy(path.join(allRules, entry.name), path.join(rulesTarget, entry.name), { overwrite: true });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (primaryFramework) {
|
|
71
|
+
const lang = FRAMEWORK_LANGUAGE[primaryFramework];
|
|
72
|
+
if (lang) {
|
|
73
|
+
const langRules = path.join(PKG_DIR, 'custom', 'rules', lang);
|
|
74
|
+
if (await fs.pathExists(langRules)) {
|
|
75
|
+
await fs.copy(langRules, rulesTarget, { overwrite: true });
|
|
76
|
+
console.log(chalk.gray(` ✓ Applied ${lang} rules`));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(chalk.green(`✓ Downloaded assets for v${PKG_VERSION} into the project.`));
|
|
82
|
+
|
|
83
|
+
// Only offer to delete old version when it's a different version.
|
|
84
|
+
// When --force re-copies the same version, old === new === newVersionDir,
|
|
85
|
+
// so deleting "old" would immediately break the copy step below.
|
|
86
|
+
const isSameVersion = currentVersion === PKG_VERSION;
|
|
87
|
+
if (!isSameVersion) {
|
|
88
|
+
const deleteOld = await confirm({ message: `Do you want to delete the old version (v${currentVersion})?` });
|
|
89
|
+
if (deleteOld) {
|
|
90
|
+
await fs.remove(path.join(aiflowDir, 'versions', currentVersion));
|
|
91
|
+
console.log(chalk.gray(`Deleted v${currentVersion}.`));
|
|
92
|
+
} else {
|
|
93
|
+
console.log(chalk.gray(`Kept v${currentVersion}. You can switch back using 'aiflow use ${currentVersion}'.`));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Switch to new version — copy skills without wiping the whole .claude dir
|
|
98
|
+
// (wiping would destroy settings.json which holds the hooks configuration)
|
|
99
|
+
const claudeDir = path.join(projectDir, '.claude');
|
|
100
|
+
const claudeSkillsDir = path.join(claudeDir, 'skills');
|
|
101
|
+
await fs.emptyDir(claudeSkillsDir);
|
|
102
|
+
await fs.copy(path.join(newVersionDir, 'skills'), claudeSkillsDir, { overwrite: true });
|
|
103
|
+
|
|
104
|
+
const rulesDir = path.join(projectDir, '.rules');
|
|
105
|
+
await fs.emptyDir(rulesDir);
|
|
106
|
+
await fs.copy(path.join(newVersionDir, 'rules'), rulesDir, { overwrite: true });
|
|
107
|
+
|
|
108
|
+
state.current_version = PKG_VERSION;
|
|
109
|
+
await fs.writeJson(stateFile, state);
|
|
110
|
+
|
|
111
|
+
// Sync instruction files with the updated skills.
|
|
112
|
+
// Support both old 'framework' (singular string) and new 'frameworks' (array).
|
|
113
|
+
const { setupFramework, AI_TOOL_FILES, ensureAiflowGitignored, setupClaudeCommands } = require('./init');
|
|
114
|
+
const frameworks = state.frameworks || (state.framework ? [state.framework] : []);
|
|
115
|
+
const selectedTools = state.aiTools || Object.keys(AI_TOOL_FILES);
|
|
116
|
+
for (const fw of frameworks) {
|
|
117
|
+
await setupFramework(projectDir, fw, frameworks.length > 1, selectedTools, { force: true });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Install / refresh Claude Code custom commands (.claude/commands/)
|
|
121
|
+
await setupClaudeCommands(projectDir);
|
|
122
|
+
|
|
123
|
+
// Ensure all aiflow files are gitignored (especially for projects upgrading from older versions)
|
|
124
|
+
await ensureAiflowGitignored(projectDir);
|
|
125
|
+
|
|
126
|
+
console.log(chalk.green(`\n✨ Update completed! Your project is now on v${PKG_VERSION}.`));
|
|
127
|
+
};
|
package/scripts/use.js
CHANGED
|
@@ -5,6 +5,20 @@ const chalk = require("chalk");
|
|
|
5
5
|
const https = require("https");
|
|
6
6
|
const { select, input } = require("@inquirer/prompts");
|
|
7
7
|
|
|
8
|
+
const stringWidth = require("string-width");
|
|
9
|
+
const CATEGORY_COLOR = {
|
|
10
|
+
Coding: chalk.cyan,
|
|
11
|
+
Testing: chalk.green,
|
|
12
|
+
Analysis: chalk.yellow,
|
|
13
|
+
Document: chalk.magenta,
|
|
14
|
+
BA: chalk.blue,
|
|
15
|
+
QA: chalk.greenBright,
|
|
16
|
+
};
|
|
17
|
+
const td = (label, cat, desc) => {
|
|
18
|
+
const pad = " ".repeat(Math.max(0, 20 - stringWidth(label)));
|
|
19
|
+
return label + pad + CATEGORY_COLOR[cat](cat.padEnd(10)) + chalk.dim(desc);
|
|
20
|
+
};
|
|
21
|
+
|
|
8
22
|
const PROJECT_DIR = process.cwd();
|
|
9
23
|
const AIFLOW_DIR = path.join(PROJECT_DIR, ".aiflow");
|
|
10
24
|
const STATE_FILE = path.join(AIFLOW_DIR, "state.json");
|
|
@@ -613,12 +627,16 @@ async function promptForTaskType(detectedDefault) {
|
|
|
613
627
|
return await select({
|
|
614
628
|
message: "Task type:",
|
|
615
629
|
choices: [
|
|
616
|
-
{ name: "🐛 Bug Fix",
|
|
617
|
-
{ name: "✨ Feature",
|
|
618
|
-
{ name: "
|
|
619
|
-
{ name: "
|
|
620
|
-
{ name: "
|
|
621
|
-
{ name: "
|
|
630
|
+
{ name: td("🐛 Bug Fix", "Coding", "Fix bugs, crashes, regressions"), value: "bug-fix" },
|
|
631
|
+
{ name: td("✨ Feature", "Coding", "Build new features, user stories"), value: "feature" },
|
|
632
|
+
{ name: td("🔄 Refactor", "Coding", "Improve code without behavior change"), value: "refactor" },
|
|
633
|
+
{ name: td("🔬 Testing", "Testing", "Write tests, QA, coverage"), value: "testing" },
|
|
634
|
+
{ name: td("▶️ Execute Test", "Testing", "Run existing TC scripts (4-gate flow)"), value: "execute" },
|
|
635
|
+
{ name: td("📋 Create Spec", "BA", "Create UC Spec from raw requirements (4-gate BA)"), value: "create-spec" },
|
|
636
|
+
{ name: td("✅ Create TestCase", "QA", "Create Test Cases from requirements (4-gate QA)"), value: "create-testcase" },
|
|
637
|
+
{ name: td("🔍 Investigation", "Analysis", "Investigate, analyze root cause"), value: "investigation" },
|
|
638
|
+
{ name: td("📊 Impact Analysis", "Analysis", "Assess scope and risk of changes"), value: "impact-analysis" },
|
|
639
|
+
{ name: td("📖 Documentation", "Document", "Write docs, README, API reference"), value: "documentation" },
|
|
622
640
|
],
|
|
623
641
|
default: detectedDefault || "feature",
|
|
624
642
|
});
|
|
@@ -683,12 +701,16 @@ async function manualContext(prefillId = "") {
|
|
|
683
701
|
const taskType = await select({
|
|
684
702
|
message: "Task type:",
|
|
685
703
|
choices: [
|
|
686
|
-
{ name: "🐛 Bug Fix", value: "bug-fix" },
|
|
687
|
-
{ name: "✨ Feature", value: "feature" },
|
|
688
|
-
{ name: "
|
|
689
|
-
{ name: "
|
|
690
|
-
{ name: "
|
|
691
|
-
{ name: "
|
|
704
|
+
{ name: td("🐛 Bug Fix", "Coding", "Fix bugs, crashes, regressions"), value: "bug-fix" },
|
|
705
|
+
{ name: td("✨ Feature", "Coding", "Build new features, user stories"), value: "feature" },
|
|
706
|
+
{ name: td("🔄 Refactor", "Coding", "Improve code without behavior change"), value: "refactor" },
|
|
707
|
+
{ name: td("🔬 Testing", "Testing", "Write tests, QA, coverage"), value: "testing" },
|
|
708
|
+
{ name: td("▶️ Execute Test", "Testing", "Run existing TC scripts (4-gate flow)"), value: "execute" },
|
|
709
|
+
{ name: td("📋 Create Spec", "BA", "Create UC Spec from raw requirements (4-gate BA)"), value: "create-spec" },
|
|
710
|
+
{ name: td("✅ Create TestCase", "QA", "Create Test Cases from requirements (4-gate QA)"), value: "create-testcase" },
|
|
711
|
+
{ name: td("🔍 Investigation", "Analysis", "Investigate, analyze root cause"), value: "investigation" },
|
|
712
|
+
{ name: td("📊 Impact Analysis", "Analysis", "Assess scope and risk of changes"), value: "impact-analysis" },
|
|
713
|
+
{ name: td("📖 Documentation", "Document", "Write docs, README, API reference"), value: "documentation" },
|
|
692
714
|
],
|
|
693
715
|
default: existing.taskType || undefined,
|
|
694
716
|
});
|
|
@@ -939,6 +961,8 @@ function detectTaskTypeFromString(text) {
|
|
|
939
961
|
return "feature";
|
|
940
962
|
if (["research", "investigation", "調査"].some((k) => lower.includes(k)))
|
|
941
963
|
return "investigation";
|
|
964
|
+
if (["test", "testing", "qa", "quality", "coverage", "テスト"].some((k) => lower.includes(k)))
|
|
965
|
+
return "testing";
|
|
942
966
|
return "bug-fix"; // default for unknown
|
|
943
967
|
}
|
|
944
968
|
|