thachvd-kit 1.0.5 → 1.0.7

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 CHANGED
@@ -18,6 +18,7 @@ npx github:thachvd/thachvd-kit init
18
18
  The interactive wizard will first ask whether this is a new project or an existing one.
19
19
  If it is an existing project, it can scan the current codebase to prefill `PROJECT_CONTEXT.md`, or let you enter everything manually.
20
20
  The scan mode uses evidence-based detectors and shows why a framework was inferred, so you can quickly confirm or correct it.
21
+ After init, you can also generate an AI refinement prompt to let your editor/agent deepen the project context.
21
22
 
22
23
  ```bash
23
24
  thachvd-kit init --scan
package/bin/cli.js CHANGED
@@ -842,9 +842,73 @@ Stack: ${data.primary_language} | ${(data.frameworks || []).join(', ')}
842
842
  - \`/test\` — Run test suite
843
843
  - \`/deploy\` — Deploy checklist
844
844
 
845
- See PROJECT_CONTEXT.md for full agent routing table.
846
- `;
847
- }
845
+ See PROJECT_CONTEXT.md for full agent routing table.
846
+ `;
847
+ }
848
+
849
+ function generateAiContextRefinementPrompt(data) {
850
+ const evidence = (data.scan_evidence || []).length > 0
851
+ ? (data.scan_evidence || []).map(line => `- ${line}`).join('\n')
852
+ : '- No scan evidence was captured during init.';
853
+
854
+ return `# AI Context Refinement
855
+
856
+ Use this prompt in your AI editor after \`thachvd-kit init\`.
857
+
858
+ ## Goal
859
+
860
+ Refine \`PROJECT_CONTEXT.md\` so it reflects the real project more accurately than the baseline init scan.
861
+
862
+ ## Current Baseline
863
+
864
+ - Project: ${data.project_name}
865
+ - Type: ${data.project_type}
866
+ - Stack: ${data.primary_language} | ${(data.frameworks || []).join(', ') || 'no framework'}
867
+ - Database: ${data.database || 'none'}
868
+ - Infra: ${(data.infrastructure || []).join(', ') || 'none'}
869
+
870
+ ## Scan Evidence
871
+
872
+ ${evidence}
873
+
874
+ ## Instructions For The AI Agent
875
+
876
+ 1. Read \`PROJECT_CONTEXT.md\` first.
877
+ 2. Inspect the project selectively to improve factual accuracy.
878
+ 3. Prioritize:
879
+ - real database/config detection
880
+ - domain/capability inference
881
+ - architecture notes
882
+ - more accurate auto-resolved skills
883
+ - important project-specific constraints
884
+ 4. Update \`PROJECT_CONTEXT.md\` directly.
885
+ 5. Distinguish facts from inferences when uncertain.
886
+ 6. Do not implement product code in this pass. Only refine project context.
887
+
888
+ ## Suggested Files To Inspect
889
+
890
+ - Root manifests: \`package.json\`, \`composer.json\`, \`Cargo.toml\`, \`pyproject.toml\`
891
+ - Infrastructure/config: Docker, CI, env, framework config files
892
+ - Database config and models
893
+ - Main app entry points, routing, controllers/services
894
+ - README and existing documentation
895
+
896
+ ## Desired Improvements
897
+
898
+ - Correct the \`database\` field if config files reveal the real DB.
899
+ - Add architecture notes that explain the actual structure.
900
+ - Infer domain capabilities such as scraping, browser automation, external API integrations, queues, workers, etc.
901
+ - Expand auto-resolved skills when there is clear evidence in the codebase.
902
+ - Add caveats or assumptions if parts of the stack are still uncertain.
903
+
904
+ ## Completion Standard
905
+
906
+ When done, summarize:
907
+ - what was corrected
908
+ - what is still inferred
909
+ - which files provided the strongest evidence
910
+ `;
911
+ }
848
912
 
849
913
  // --- Main CLI ---
850
914
 
@@ -924,6 +988,8 @@ async function main() {
924
988
  }
925
989
 
926
990
  const scanned = useScan ? scanProject() : null;
991
+ let reviewScannedFields = !useScan;
992
+ let requestAiRefinement = false;
927
993
 
