thachvd-kit 1.0.18 → 1.0.20
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/.agent/docs/architecture.md +3 -2
- package/.agent/docs/conventions.md +1 -1
- package/.agent/docs/tooling.md +5 -8
- package/.agent/skills/project-onboarding/SKILL.md +1 -1
- package/.agent/skills/using-git-worktrees/SKILL.md +2 -3
- package/.agent/skills/writing-skills/SKILL.md +170 -110
- package/.agent/workflows/review.md +125 -0
- package/.agent/workflows/spec.md +140 -0
- package/README.md +45 -44
- package/bin/cli.js +347 -330
- package/kit/README.md +2 -1
- package/package.json +1 -1
- package/skills/code-review-checklist/SKILL.md +142 -109
- package/skills/project-onboarding/SKILL.md +1 -1
- package/skills/tdd-workflow/SKILL.md +25 -1
- package/skills/using-git-worktrees/SKILL.md +2 -3
- package/skills/verification-before-completion/SKILL.md +24 -10
- package/skills/writing-skills/SKILL.md +170 -110
package/bin/cli.js
CHANGED
|
@@ -136,12 +136,13 @@ ${pc.bold('Options:')}
|
|
|
136
136
|
--help Show this help message
|
|
137
137
|
|
|
138
138
|
${pc.bold('What gets generated:')}
|
|
139
|
-
AGENTS.md Shared instructions for Codex, Antigravity,
|
|
139
|
+
AGENTS.md Shared instructions for Codex, Antigravity, Claude Code, and Cursor
|
|
140
140
|
CLAUDE.md Claude Code entry file that imports AGENTS.md
|
|
141
141
|
GEMINI.md Antigravity entry file that points to AGENTS.md
|
|
142
|
+
.cursorrules Cursor entry file that points to AGENTS.md
|
|
142
143
|
.agent/ Shared docs, skills, workflows, agents, and rules
|
|
143
|
-
|
|
144
|
-
.claude/skills/
|
|
144
|
+
~/.codex/skills/ Selected Codex skills copied to global user dir (shows in $ menu)
|
|
145
|
+
.claude/skills/ Selected Claude Code project skills copied from .agent/skills
|
|
145
146
|
|
|
146
147
|
${pc.bold('Workflow guide:')}
|
|
147
148
|
Idea is fuzzy /brainstorm Explore options, tradeoffs, and recommended direction
|
|
@@ -885,248 +886,257 @@ function resolveAgentTable(data) {
|
|
|
885
886
|
rows.push(["Debug", "debugger", "systematic-debugging"]);
|
|
886
887
|
rows.push(["Security", "security-auditor", "vulnerability-scanner"]);
|
|
887
888
|
rows.push(["Planning", "project-planner", "brainstorming, plan-writing"]);
|
|
888
|
-
|
|
889
|
-
return rows;
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
// --- File Generators ---
|
|
893
|
-
|
|
894
|
-
function generateSharedAgentsMd(data) {
|
|
895
|
-
return `# AGENTS.md
|
|
896
|
-
|
|
897
|
-
Shared operating instructions for Codex, Antigravity, and Claude Code.
|
|
898
|
-
|
|
899
|
-
## Startup
|
|
900
|
-
|
|
901
|
-
1. Read this file first.
|
|
902
|
-
2. Read \`.agent/docs/project.md\` for detected stack, commands, and routing.
|
|
889
|
+
|
|
903
890
|
return rows;
|
|
891
|
+
}
|
|
892
|
+
// --- File Generators ---
|
|
893
|
+
|
|
894
|
+
function generateSharedAgentsMd(data) {
|
|
895
|
+
return `# AGENTS.md
|
|
896
|
+
|
|
897
|
+
Shared operating instructions for Codex, Antigravity, Claude Code, and Cursor.
|
|
898
|
+
|
|
899
|
+
## Startup
|
|
900
|
+
|
|
901
|
+
1. Read this file first.
|
|
902
|
+
2. Read \`.agent/docs/project.md\` for detected stack, commands, and routing.
|
|
904
903
|
3. Read \`.agent/docs/workflow.md\` for the task flow before editing.
|
|
905
904
|
4. Read \`.agent/docs/architecture.md\` and \`.agent/docs/conventions.md\` before planning code changes.
|
|
906
905
|
5. Read \`.agent/docs/tooling.md\` when the task needs Playwright, codegraph, MCP, or native Codex/Claude skill setup.
|
|
907
906
|
6. Select and load only the agent, skill, or workflow files that match the current task.
|
|
908
|
-
|
|
909
|
-
If any \`.agent/docs/*.md\` file still contains \`TODO: refine\`, update the docs by scanning the project before making product code changes.
|
|
910
|
-
|
|
911
|
-
## Task Flow
|
|
912
|
-
|
|
913
|
-
- Questions and analysis: answer directly, cite relevant files when useful, and do not edit code.
|
|
914
|
-
- Simple fix: inspect dependencies, make the smallest change, run focused verification.
|
|
915
|
-
- Feature or refactor: define success criteria, make a short plan, implement, then verify.
|
|
907
|
+
|
|
908
|
+
If any \`.agent/docs/*.md\` file still contains \`TODO: refine\`, update the docs by scanning the project before making product code changes.
|
|
909
|
+
|
|
910
|
+
## Task Flow
|
|
911
|
+
|
|
912
|
+
- Questions and analysis: answer directly, cite relevant files when useful, and do not edit code.
|
|
913
|
+
- Simple fix: inspect dependencies, make the smallest change, run focused verification.
|
|
914
|
+
- Feature or refactor: define success criteria, make a short plan, implement, then verify.
|
|
916
915
|
- Multi-domain work: use \`.agent/workflows/orchestrate.md\` and route to the relevant specialist docs.
|
|
917
916
|
- UI work: read \`.agent/agents/frontend-specialist.md\` and applicable design skills before editing.
|
|
918
917
|
|
|
919
918
|
## Skill Loading
|
|
920
919
|
|
|
921
920
|
- Treat \`.agent/skills/\` as the shared source of truth for all kit skills.
|
|
922
|
-
- Codex
|
|
923
|
-
-
|
|
921
|
+
- Codex exposes skills from \`~/.codex/skills/\` in the \`$\` menu; \`thachvd-kit\` copies selected skills there on init.
|
|
922
|
+
- Claude Code project skills live in \`.claude/skills/\`.
|
|
923
|
+
- If a skill is missing from the global dir, fall back to the matching \`.agent/skills/<skill>/SKILL.md\` file.
|
|
924
924
|
- Do not load skill bodies by default; load a skill only when the user mentions it, the task clearly matches its description, or \`.agent/docs/project.md\` routes the task to it.
|
|
925
925
|
- Prefer explicit skill mentions for predictable behavior: \`$clean-code\`, \`$systematic-debugging\`, \`$webapp-testing\`, or any skill listed in \`.agent/docs/project.md\`.
|
|
926
926
|
- Run \`thachvd-kit --help\` to see common workflow and skill recommendations.
|
|
927
927
|
- When creating or improving skills, use \`writing-skills\` first and make the \`description\` field specific enough for implicit invocation.
|
|
928
928
|
|
|
929
929
|
## Rules
|
|
930
|
-
|
|
931
|
-
- Respond in the user's language; keep code, identifiers, and code comments in English.
|
|
932
|
-
- State assumptions when the request is ambiguous.
|
|
933
|
-
- Prefer the existing project style over new abstractions.
|
|
934
|
-
- Keep changes surgical and remove only dead code introduced by your change.
|
|
935
|
-
- Tests or equivalent verification are mandatory before claiming done.
|
|
936
|
-
- Keep files under ${data.max_file_lines || '300'} lines unless the project already has a different standard in \`.agent/docs/conventions.md\`.
|
|
937
|
-
|
|
938
|
-
## Shared Knowledge
|
|
939
|
-
|
|
930
|
+
|
|
931
|
+
- Respond in the user's language; keep code, identifiers, and code comments in English.
|
|
932
|
+
- State assumptions when the request is ambiguous.
|
|
933
|
+
- Prefer the existing project style over new abstractions.
|
|
934
|
+
- Keep changes surgical and remove only dead code introduced by your change.
|
|
935
|
+
- Tests or equivalent verification are mandatory before claiming done.
|
|
936
|
+
- Keep files under ${data.max_file_lines || '300'} lines unless the project already has a different standard in \`.agent/docs/conventions.md\`.
|
|
937
|
+
|
|
938
|
+
## Shared Knowledge
|
|
939
|
+
|
|
940
940
|
- Project docs: \`.agent/docs/\`
|
|
941
941
|
- Specialist agents: \`.agent/agents/\`
|
|
942
942
|
- Skills: \`.agent/skills/\`
|
|
943
|
-
- Codex
|
|
943
|
+
- Codex global skills: \`~/.codex/skills/\` (installed by thachvd-kit init)
|
|
944
944
|
- Claude Code project skills: \`.claude/skills/\`
|
|
945
945
|
- Workflows: \`.agent/workflows/\`
|
|
946
946
|
- Tooling setup: \`.agent/docs/tooling.md\`
|
|
947
947
|
- Antigravity mirror rules: \`.agent/rules/GEMINI.md\`
|
|
948
|
+
- Cursor entry rules: \`.cursorrules\`
|
|
948
949
|
`;
|
|
949
950
|
}
|
|
950
|
-
|
|
951
|
-
function generateSharedClaudeMd() {
|
|
952
|
-
return `@AGENTS.md
|
|
953
|
-
|
|
954
|
-
## Claude Code
|
|
955
|
-
|
|
956
|
-
This repository uses AGENTS.md as the shared cross-agent entry file. Follow the imported instructions and keep Claude-specific notes here only when they cannot apply to Codex or Antigravity.
|
|
957
|
-
`;
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
function generateSharedGeminiMd() {
|
|
961
|
-
return `# GEMINI.md
|
|
962
|
-
|
|
963
|
-
Antigravity entry file for this project.
|
|
964
|
-
|
|
965
|
-
Read AGENTS.md first, then follow the shared docs under .agent/docs/.
|
|
966
|
-
`;
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
function
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
dev = '
|
|
1010
|
-
lint = '
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
-
|
|
1044
|
-
-
|
|
1045
|
-
-
|
|
1046
|
-
-
|
|
1047
|
-
|
|
1048
|
-
##
|
|
1049
|
-
|
|
1050
|
-
-
|
|
1051
|
-
-
|
|
1052
|
-
-
|
|
1053
|
-
-
|
|
1054
|
-
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
##
|
|
1102
|
-
|
|
1103
|
-
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
-
|
|
1113
|
-
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
951
|
+
|
|
952
|
+
function generateSharedClaudeMd() {
|
|
953
|
+
return `@AGENTS.md
|
|
954
|
+
|
|
955
|
+
## Claude Code
|
|
956
|
+
|
|
957
|
+
This repository uses AGENTS.md as the shared cross-agent entry file. Follow the imported instructions and keep Claude-specific notes here only when they cannot apply to Codex or Antigravity.
|
|
958
|
+
`;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
function generateSharedGeminiMd() {
|
|
962
|
+
return `# GEMINI.md
|
|
963
|
+
|
|
964
|
+
Antigravity entry file for this project.
|
|
965
|
+
|
|
966
|
+
Read AGENTS.md first, then follow the shared docs under .agent/docs/.
|
|
967
|
+
`;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
function generateSharedCursorrules() {
|
|
971
|
+
return `# Cursor Rules
|
|
972
|
+
|
|
973
|
+
This repository uses AGENTS.md as the shared cross-agent entry file. Follow the instructions in AGENTS.md and keep Cursor-specific notes here only when they cannot apply to Codex, Antigravity, or Claude Code.
|
|
974
|
+
|
|
975
|
+
Read AGENTS.md first, then follow the shared docs under .agent/docs/.
|
|
976
|
+
`;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
function resolveCommands(data) {
|
|
980
|
+
const frameworks = data.frameworks || [];
|
|
981
|
+
const primaryLang = data.primary_language || 'javascript';
|
|
982
|
+
const pkgManager = data.package_manager || 'npm';
|
|
983
|
+
const testFramework = data.test_framework || 'auto-detect';
|
|
984
|
+
|
|
985
|
+
const isPython = primaryLang === 'python';
|
|
986
|
+
const isGo = primaryLang === 'go';
|
|
987
|
+
const isRust = primaryLang === 'rust';
|
|
988
|
+
const isPhp = primaryLang === 'php';
|
|
989
|
+
|
|
990
|
+
let install = 'npm install';
|
|
991
|
+
let dev = 'npm run dev';
|
|
992
|
+
let build = 'npm run build';
|
|
993
|
+
let test = 'npm test';
|
|
994
|
+
let lint = 'npm run lint';
|
|
995
|
+
|
|
996
|
+
if (pkgManager === 'pnpm') { install = 'pnpm install'; dev = 'pnpm dev'; build = 'pnpm build'; test = 'pnpm test'; lint = 'pnpm lint'; }
|
|
997
|
+
else if (pkgManager === 'yarn') { install = 'yarn'; dev = 'yarn dev'; build = 'yarn build'; test = 'yarn test'; lint = 'yarn lint'; }
|
|
998
|
+
else if (pkgManager === 'bun') { install = 'bun install'; dev = 'bun dev'; build = 'bun run build'; test = 'bun test'; lint = 'bun run lint'; }
|
|
999
|
+
else if (isPython) { install = 'pip install -r requirements.txt'; dev = 'python manage.py runserver'; build = '# no build step'; test = 'pytest'; lint = 'ruff check .'; }
|
|
1000
|
+
else if (isGo) { install = 'go mod download'; dev = 'go run .'; build = 'go build ./...'; test = 'go test ./...'; lint = 'golangci-lint run'; }
|
|
1001
|
+
else if (isRust) { install = 'cargo build'; dev = 'cargo run'; build = 'cargo build --release'; test = 'cargo test'; lint = 'cargo clippy'; }
|
|
1002
|
+
else if (isPhp) {
|
|
1003
|
+
install = 'composer install';
|
|
1004
|
+
build = '# no build step';
|
|
1005
|
+
test = testFramework === 'pest' ? './vendor/bin/pest' : './vendor/bin/phpunit';
|
|
1006
|
+
const isCakePHP = frameworks.some(f => f.toLowerCase().includes('cakephp'));
|
|
1007
|
+
const isSymfony = frameworks.some(f => f.toLowerCase().includes('symfony'));
|
|
1008
|
+
const isCodeIgniter = frameworks.some(f => f.toLowerCase().includes('codeigniter'));
|
|
1009
|
+
if (isCakePHP) {
|
|
1010
|
+
dev = 'bin/cake server';
|
|
1011
|
+
lint = './vendor/bin/phpcs';
|
|
1012
|
+
} else if (isSymfony) {
|
|
1013
|
+
dev = 'bin/console server:run';
|
|
1014
|
+
lint = './vendor/bin/phpcs';
|
|
1015
|
+
} else if (isCodeIgniter) {
|
|
1016
|
+
dev = 'php spark serve';
|
|
1017
|
+
lint = './vendor/bin/phpcs';
|
|
1018
|
+
} else {
|
|
1019
|
+
dev = 'php artisan serve';
|
|
1020
|
+
lint = 'php artisan pint';
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
if (testFramework === 'vitest') test = `${pkgManager === 'pnpm' ? 'pnpm' : pkgManager === 'yarn' ? 'yarn' : pkgManager === 'bun' ? 'bun run' : 'npx'} vitest`;
|
|
1025
|
+
else if (testFramework === 'jest') test = `${pkgManager === 'pnpm' ? 'pnpm' : pkgManager === 'yarn' ? 'yarn' : 'npx'} jest`;
|
|
1026
|
+
|
|
1027
|
+
return { install, dev, build, test, lint };
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
function generateProjectDoc(data) {
|
|
1031
|
+
const commands = resolveCommands(data);
|
|
1032
|
+
const agentRows = resolveAgentTable(data).map(([task, agent, skills]) => `| ${task} | \`${agent}\` | ${skills} |`).join('\n');
|
|
1033
|
+
const skillsList = resolveSkills(data).map(s => `- ${s}`).join('\n');
|
|
1034
|
+
const evidence = (data.scan_evidence || []).length > 0
|
|
1035
|
+
? (data.scan_evidence || []).map(line => `- ${line}`).join('\n')
|
|
1036
|
+
: '- TODO: refine scan evidence by inspecting the project.';
|
|
1037
|
+
|
|
1038
|
+
return `# Project Rules
|
|
1039
|
+
|
|
1040
|
+
Generated by thachvd-kit on ${new Date().toISOString().split('T')[0]}.
|
|
1041
|
+
|
|
1042
|
+
## Summary
|
|
1043
|
+
|
|
1044
|
+
- Name: ${data.project_name}
|
|
1045
|
+
- Description: ${data.description}
|
|
1046
|
+
- Type: ${data.project_type}
|
|
1047
|
+
- App root: ${data.app_root || '.'}
|
|
1048
|
+
|
|
1049
|
+
## Stack
|
|
1050
|
+
|
|
1051
|
+
- Language: ${data.primary_language}
|
|
1052
|
+
- Frameworks: ${(data.frameworks || []).join(', ') || 'none'}
|
|
1053
|
+
- Database: ${data.database || 'none'}
|
|
1054
|
+
- Infrastructure: ${(data.infrastructure || []).join(', ') || 'none'}
|
|
1055
|
+
- Package manager: ${data.package_manager || 'auto-detect'}
|
|
1056
|
+
- Test framework: ${data.test_framework || 'auto-detect'}
|
|
1057
|
+
|
|
1058
|
+
## Commands
|
|
1059
|
+
|
|
1060
|
+
- Install: \`${commands.install}\`
|
|
1061
|
+
- Dev: \`${commands.dev}\`
|
|
1062
|
+
- Build: \`${commands.build}\`
|
|
1063
|
+
- Test: \`${commands.test}\`
|
|
1064
|
+
- Lint: \`${commands.lint}\`
|
|
1065
|
+
|
|
1066
|
+
## Agent Routing
|
|
1067
|
+
|
|
1068
|
+
| Task Type | Agent | Primary Skills |
|
|
1069
|
+
|-----------|-------|----------------|
|
|
1070
|
+
${agentRows}
|
|
1071
|
+
|
|
1072
|
+
## Auto-Resolved Skills
|
|
1073
|
+
|
|
1074
|
+
${skillsList}
|
|
1075
|
+
|
|
1076
|
+
## Scan Evidence
|
|
1077
|
+
|
|
1078
|
+
${evidence}
|
|
1079
|
+
`;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
function generateArchitectureDoc(data) {
|
|
1083
|
+
const appRootLine = data.app_root && data.app_root !== '.'
|
|
1084
|
+
? `- App root is currently detected as \`${data.app_root}\`.`
|
|
1085
|
+
: '- App root is the repository root unless refined below.';
|
|
1086
|
+
const evidence = (data.scan_evidence || []).length > 0
|
|
1087
|
+
? (data.scan_evidence || []).map(line => `- ${line}`).join('\n')
|
|
1088
|
+
: '- TODO: refine architecture by scanning source directories.';
|
|
1089
|
+
|
|
1090
|
+
return `# Architecture Notes
|
|
1091
|
+
|
|
1092
|
+
## Current Map
|
|
1093
|
+
|
|
1094
|
+
${appRootLine}
|
|
1095
|
+
- TODO: refine major directories and responsibilities.
|
|
1096
|
+
- TODO: refine main entry points, routing, state boundaries, and integration boundaries.
|
|
1097
|
+
|
|
1098
|
+
## Detected Evidence
|
|
1099
|
+
|
|
1100
|
+
${evidence}
|
|
1101
|
+
|
|
1102
|
+
## AI Maintenance Rule
|
|
1103
|
+
|
|
1104
|
+
Before non-trivial implementation work, inspect this file. If it is stale or still contains TODO items relevant to the task, update it from the code before editing product code.
|
|
1105
|
+
`;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
function generateConventionsDoc(data) {
|
|
1109
|
+
return `# Coding Conventions
|
|
1110
|
+
|
|
1111
|
+
## Current Standards
|
|
1112
|
+
|
|
1113
|
+
- Maximum file length: ${data.max_file_lines || '300'} lines unless the existing project standard is stricter.
|
|
1114
|
+
- Code comments and identifiers should be written in English.
|
|
1115
|
+
- Keep changes scoped to the user request.
|
|
1116
|
+
- Prefer existing local patterns over introducing new abstractions.
|
|
1117
|
+
- TODO: refine naming, formatting, folder, API, state, styling, and testing conventions from the real codebase.
|
|
1118
|
+
|
|
1119
|
+
## Verification
|
|
1120
|
+
|
|
1121
|
+
- Run the focused test or lint command that matches the touched area.
|
|
1122
|
+
- If no automated check exists, document the manual verification performed.
|
|
1123
|
+
- Do not claim completion without verification evidence.
|
|
1124
|
+
`;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1117
1127
|
function generateWorkflowDoc() {
|
|
1118
|
-
return `# Agent Workflow
|
|
1119
|
-
|
|
1120
|
-
## Before Every Task
|
|
1121
|
-
|
|
1128
|
+
return `# Agent Workflow
|
|
1129
|
+
|
|
1130
|
+
## Before Every Task
|
|
1131
|
+
|
|
1122
1132
|
1. Read AGENTS.md.
|
|
1123
1133
|
2. Read .agent/docs/project.md.
|
|
1124
1134
|
3. Classify the request: question, survey, simple fix, feature, refactor, debug, UI, security, or deploy.
|
|
1125
|
-
4. Read only the relevant docs under .agent/agents, .agent/skills, .
|
|
1135
|
+
4. Read only the relevant docs under .agent/agents, .agent/skills, .claude/skills, and .agent/workflows.
|
|
1126
1136
|
|
|
1127
1137
|
## Skill Selection
|
|
1128
1138
|
|
|
1129
1139
|
- Prefer native skill discovery when the client exposes it.
|
|
1130
|
-
- Codex
|
|
1140
|
+
- Codex global skills live in ~/.codex/skills/ and are visible via the $ menu; thachvd-kit copies selected skills there on init.
|
|
1131
1141
|
- Claude Code project skills live in .claude/skills.
|
|
1132
1142
|
- Shared fallback skills live in .agent/skills.
|
|
1133
1143
|
- Do not load skill bodies by default.
|
|
@@ -1135,20 +1145,20 @@ function generateWorkflowDoc() {
|
|
|
1135
1145
|
- Run thachvd-kit --help to see common workflow and skill recommendations.
|
|
1136
1146
|
|
|
1137
1147
|
## Implementation Flow
|
|
1138
|
-
|
|
1139
|
-
1. State assumptions and success criteria when the task is not trivial.
|
|
1140
|
-
2. Inspect dependent files before editing.
|
|
1141
|
-
3. Make the smallest coherent change.
|
|
1142
|
-
4. Add or update focused tests when behavior changes.
|
|
1143
|
-
5. Run verification.
|
|
1144
|
-
6. Summarize changed files and verification evidence.
|
|
1145
|
-
|
|
1146
|
-
## When To Update Docs
|
|
1147
|
-
|
|
1148
|
-
- Update .agent/docs/architecture.md when structure, boundaries, or entry points change.
|
|
1149
|
-
- Update .agent/docs/conventions.md when repeated project patterns become clear.
|
|
1150
|
-
- Update .agent/docs/project.md when stack, scripts, app root, test tooling, or routing changes.
|
|
1151
|
-
- Keep AGENTS.md concise. Put project-specific detail in .agent/docs.
|
|
1148
|
+
|
|
1149
|
+
1. State assumptions and success criteria when the task is not trivial.
|
|
1150
|
+
2. Inspect dependent files before editing.
|
|
1151
|
+
3. Make the smallest coherent change.
|
|
1152
|
+
4. Add or update focused tests when behavior changes.
|
|
1153
|
+
5. Run verification.
|
|
1154
|
+
6. Summarize changed files and verification evidence.
|
|
1155
|
+
|
|
1156
|
+
## When To Update Docs
|
|
1157
|
+
|
|
1158
|
+
- Update .agent/docs/architecture.md when structure, boundaries, or entry points change.
|
|
1159
|
+
- Update .agent/docs/conventions.md when repeated project patterns become clear.
|
|
1160
|
+
- Update .agent/docs/project.md when stack, scripts, app root, test tooling, or routing changes.
|
|
1161
|
+
- Keep AGENTS.md concise. Put project-specific detail in .agent/docs.
|
|
1152
1162
|
`;
|
|
1153
1163
|
}
|
|
1154
1164
|
|
|
@@ -1281,14 +1291,13 @@ Common local path:
|
|
|
1281
1291
|
|
|
1282
1292
|
## Native Skill Folders
|
|
1283
1293
|
|
|
1284
|
-
The shared kit skills live in \`.agent/skills/\`. Antigravity
|
|
1294
|
+
The shared kit skills live in \`.agent/skills/\`. Antigravity reads that folder directly. Codex shows skills from \`~/.codex/skills/\` in the \`$\` menu. Claude Code reads project skills from \`.claude/skills/\`.
|
|
1285
1295
|
|
|
1286
|
-
- Codex
|
|
1287
|
-
-
|
|
1288
|
-
-
|
|
1289
|
-
- Claude Code project skills commonly live under \`.claude/skills/\`.
|
|
1290
|
-
- \`thachvd-kit\` copies selected native skills to \`.agents/skills/\` and \`.claude/skills/\` based on the detected stack.
|
|
1296
|
+
- Codex global skills: \`~/.codex/skills/\` — installed by \`thachvd-kit init\`, visible in Codex \`$\` menu
|
|
1297
|
+
- Claude Code project skills: \`.claude/skills/\`
|
|
1298
|
+
- Antigravity: reads \`.agent/skills/\` directly (no copy needed)
|
|
1291
1299
|
- Keep \`.agent/skills/\` as the full shared source of truth committed with the repo.
|
|
1300
|
+
- Do not commit \`~/.codex/skills/\`; it is local user state.
|
|
1292
1301
|
|
|
1293
1302
|
Recommended candidates to copy first:
|
|
1294
1303
|
|
|
@@ -1298,39 +1307,39 @@ Recommended candidates to copy first:
|
|
|
1298
1307
|
- Stack-specific skills listed in \`.agent/docs/project.md\`
|
|
1299
1308
|
`;
|
|
1300
1309
|
}
|
|
1301
|
-
|
|
1302
|
-
// --- Agent Folder Copy ---
|
|
1303
|
-
|
|
1310
|
+
|
|
1311
|
+
// --- Agent Folder Copy ---
|
|
1312
|
+
|
|
1304
1313
|
function copyAgentFolder() {
|
|
1305
|
-
const srcAgent = path.join(sourceDir, '.agent');
|
|
1306
|
-
if (!fs.existsSync(srcAgent)) return { copied: 0, skipped: 0 };
|
|
1307
|
-
|
|
1308
|
-
const destAgent = path.join(targetDir, '.agent');
|
|
1309
|
-
let copied = 0;
|
|
1310
|
-
let skipped = 0;
|
|
1311
|
-
|
|
1312
|
-
function copyDir(src, dest) {
|
|
1313
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
1314
|
-
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
1315
|
-
const srcPath = path.join(src, entry.name);
|
|
1316
|
-
const destPath = path.join(dest, entry.name);
|
|
1317
|
-
const relativeSrc = path.relative(srcAgent, srcPath).split(path.sep).join('/');
|
|
1318
|
-
if (relativeSrc === 'docs' || relativeSrc.startsWith('docs/')) {
|
|
1319
|
-
continue;
|
|
1320
|
-
}
|
|
1321
|
-
if (entry.isDirectory()) {
|
|
1322
|
-
copyDir(srcPath, destPath);
|
|
1323
|
-
} else {
|
|
1324
|
-
if (fs.existsSync(destPath)) {
|
|
1325
|
-
skipped++;
|
|
1326
|
-
} else {
|
|
1327
|
-
fs.copyFileSync(srcPath, destPath);
|
|
1328
|
-
copied++;
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1314
|
+
const srcAgent = path.join(sourceDir, '.agent');
|
|
1315
|
+
if (!fs.existsSync(srcAgent)) return { copied: 0, skipped: 0 };
|
|
1316
|
+
|
|
1317
|
+
const destAgent = path.join(targetDir, '.agent');
|
|
1318
|
+
let copied = 0;
|
|
1319
|
+
let skipped = 0;
|
|
1320
|
+
|
|
1321
|
+
function copyDir(src, dest) {
|
|
1322
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
1323
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
1324
|
+
const srcPath = path.join(src, entry.name);
|
|
1325
|
+
const destPath = path.join(dest, entry.name);
|
|
1326
|
+
const relativeSrc = path.relative(srcAgent, srcPath).split(path.sep).join('/');
|
|
1327
|
+
if (relativeSrc === 'docs' || relativeSrc.startsWith('docs/')) {
|
|
1328
|
+
continue;
|
|
1329
|
+
}
|
|
1330
|
+
if (entry.isDirectory()) {
|
|
1331
|
+
copyDir(srcPath, destPath);
|
|
1332
|
+
} else {
|
|
1333
|
+
if (fs.existsSync(destPath)) {
|
|
1334
|
+
skipped++;
|
|
1335
|
+
} else {
|
|
1336
|
+
fs.copyFileSync(srcPath, destPath);
|
|
1337
|
+
copied++;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1334
1343
|
copyDir(srcAgent, destAgent);
|
|
1335
1344
|
return { copied, skipped };
|
|
1336
1345
|
}
|
|
@@ -1340,10 +1349,15 @@ function copySelectedSkillFolders(data, assumeYes) {
|
|
|
1340
1349
|
if (!fs.existsSync(srcSkills)) return { copied: 0, skipped: 0, missing: 0, skills: [] };
|
|
1341
1350
|
|
|
1342
1351
|
const selectedSkills = resolveNativeSkills(data);
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1352
|
+
|
|
1353
|
+
// ~/.codex/skills/ — global Codex user skills dir, always visible in the $ menu
|
|
1354
|
+
const codexSkillsDir = homePath('.codex', 'skills');
|
|
1355
|
+
// .claude/skills/ — project-level Claude Code skills
|
|
1356
|
+
const claudeSkillsDir = path.join(targetDir, '.claude', 'skills');
|
|
1357
|
+
|
|
1358
|
+
const destinations = [claudeSkillsDir];
|
|
1359
|
+
if (codexSkillsDir) destinations.push(codexSkillsDir);
|
|
1360
|
+
|
|
1347
1361
|
let copied = 0;
|
|
1348
1362
|
let skipped = 0;
|
|
1349
1363
|
let missing = 0;
|
|
@@ -1516,28 +1530,28 @@ function setupMcpServers() {
|
|
|
1516
1530
|
}
|
|
1517
1531
|
|
|
1518
1532
|
// --- Main CLI ---
|
|
1519
|
-
|
|
1533
|
+
|
|
1520
1534
|
async function main() {
|
|
1521
|
-
const rawArgs = process.argv.slice(2);
|
|
1522
|
-
const command = rawArgs[0] && !rawArgs[0].startsWith('-') ? rawArgs[0] : 'init';
|
|
1523
|
-
const args = command === 'init' ? rawArgs.slice(rawArgs[0] === 'init' ? 1 : 0) : rawArgs.slice(1);
|
|
1524
|
-
|
|
1525
|
-
if (rawArgs.includes('--version') || rawArgs.includes('-v')) {
|
|
1526
|
-
console.log(packageJson.version);
|
|
1527
|
-
return;
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
|
-
if (rawArgs.includes('--help') || rawArgs.includes('-h')) {
|
|
1531
|
-
printHelp();
|
|
1532
|
-
return;
|
|
1533
|
-
}
|
|
1534
|
-
|
|
1535
|
-
if (command !== 'init') {
|
|
1536
|
-
console.error(pc.red(`Unknown command: ${command}`));
|
|
1537
|
-
printHelp();
|
|
1538
|
-
process.exit(1);
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1535
|
+
const rawArgs = process.argv.slice(2);
|
|
1536
|
+
const command = rawArgs[0] && !rawArgs[0].startsWith('-') ? rawArgs[0] : 'init';
|
|
1537
|
+
const args = command === 'init' ? rawArgs.slice(rawArgs[0] === 'init' ? 1 : 0) : rawArgs.slice(1);
|
|
1538
|
+
|
|
1539
|
+
if (rawArgs.includes('--version') || rawArgs.includes('-v')) {
|
|
1540
|
+
console.log(packageJson.version);
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
if (rawArgs.includes('--help') || rawArgs.includes('-h')) {
|
|
1545
|
+
printHelp();
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
if (command !== 'init') {
|
|
1550
|
+
console.error(pc.red(`Unknown command: ${command}`));
|
|
1551
|
+
printHelp();
|
|
1552
|
+
process.exit(1);
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1541
1555
|
const assumeYes = args.includes('--yes') || args.includes('-y');
|
|
1542
1556
|
const skipMcpSetup = args.includes('--no-setup-mcp') || process.env.THACHVD_KIT_SKIP_MCP_SETUP === '1';
|
|
1543
1557
|
|
|
@@ -1574,17 +1588,17 @@ async function main() {
|
|
|
1574
1588
|
test_framework: scanned?.test_framework || 'auto-detect',
|
|
1575
1589
|
max_file_lines: scanned?.max_file_lines || '300'
|
|
1576
1590
|
};
|
|
1577
|
-
|
|
1578
|
-
data.database = data.database || scanned?.database || 'none';
|
|
1579
|
-
data.uses_docker = typeof data.uses_docker === 'boolean' ? data.uses_docker : (scanned?.uses_docker ?? true);
|
|
1580
|
-
data.cloud = data.cloud || scanned?.cloud || 'none';
|
|
1581
|
-
data.package_manager = data.package_manager || scanned?.package_manager || 'auto-detect';
|
|
1582
|
-
data.test_framework = data.test_framework || scanned?.test_framework || 'auto-detect';
|
|
1583
|
-
data.max_file_lines = data.max_file_lines || scanned?.max_file_lines || '300';
|
|
1584
|
-
data.framework_details = scanned?.framework_details || [];
|
|
1585
|
-
data.scan_evidence = scanned?.scan_evidence || [];
|
|
1586
|
-
data.app_root = scanned?.app_root || '.';
|
|
1587
|
-
|
|
1591
|
+
|
|
1592
|
+
data.database = data.database || scanned?.database || 'none';
|
|
1593
|
+
data.uses_docker = typeof data.uses_docker === 'boolean' ? data.uses_docker : (scanned?.uses_docker ?? true);
|
|
1594
|
+
data.cloud = data.cloud || scanned?.cloud || 'none';
|
|
1595
|
+
data.package_manager = data.package_manager || scanned?.package_manager || 'auto-detect';
|
|
1596
|
+
data.test_framework = data.test_framework || scanned?.test_framework || 'auto-detect';
|
|
1597
|
+
data.max_file_lines = data.max_file_lines || scanned?.max_file_lines || '300';
|
|
1598
|
+
data.framework_details = scanned?.framework_details || [];
|
|
1599
|
+
data.scan_evidence = scanned?.scan_evidence || [];
|
|
1600
|
+
data.app_root = scanned?.app_root || '.';
|
|
1601
|
+
|
|
1588
1602
|
data.infrastructure = [];
|
|
1589
1603
|
if (data.uses_docker) data.infrastructure.push('docker');
|
|
1590
1604
|
if (data.cloud !== 'none') data.infrastructure.push(data.cloud);
|
|
@@ -1592,36 +1606,37 @@ async function main() {
|
|
|
1592
1606
|
const shouldSetupMcp = !skipMcpSetup;
|
|
1593
1607
|
|
|
1594
1608
|
console.log(`\n${pc.bold(pc.cyan('Generating Files'))}`);
|
|
1595
|
-
|
|
1596
|
-
// Shared entry files are written after the .agent folder is available.
|
|
1597
|
-
|
|
1598
|
-
// Copy .agent folder
|
|
1599
|
-
const { copied, skipped } = copyAgentFolder();
|
|
1600
|
-
if (copied > 0) {
|
|
1601
|
-
console.log(` ${pc.green('OK')} Copied ${pc.bold('.agent/')} (${copied} file${copied !== 1 ? 's' : ''} added${skipped > 0 ? `, ${skipped} skipped` : ''})`);
|
|
1609
|
+
|
|
1610
|
+
// Shared entry files are written after the .agent folder is available.
|
|
1611
|
+
|
|
1612
|
+
// Copy .agent folder
|
|
1613
|
+
const { copied, skipped } = copyAgentFolder();
|
|
1614
|
+
if (copied > 0) {
|
|
1615
|
+
console.log(` ${pc.green('OK')} Copied ${pc.bold('.agent/')} (${copied} file${copied !== 1 ? 's' : ''} added${skipped > 0 ? `, ${skipped} skipped` : ''})`);
|
|
1602
1616
|
} else if (skipped > 0) {
|
|
1603
1617
|
console.log(` ${pc.yellow('~')} ${pc.bold('.agent/')} already exists - ${skipped} file${skipped !== 1 ? 's' : ''} skipped (no overwrite)`);
|
|
1604
1618
|
}
|
|
1605
1619
|
|
|
1606
1620
|
const nativeSkills = copySelectedSkillFolders(data, assumeYes);
|
|
1607
1621
|
if (nativeSkills.copied > 0) {
|
|
1608
|
-
console.log(` ${pc.green('OK')} Copied native skills to ${pc.bold('
|
|
1622
|
+
console.log(` ${pc.green('OK')} Copied native skills to ${pc.bold('~/.codex/skills/')} and ${pc.bold('.claude/skills/')} (${nativeSkills.skills.join(', ')})`);
|
|
1609
1623
|
} else if (nativeSkills.skipped > 0) {
|
|
1610
1624
|
console.log(` ${pc.yellow('~')} Native skills already exist - ${nativeSkills.skipped} file${nativeSkills.skipped !== 1 ? 's' : ''} skipped`);
|
|
1611
1625
|
}
|
|
1612
1626
|
|
|
1613
1627
|
|
|
1614
1628
|
const generatedFiles = [
|
|
1615
|
-
['AGENTS.md', generateSharedAgentsMd(data)],
|
|
1616
|
-
['CLAUDE.md', generateSharedClaudeMd()],
|
|
1617
|
-
['GEMINI.md', generateSharedGeminiMd()],
|
|
1618
|
-
[
|
|
1629
|
+
['AGENTS.md', generateSharedAgentsMd(data)],
|
|
1630
|
+
['CLAUDE.md', generateSharedClaudeMd()],
|
|
1631
|
+
['GEMINI.md', generateSharedGeminiMd()],
|
|
1632
|
+
['.cursorrules', generateSharedCursorrules()],
|
|
1633
|
+
[path.join('.agent', 'docs', 'project.md'), generateProjectDoc(data)],
|
|
1619
1634
|
[path.join('.agent', 'docs', 'architecture.md'), generateArchitectureDoc(data)],
|
|
1620
1635
|
[path.join('.agent', 'docs', 'conventions.md'), generateConventionsDoc(data)],
|
|
1621
1636
|
[path.join('.agent', 'docs', 'workflow.md'), generateWorkflowDoc()],
|
|
1622
1637
|
[path.join('.agent', 'docs', 'tooling.md'), generateToolingDoc(data)]
|
|
1623
1638
|
];
|
|
1624
|
-
|
|
1639
|
+
|
|
1625
1640
|
for (const [relativePath, content] of generatedFiles) {
|
|
1626
1641
|
const wrote = await writeGeneratedFile(relativePath, content, assumeYes);
|
|
1627
1642
|
if (wrote) console.log(` ${pc.green('OK')} Generated ${pc.bold(relativePath)}`);
|
|
@@ -1637,17 +1652,18 @@ async function main() {
|
|
|
1637
1652
|
}
|
|
1638
1653
|
|
|
1639
1654
|
console.log(`\n${pc.bold(pc.green('Done!'))}
|
|
1640
|
-
|
|
1641
|
-
${pc.bold('Project:')} ${data.project_name}
|
|
1642
|
-
${pc.bold('Stack:')} ${data.primary_language} | ${(data.frameworks || []).join(', ') || 'no framework'}
|
|
1643
|
-
|
|
1644
|
-
${pc.bold('Generated:')}
|
|
1645
|
-
- ${pc.bold('AGENTS.md')} shared entry for Codex, Antigravity,
|
|
1646
|
-
- ${pc.bold('CLAUDE.md')} Claude Code entry that imports AGENTS.md
|
|
1655
|
+
|
|
1656
|
+
${pc.bold('Project:')} ${data.project_name}
|
|
1657
|
+
${pc.bold('Stack:')} ${data.primary_language} | ${(data.frameworks || []).join(', ') || 'no framework'}
|
|
1658
|
+
|
|
1659
|
+
${pc.bold('Generated:')}
|
|
1660
|
+
- ${pc.bold('AGENTS.md')} shared entry for Codex, Antigravity, Claude Code, and Cursor
|
|
1661
|
+
- ${pc.bold('CLAUDE.md')} Claude Code entry that imports AGENTS.md
|
|
1647
1662
|
- ${pc.bold('GEMINI.md')} Antigravity entry
|
|
1663
|
+
- ${pc.bold('.cursorrules')} Cursor entry
|
|
1648
1664
|
- ${pc.bold('.agent/docs/')} scan-based project rules
|
|
1649
1665
|
- ${pc.bold('.agent/')} skills, workflows, agents, and rules
|
|
1650
|
-
- ${pc.bold('
|
|
1666
|
+
- ${pc.bold('~/.codex/skills/')} selected Codex skills installed globally (visible in $ menu)
|
|
1651
1667
|
- ${pc.bold('.claude/skills/')} selected Claude Code native skills
|
|
1652
1668
|
|
|
1653
1669
|
${pc.bold('MCP/tooling setup:')}
|
|
@@ -1659,22 +1675,23 @@ async function main() {
|
|
|
1659
1675
|
|
|
1660
1676
|
${pc.bold('Next steps:')}
|
|
1661
1677
|
1. Copy the prompt below into your AI editor and describe what the project does
|
|
1662
|
-
2. Commit ${pc.bold('AGENTS.md')}, ${pc.bold('CLAUDE.md')}, ${pc.bold('GEMINI.md')}, and ${pc.bold('.agent/')}
|
|
1663
|
-
3. Open the project in Codex, Antigravity,
|
|
1678
|
+
2. Commit ${pc.bold('AGENTS.md')}, ${pc.bold('CLAUDE.md')}, ${pc.bold('GEMINI.md')}, ${pc.bold('.cursorrules')}, and ${pc.bold('.agent/')}
|
|
1679
|
+
3. Open the project in Codex, Antigravity, Claude Code, or Cursor
|
|
1664
1680
|
|
|
1665
1681
|
${pc.bold('Copy this prompt into your AI editor:')}
|
|
1666
1682
|
${pc.dim('---')}
|
|
1667
1683
|
Read AGENTS.md and all files under .agent/docs/.
|
|
1668
1684
|
Ask me what this project does and any important conventions I want preserved.
|
|
1669
1685
|
Then scan this repository.
|
|
1670
|
-
Update AGENTS.md and .agent/docs/project.md, .agent/docs/architecture.md, .agent/docs/conventions.md, .agent/docs/workflow.md, and .agent/docs/tooling.md with factual project-specific rules.
|
|
1686
|
+
Update AGENTS.md, .cursorrules and .agent/docs/project.md, .agent/docs/architecture.md, .agent/docs/conventions.md, .agent/docs/workflow.md, and .agent/docs/tooling.md with factual project-specific rules.
|
|
1671
1687
|
Do not implement product code.
|
|
1672
1688
|
Remove TODO: refine only when backed by evidence from the codebase.
|
|
1673
1689
|
${pc.dim('---')}
|
|
1674
|
-
`);
|
|
1675
|
-
}
|
|
1690
|
+
`);
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
main().catch(err => {
|
|
1694
|
+
console.error(pc.red('\nError during init:'), err);
|
|
1695
|
+
process.exit(1);
|
|
1696
|
+
});
|
|
1676
1697
|
|
|
1677
|
-
main().catch(err => {
|
|
1678
|
-
console.error(pc.red('\nError during init:'), err);
|
|
1679
|
-
process.exit(1);
|
|
1680
|
-
});
|