928
994
  if (useScan) {
929
995
  console.log(`${pc.bold(' Scan result:')} ${scanned.primary_language} | ${scanned.frameworks.join(', ') || 'no framework'}`);
@@ -933,20 +999,34 @@ async function main() {
933
999
  scanned.scan_evidence.forEach(line => console.log(` · ${line}`));
934
1000
  console.log('');
935
1001
  }
1002
+
1003
+ if (!assumeYes) {
1004
+ const scanAction = await askQuestions({
1005
+ type: 'select',
1006
+ name: 'scan_action',
1007
+ message: 'Use detected context as-is or review fields manually?',
1008
+ choices: [
1009
+ { title: 'Use detected context', value: 'accept' },
1010
+ { title: 'Review detected fields', value: 'review' }
1011
+ ],
1012
+ initial: 0
1013
+ });
1014
+ reviewScannedFields = scanAction.scan_action === 'review';
1015
+ }
936
1016
  }
937
1017
 
938
1018
  const { project_name, description, project_type } = await askQuestions([
939
- { type: assumeYes ? null : 'text', name: 'project_name', message: 'Project name:', initial: scanned?.project_name || path.basename(targetDir) },
940
- { type: assumeYes ? null : 'text', name: 'description', message: 'Short description:', initial: scanned?.description || 'A software project' },
1019
+ { type: assumeYes || !reviewScannedFields ? null : 'text', name: 'project_name', message: 'Project name:', initial: scanned?.project_name || path.basename(targetDir) },
1020
+ { type: assumeYes || !reviewScannedFields ? null : 'text', name: 'description', message: 'Short description:', initial: scanned?.description || 'A software project' },
941
1021
  {
942
- type: assumeYes ? null : 'select', name: 'project_type', message: 'Project type:',
1022
+ type: assumeYes || !reviewScannedFields ? null : 'select', name: 'project_type', message: 'Project type:',
943
1023
  choices: PROJECT_TYPE_CHOICES.map(value => ({ title: value, value })),
944
1024
  initial: Math.max(PROJECT_TYPE_CHOICES.indexOf(scanned?.project_type || 'web-app'), 0)
945
1025
  }
946
1026
  ]);
947
1027
 
948
1028
  const { primary_language } = await askQuestions({
949
- type: assumeYes ? null : 'select',
1029
+ type: assumeYes || !reviewScannedFields ? null : 'select',
950
1030
  name: 'primary_language',
951
1031
  message: 'Primary language:',
952
1032
  choices: LANGUAGE_CHOICES.map(l => ({ title: l, value: l })),
@@ -954,7 +1034,7 @@ async function main() {
954
1034
  });
955
1035
 
956
1036
  const { frameworks } = await askQuestions({
957
- type: assumeYes ? null : 'multiselect',
1037
+ type: assumeYes || !reviewScannedFields ? null : 'multiselect',
958
1038
  name: 'frameworks',
959
1039
  message: 'Frameworks (Space to select, Enter to confirm):',
960
1040
  choices: FRAMEWORK_CHOICES.map(f => ({ title: f, value: f, selected: (scanned?.frameworks || []).includes(f) })),
@@ -963,13 +1043,13 @@ async function main() {
963
1043
 
964
1044
  const dbAndInfra = await askQuestions([
965
1045
  {
966
- type: assumeYes ? null : 'select', name: 'database', message: 'Database / ORM:',
1046
+ type: assumeYes || !reviewScannedFields ? null : 'select', name: 'database', message: 'Database / ORM:',
967
1047
  choices: DATABASE_CHOICES.map(d => ({ title: d, value: d })),
968
1048
  initial: Math.max(DATABASE_CHOICES.indexOf(scanned?.database || 'none'), 0)
969
1049
  },
970
- { type: assumeYes ? null : 'confirm', name: 'uses_docker', message: 'Uses Docker / Docker Compose?', initial: scanned?.uses_docker ?? true },
1050
+ { type: assumeYes || !reviewScannedFields ? null : 'confirm', name: 'uses_docker', message: 'Uses Docker / Docker Compose?', initial: scanned?.uses_docker ?? true },
971
1051
  {
972
- type: assumeYes ? null : 'select', name: 'cloud', message: 'Cloud Provider:',
1052
+ type: assumeYes || !reviewScannedFields ? null : 'select', name: 'cloud', message: 'Cloud Provider:',
973
1053
  choices: CLOUD_CHOICES.map(c => ({ title: c, value: c })),
974
1054
  initial: Math.max(CLOUD_CHOICES.indexOf(scanned?.cloud || 'none'), 0)
975
1055
  }
@@ -977,12 +1057,12 @@ async function main() {
977
1057
 
978
1058
  const { package_manager, test_framework, max_file_lines } = await askQuestions([
979
1059
  {
980
- type: assumeYes ? null : 'select', name: 'package_manager', message: 'Package Manager:',
1060
+ type: assumeYes || !reviewScannedFields ? null : 'select', name: 'package_manager', message: 'Package Manager:',
981
1061
  choices: PACKAGE_MANAGER_CHOICES.map(p => ({ title: p, value: p })),
982
1062
  initial: Math.max(PACKAGE_MANAGER_CHOICES.indexOf(scanned?.package_manager || 'auto-detect'), 0)
983
1063
  },
984
- { type: assumeYes ? null : 'text', name: 'test_framework', message: 'Test Framework (jest, phpunit, etc):', initial: scanned?.test_framework || 'auto-detect' },
985
- { type: assumeYes ? null : 'text', name: 'max_file_lines', message: 'Max lines per file:', initial: scanned?.max_file_lines || '300' }
1064
+ { type: assumeYes || !reviewScannedFields ? null : 'text', name: 'test_framework', message: 'Test Framework (jest, phpunit, etc):', initial: scanned?.test_framework || 'auto-detect' },
1065
+ { type: assumeYes || !reviewScannedFields ? null : 'text', name: 'max_file_lines', message: 'Max lines per file:', initial: scanned?.max_file_lines || '300' }
986
1066
  ]);
987
1067
 
988
1068
  // Combine data
@@ -1037,9 +1117,26 @@ async function main() {
1037
1117
  const claudeMdPath = path.join(targetDir, 'CLAUDE.md');
1038
1118
  fs.writeFileSync(claudeMdPath, generateClaudeMd(data), 'utf8');
1039
1119
  console.log(` ${pc.green('✓')} Generated ${pc.bold('CLAUDE.md')}`);
1040
-
1041
- // Summary
1042
- const autoSkills = resolveSkills(data);
1120
+
1121
+ if (!assumeYes) {
1122
+ const aiRefineAnswer = await askQuestions({
1123
+ type: 'confirm',
1124
+ name: 'ai_refine',
1125
+ message: 'Do you want an AI refinement prompt for PROJECT_CONTEXT.md?',
1126
+ initial: useScan
1127
+ });
1128
+ requestAiRefinement = Boolean(aiRefineAnswer.ai_refine);
1129
+ }
1130
+
1131
+ let aiRefinementPath = null;
1132
+ if (requestAiRefinement) {
1133
+ aiRefinementPath = path.join(targetDir, 'AI_CONTEXT_REFINEMENT.md');
1134
+ fs.writeFileSync(aiRefinementPath, generateAiContextRefinementPrompt(data), 'utf8');
1135
+ console.log(` ${pc.green('✓')} Generated ${pc.bold('AI_CONTEXT_REFINEMENT.md')}`);
1136
+ }
1137
+
1138
+ // Summary
1139
+ const autoSkills = resolveSkills(data);
1043
1140
  console.log(`\n${pc.bold(pc.green('━━ Done! ━━'))}
1044
1141
 
1045
1142
  ${pc.bold('Project:')} ${data.project_name}
@@ -1052,11 +1149,12 @@ ${autoSkills.map(s => ' · ' + s).join('\n')}
1052
1149
  ${pc.bold('Generated files:')}
1053
1150
  · ${pc.bold(projectContextPath)}
1054
1151
  · ${pc.bold(claudeMdPath)}
1152
+ ${aiRefinementPath ? ` · ${pc.bold(aiRefinementPath)}` : ''}
1055
1153
 
1056
1154
  ${pc.bold('Next steps:')}
1057
1155
  1. Your kit is installed in ${pc.bold('./.agent')}
1058
1156
  2. Review ${pc.bold('PROJECT_CONTEXT.md')} first and add architecture notes
1059
- 3. Instruct the agent to read/update ${pc.bold('PROJECT_CONTEXT.md')} before major tasks
1157
+ 3. ${aiRefinementPath ? `Open ${pc.bold('AI_CONTEXT_REFINEMENT.md')} in your AI editor to refine project context` : `Instruct the agent to read/update ${pc.bold('PROJECT_CONTEXT.md')} before major tasks`}
1060
1158
  4. Open project in Antigravity or Claude Code — the agent will read context on start
1061
1159
  `);
1062
1160
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thachvd-kit",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Universal Agent Kit for Antigravity, Claude Code, and OpenCode",
5
5
  "bin": {
6
6
  "thachvd-kit": "./bin/cli.js"
package/scripts/init.py CHANGED
@@ -607,7 +607,7 @@ Based on your stack, these skills will be loaded automatically:
607
607
  {data.get('known_issues', '<!-- Add known issues or pending tasks -->')}
608
608
  """
609
609
 
610
- def generate_claude_md(data):
610
+ def generate_claude_md(data):
611
611
  """Generate CLAUDE.md for Claude Code / Codex compatibility."""
612
612
  return f"""# CLAUDE.md — {data['project_name']}
613
613
  # Generated by thachvd-kit. See PROJECT_CONTEXT.md for full stack info.
@@ -636,8 +636,69 @@ Stack: {data['primary_language']} | {', '.join(data.get('frameworks', []))}
636
636
  - `/test` — Run test suite
637
637
  - `/deploy` — Deploy checklist
638
638
 
639
- See PROJECT_CONTEXT.md for full agent routing table.
640
- """
639
+ See PROJECT_CONTEXT.md for full agent routing table.
640
+ """
641
+
642
+ def generate_ai_context_refinement_prompt(data):
643
+ scan_evidence = data.get("scan_evidence", [])
644
+ evidence_block = "\n".join("- " + line for line in scan_evidence) if scan_evidence else "- No scan evidence was captured during init."
645
+ return f"""# AI Context Refinement
646
+
647
+ Use this prompt in your AI editor after `thachvd-kit init`.
648
+
649
+ ## Goal
650
+
651
+ Refine `PROJECT_CONTEXT.md` so it reflects the real project more accurately than the baseline init scan.
652
+
653
+ ## Current Baseline
654
+
655
+ - Project: {data['project_name']}
656
+ - Type: {data['project_type']}
657
+ - Stack: {data['primary_language']} | {', '.join(data.get('frameworks', [])) or 'no framework'}
658
+ - Database: {data.get('database', 'none')}
659
+ - Infra: {', '.join(data.get('infrastructure', [])) or 'none'}
660
+
661
+ ## Scan Evidence
662
+
663
+ {evidence_block}
664
+
665
+ ## Instructions For The AI Agent
666
+
667
+ 1. Read `PROJECT_CONTEXT.md` first.
668
+ 2. Inspect the project selectively to improve factual accuracy.
669
+ 3. Prioritize:
670
+ - real database/config detection
671
+ - domain/capability inference
672
+ - architecture notes
673
+ - more accurate auto-resolved skills
674
+ - important project-specific constraints
675
+ 4. Update `PROJECT_CONTEXT.md` directly.
676
+ 5. Distinguish facts from inferences when uncertain.
677
+ 6. Do not implement product code in this pass. Only refine project context.
678
+
679
+ ## Suggested Files To Inspect
680
+
681
+ - Root manifests: `package.json`, `composer.json`, `Cargo.toml`, `pyproject.toml`
682
+ - Infrastructure/config: Docker, CI, env, framework config files
683
+ - Database config and models
684
+ - Main app entry points, routing, controllers/services
685
+ - README and existing documentation
686
+
687
+ ## Desired Improvements
688
+
689
+ - Correct the `database` field if config files reveal the real DB.
690
+ - Add architecture notes that explain the actual structure.
691
+ - Infer domain capabilities such as scraping, browser automation, external API integrations, queues, workers, etc.
692
+ - Expand auto-resolved skills when there is clear evidence in the codebase.
693
+ - Add caveats or assumptions if parts of the stack are still uncertain.
694
+
695
+ ## Completion Standard
696
+
697
+ When done, summarize:
698
+ - what was corrected
699
+ - what is still inferred
700
+ - which files provided the strongest evidence
701
+ """
641
702
 
642
703
  # ─── Main wizard ─────────────────────────────────────────────────────────────
643
704
 
@@ -675,6 +736,7 @@ def main():
675
736
  use_scan = existing_mode == "scan"
676
737
 
677
738
  scanned = scan_project() if use_scan else None
739
+ review_scanned_fields = not use_scan
678
740
  if use_scan:
679
741
  print(f" {dim('Scan mode: detecting stack from current project files...')}")
680
742
  print(f" {bold('Scan result:')} {scanned['primary_language']} | {', '.join(scanned['frameworks']) or 'no framework'}")
@@ -684,6 +746,10 @@ def main():
684
746
  for line in scanned["scan_evidence"]:
685
747
  print(f" · {line}")
686
748
  print()
749
+ if not args.yes:
750
+ scan_action = ask_select("Use detected context as-is or review fields manually",
751
+ ["accept", "review"], default="accept")
752
+ review_scanned_fields = scan_action == "review"
687
753
  elif not args.yes:
688
754
  print(f" {dim('Manual mode: asking for project context explicitly.')}\n")
689
755
 
@@ -692,7 +758,7 @@ def main():
692
758
  else:
693
759
  data = {}
694
760
 
695
- if not args.yes:
761
+ if not args.yes and review_scanned_fields:
696
762
  # ── Project Info ──────────────────────────────────────────────────────
697
763
  section("Project Info")
698
764
  data["project_name"] = ask("Project name", default=(scanned or {}).get("project_name", Path.cwd().name))
@@ -783,11 +849,17 @@ def main():
783
849
  # CLAUDE.md (for Claude Code / Codex)
784
850
  if args.platform in ("claude", "all"):
785
851
  claude_path = Path("CLAUDE.md")
786
- claude_path.write_text(generate_claude_md(data), encoding="utf-8")
787
- print(f" {green('✓')} {bold('CLAUDE.md')} generated (Claude Code / Codex)")
788
-
789
- # Summary
790
- auto_skills = resolve_skills(data)
852
+ claude_path.write_text(generate_claude_md(data), encoding="utf-8")
853
+ print(f" {green('✓')} {bold('CLAUDE.md')} generated (Claude Code / Codex)")
854
+
855
+ ai_refine_path = None
856
+ if not args.yes and ask_bool("Generate AI context refinement prompt?", default=use_scan):
857
+ ai_refine_path = Path("AI_CONTEXT_REFINEMENT.md")
858
+ ai_refine_path.write_text(generate_ai_context_refinement_prompt(data), encoding="utf-8")
859
+ print(f" {green('✓')} {bold('AI_CONTEXT_REFINEMENT.md')} generated")
860
+
861
+ # Summary
862
+ auto_skills = resolve_skills(data)
791
863
  print(f"""
792
864
  {bold(green('━━ Done! ━━'))}
793
865
 
@@ -801,10 +873,11 @@ def main():
801
873
  {bold('Generated files:')}
802
874
  · {bold(str(output_path.resolve()))}
803
875
  · {bold(str(Path("CLAUDE.md").resolve())) if args.platform in ("claude", "all") else 'CLAUDE.md not generated for this platform'}
876
+ · {bold(str(ai_refine_path.resolve())) if ai_refine_path else 'AI_CONTEXT_REFINEMENT.md not generated'}
804
877
 
805
878
  {bold('Next steps:')}
806
879
  1. Review {bold('PROJECT_CONTEXT.md')} first and add architecture notes
807
- 2. Instruct the agent to read/update {bold('PROJECT_CONTEXT.md')} before major tasks
880
+ 2. {"Open " + bold("AI_CONTEXT_REFINEMENT.md") + " in your AI editor to refine project context" if ai_refine_path else "Instruct the agent to read/update " + bold("PROJECT_CONTEXT.md") + " before major tasks"}
808
881
  3. Open project in your AI editor (Antigravity / Claude Code / Codex)
809
882
  4. The agent will read PROJECT_CONTEXT.md on session start
810
883