@nahisaho/satori 0.25.5 → 0.27.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.
Files changed (90) hide show
  1. package/README.md +57 -1
  2. package/bin/satori.js +761 -33
  3. package/package.json +32 -2
  4. package/src/.github/skills/scientific-academic-writing/SKILL.md +10 -0
  5. package/src/.github/skills/scientific-active-learning/SKILL.md +10 -0
  6. package/src/.github/skills/scientific-adaptive-experiments/SKILL.md +10 -0
  7. package/src/.github/skills/scientific-advanced-imaging/SKILL.md +10 -0
  8. package/src/.github/skills/scientific-advanced-visualization/SKILL.md +10 -0
  9. package/src/.github/skills/scientific-anomaly-detection/SKILL.md +10 -0
  10. package/src/.github/skills/scientific-automl/SKILL.md +10 -0
  11. package/src/.github/skills/scientific-bayesian-statistics/SKILL.md +10 -0
  12. package/src/.github/skills/scientific-biobank-cohort/SKILL.md +10 -0
  13. package/src/.github/skills/scientific-biosignal-processing/SKILL.md +10 -0
  14. package/src/.github/skills/scientific-causal-inference/SKILL.md +10 -0
  15. package/src/.github/skills/scientific-causal-ml/SKILL.md +10 -0
  16. package/src/.github/skills/scientific-clinical-nlp/SKILL.md +10 -0
  17. package/src/.github/skills/scientific-clinical-pharmacology/SKILL.md +10 -0
  18. package/src/.github/skills/scientific-clinical-standards/SKILL.md +11 -0
  19. package/src/.github/skills/scientific-crispr-design/SKILL.md +10 -0
  20. package/src/.github/skills/scientific-critical-review/SKILL.md +10 -1
  21. package/src/.github/skills/scientific-data-preprocessing/SKILL.md +10 -0
  22. package/src/.github/skills/scientific-data-profiling/SKILL.md +10 -0
  23. package/src/.github/skills/scientific-data-simulation/SKILL.md +10 -0
  24. package/src/.github/skills/scientific-data-submission/SKILL.md +10 -0
  25. package/src/.github/skills/scientific-deep-chemistry/SKILL.md +10 -0
  26. package/src/.github/skills/scientific-deep-learning/SKILL.md +10 -0
  27. package/src/.github/skills/scientific-doe/SKILL.md +10 -0
  28. package/src/.github/skills/scientific-eda-correlation/SKILL.md +10 -0
  29. package/src/.github/skills/scientific-ensemble-methods/SKILL.md +10 -0
  30. package/src/.github/skills/scientific-explainable-ai/SKILL.md +10 -0
  31. package/src/.github/skills/scientific-feature-importance/SKILL.md +10 -0
  32. package/src/.github/skills/scientific-federated-learning/SKILL.md +10 -0
  33. package/src/.github/skills/scientific-geospatial-analysis/SKILL.md +10 -0
  34. package/src/.github/skills/scientific-glycomics/SKILL.md +10 -0
  35. package/src/.github/skills/scientific-gpu-singlecell/SKILL.md +10 -0
  36. package/src/.github/skills/scientific-hgnc-nomenclature/SKILL.md +10 -0
  37. package/src/.github/skills/scientific-hypothesis-pipeline/SKILL.md +10 -1
  38. package/src/.github/skills/scientific-image-analysis/SKILL.md +10 -0
  39. package/src/.github/skills/scientific-interactive-dashboard/SKILL.md +10 -0
  40. package/src/.github/skills/scientific-lab-automation/SKILL.md +10 -0
  41. package/src/.github/skills/scientific-latex-formatter/SKILL.md +10 -0
  42. package/src/.github/skills/scientific-lipidomics/SKILL.md +10 -0
  43. package/src/.github/skills/scientific-materials-characterization/SKILL.md +10 -0
  44. package/src/.github/skills/scientific-md-simulation/SKILL.md +10 -0
  45. package/src/.github/skills/scientific-medical-imaging/SKILL.md +10 -0
  46. package/src/.github/skills/scientific-metabolic-atlas/SKILL.md +11 -0
  47. package/src/.github/skills/scientific-metabolic-flux/SKILL.md +10 -0
  48. package/src/.github/skills/scientific-metabolomics-network/SKILL.md +10 -0
  49. package/src/.github/skills/scientific-metagenome-assembled-genomes/SKILL.md +10 -0
  50. package/src/.github/skills/scientific-missing-data-analysis/SKILL.md +10 -0
  51. package/src/.github/skills/scientific-ml-classification/SKILL.md +10 -0
  52. package/src/.github/skills/scientific-ml-regression/SKILL.md +10 -0
  53. package/src/.github/skills/scientific-model-monitoring/SKILL.md +10 -0
  54. package/src/.github/skills/scientific-multi-task-learning/SKILL.md +10 -0
  55. package/src/.github/skills/scientific-nci60-screening/SKILL.md +10 -0
  56. package/src/.github/skills/scientific-network-visualization/SKILL.md +10 -0
  57. package/src/.github/skills/scientific-neural-architecture-search/SKILL.md +10 -0
  58. package/src/.github/skills/scientific-neuroscience-electrophysiology/SKILL.md +10 -0
  59. package/src/.github/skills/scientific-paper-quality/SKILL.md +10 -0
  60. package/src/.github/skills/scientific-pca-tsne/SKILL.md +10 -0
  61. package/src/.github/skills/scientific-peer-review-response/SKILL.md +10 -0
  62. package/src/.github/skills/scientific-perturbation-analysis/SKILL.md +10 -0
  63. package/src/.github/skills/scientific-phylogenetics/SKILL.md +10 -0
  64. package/src/.github/skills/scientific-pipeline-scaffold/SKILL.md +10 -0
  65. package/src/.github/skills/scientific-plant-biology/SKILL.md +10 -0
  66. package/src/.github/skills/scientific-presentation-design/SKILL.md +10 -0
  67. package/src/.github/skills/scientific-process-optimization/SKILL.md +10 -0
  68. package/src/.github/skills/scientific-publication-figures/SKILL.md +10 -0
  69. package/src/.github/skills/scientific-quantum-computing/SKILL.md +10 -0
  70. package/src/.github/skills/scientific-radiology-ai/SKILL.md +10 -0
  71. package/src/.github/skills/scientific-reinforcement-learning/SKILL.md +10 -0
  72. package/src/.github/skills/scientific-reproducible-reporting/SKILL.md +10 -0
  73. package/src/.github/skills/scientific-research-methodology/SKILL.md +10 -0
  74. package/src/.github/skills/scientific-revision-tracker/SKILL.md +10 -0
  75. package/src/.github/skills/scientific-scatac-signac/SKILL.md +10 -0
  76. package/src/.github/skills/scientific-scvi-integration/SKILL.md +10 -0
  77. package/src/.github/skills/scientific-semi-supervised-learning/SKILL.md +10 -0
  78. package/src/.github/skills/scientific-spatial-multiomics/SKILL.md +10 -0
  79. package/src/.github/skills/scientific-spectral-signal/SKILL.md +10 -0
  80. package/src/.github/skills/scientific-squidpy-advanced/SKILL.md +11 -0
  81. package/src/.github/skills/scientific-statistical-simulation/SKILL.md +10 -0
  82. package/src/.github/skills/scientific-statistical-testing/SKILL.md +10 -0
  83. package/src/.github/skills/scientific-streaming-analytics/SKILL.md +10 -0
  84. package/src/.github/skills/scientific-supplementary-generator/SKILL.md +10 -0
  85. package/src/.github/skills/scientific-symbolic-mathematics/SKILL.md +10 -0
  86. package/src/.github/skills/scientific-time-series/SKILL.md +10 -0
  87. package/src/.github/skills/scientific-time-series-forecasting/SKILL.md +10 -0
  88. package/src/.github/skills/scientific-toxicology-env/SKILL.md +10 -0
  89. package/src/.github/skills/scientific-transfer-learning/SKILL.md +10 -0
  90. package/src/.github/skills/scientific-uncertainty-quantification/SKILL.md +10 -0
package/bin/satori.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const fs = require('fs');
4
- const path = require('path');
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
5
 
6
6
  const COMMAND = process.argv[2];
7
7
  const SUBCOMMAND = process.argv[3];
@@ -71,50 +71,410 @@ SATORI — Agent Skills for Science
71
71
 
72
72
  Usage:
73
73
  satori init [--force] [--dry-run] Install .github/ skills into current directory
74
+ satori skill search <query> Search skills by keyword
75
+ satori skill info <name> Show detailed skill information
74
76
  satori pipeline suggest Interactive pipeline recommendation
75
77
  satori pipeline list List all available pipelines
78
+ satori validate [--verbose] Validate all SKILL.md files
79
+ satori stats Show skill/TU coverage statistics
76
80
  satori help Show this help message
77
81
  satori --version, -v Show version number
78
82
 
79
83
  Options:
80
84
  --force Overwrite existing .github/ directory
81
85
  --dry-run Preview what would be installed without making changes
86
+ --verbose Show detailed validation output
82
87
  `);
83
88
  }
84
89
 
85
90
  // ── Pipeline Suggest ──
86
91
 
87
92
  const PIPELINES = [
88
- { id: 1, name: 'ä»®čŖ¬ę¤œčØ¼ā†’č«–ę–‡åŒ–', domain: 'general', keywords: ['仮説', '統計', 'č«–ę–‡', 'hypothesis'], skills: 'hypothesis-engine → data-preprocessing → statistical-testing → ml-classification → publication-figures → academic-writing → critical-review' },
89
- { id: 2, name: 'ćƒćƒŖć‚¢ćƒ³ćƒˆā†’č‡ØåŗŠ', domain: 'genomics', keywords: ['ćƒćƒŖć‚¢ćƒ³ćƒˆ', 'variant', 'VCF', 'WGS', 'WES'], skills: 'variant-interpretation → pharmacogenomics → precision-oncology → clinical-decision-support → clinical-reporting' },
90
- { id: 3, name: 'ćƒˆćƒ©ćƒ³ć‚¹ć‚ÆćƒŖćƒ—ćƒˆćƒ¼ćƒ ', domain: 'genomics', keywords: ['RNA-seq', 'ćƒˆćƒ©ćƒ³ć‚¹ć‚ÆćƒŖćƒ—ćƒˆćƒ¼ćƒ ', 'DEG', 'ē™ŗē¾'], skills: 'rnaseq-analysis → pathway-enrichment → network-analysis → publication-figures' },
91
- { id: 4, name: 'ć‚Øćƒ”ć‚øć‚§ćƒćƒ†ć‚£ć‚Æć‚¹', domain: 'genomics', keywords: ['ć‚Øćƒ”ć‚²ćƒŽćƒ ', 'ChIP-seq', 'ATAC-seq', 'ćƒ”ćƒćƒ«åŒ–'], skills: 'epigenomics-chromatin → regulatory-genomics → noncoding-rna → gene-regulation' },
92
- { id: 5, name: 'AlphaFold ę§‹é€ č§£ęž', domain: 'structural', keywords: ['AlphaFold', 'ć‚æćƒ³ćƒ‘ć‚Æč³Ŗę§‹é€ ', '3D', 'protein structure'], skills: 'alphafold-structures → protein-structure-analysis → molecular-docking' },
93
- { id: 6, name: 'ć‚Øćƒ“ćƒ‡ćƒ³ć‚¹åˆęˆ', domain: 'literature', keywords: ['ćƒ”ć‚æć‚¢ćƒŠćƒŖć‚·ć‚¹', 'systematic review', 'ę–‡ēŒ®', 'ć‚Øćƒ“ćƒ‡ćƒ³ć‚¹'], skills: 'deep-research → literature-search → meta-analysis → evidence-synthesis → academic-writing → critical-review' },
94
- { id: 7, name: 'å‰µč–¬ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³', domain: 'pharma', keywords: ['創薬', 'drug discovery', 'ADMET', 'ćƒ‰ćƒƒć‚­ćƒ³ć‚°'], skills: 'drug-target-profiling → compound-screening → molecular-docking → admet-pharmacokinetics → drug-repurposing' },
95
- { id: 8, name: 'ML/XAI ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³', domain: 'ml', keywords: ['ę©Ÿę¢°å­¦ēæ’', 'ML', 'SHAP', 'XAI', 'äŗˆęø¬ćƒ¢ćƒ‡ćƒ«'], skills: 'data-preprocessing → ml-classification → ml-regression → explainable-ai → fairness-bias → publication-figures' },
96
- { id: 9, name: 'ē’°å¢ƒćƒ»ē”Ÿę…‹å­¦', domain: 'ecology', keywords: ['ē”Ÿę…‹', 'ē”Ÿē‰©å¤šę§˜ę€§', 'SDM', 'ē’°å¢ƒ', 'ecology'], skills: 'environmental-ecology → biodiversity-conservation → species-distribution → time-series-forecasting' },
97
- { id: 10, name: 'čØˆē®—ęę–™ē§‘å­¦', domain: 'materials', keywords: ['Ꝑꖙ', 'materials', 'DFT', '物性'], skills: 'computational-materials → cheminformatics → molecular-dynamics → ml-regression' },
98
- { id: 11, name: 'åŒ»č–¬å“å®‰å…Øę€§', domain: 'pharma', keywords: ['ęœ‰å®³äŗ‹č±”', 'ćƒ•ć‚”ćƒ¼ćƒžć‚³ćƒ“ć‚øćƒ©ćƒ³ć‚¹', '安全性', 'adverse'], skills: 'pharmacovigilance → pharmacogenomics → regulatory-science' },
99
- { id: 12, name: 'åøŒå°‘ē–¾ę‚£', domain: 'clinical', keywords: ['åøŒå°‘ē–¾ę‚£', 'rare disease', 'Orphanet'], skills: 'rare-disease-genetics → gene-panel-design → variant-interpretation → clinical-reporting' },
100
- { id: 13, name: 'ćŒć‚“ć‚²ćƒŽćƒŸć‚Æć‚¹', domain: 'oncology', keywords: ['恌悓', 'cancer', 'TMB', 'ä½“ē“°čƒžå¤‰ē•°'], skills: 'cancer-genomics → precision-oncology → biomarker-discovery → clinical-reporting' },
101
- { id: 14, name: 'GWASćƒ»é›†å›£éŗä¼å­¦', domain: 'genomics', keywords: ['GWAS', 'é›†å›£éŗä¼å­¦', 'population genetics', 'biobank'], skills: 'biobank-cohort → population-genetics → statistical-testing → publication-figures' },
102
- { id: 15, name: 'ć‚·ćƒ³ć‚°ćƒ«ć‚»ćƒ«', domain: 'genomics', keywords: ['ć‚·ćƒ³ć‚°ćƒ«ć‚»ćƒ«', 'single-cell', 'scRNA-seq', 'ē©ŗé–“ćƒˆćƒ©ćƒ³ć‚¹ć‚ÆćƒŖćƒ—ćƒˆćƒ¼ćƒ '], skills: 'cellxgene-census → scvi-integration → spatial-transcriptomics → gene-regulation' },
103
- { id: 16, name: 'ćƒ—ćƒ­ćƒ†ć‚ŖćƒŸć‚Æć‚¹', domain: 'omics', keywords: ['ćƒ—ćƒ­ćƒ†ć‚ŖćƒŸć‚Æć‚¹', 'proteomics', 'č³Ŗé‡åˆ†ęž'], skills: 'proteomics → protein-structure-analysis → network-analysis' },
104
- { id: 17, name: 'ćƒ”ć‚æćƒœćƒ­ćƒŸć‚Æć‚¹', domain: 'omics', keywords: ['ćƒ”ć‚æćƒœćƒ­ćƒŸć‚Æć‚¹', 'metabolomics', 'ä»£č¬ē‰©', 'č„‚č³Ŗ'], skills: 'metabolomics → lipidomics → systems-biology → network-analysis' },
105
- { id: 18, name: 'ćƒžć‚¤ć‚Æćƒ­ćƒć‚¤ć‚Ŗćƒ¼ćƒ ', domain: 'ecology', keywords: ['ćƒžć‚¤ć‚Æćƒ­ćƒć‚¤ć‚Ŗćƒ¼ćƒ ', 'metagenome', '16S', 'č…øå†…ē“°čŒ'], skills: 'microbiome-metagenomics → metagenome-assembled-genomes → phylogenetics → environmental-ecology' },
106
- { id: 19, name: 'ćƒ‘ć‚¹ć‚¦ć‚§ć‚¤ćƒ»KG', domain: 'systems', keywords: ['ćƒ‘ć‚¹ć‚¦ć‚§ć‚¤', 'ćƒŠćƒ¬ćƒƒć‚øć‚°ćƒ©ćƒ•', 'knowledge graph', 'pathway'], skills: 'gene-id-mapping → pathway-enrichment → ontology-integration → network-analysis → knowledge-graph' },
107
- { id: 20, name: 'č¾²ę„­ćƒ»é£Ÿå“', domain: 'agriculture', keywords: ['農愭', '食品', 'agriculture', 'food safety'], skills: 'agricultural-science → food-science-nutrition → environmental-ecology' },
108
- { id: 21, name: 'č‡ØåŗŠęƒ…å ±å­¦', domain: 'clinical', keywords: ['č‡ØåŗŠ', 'EHR', 'FHIR', 'OMOP', 'é›»å­ć‚«ćƒ«ćƒ†'], skills: 'clinical-standards → clinical-nlp → clinical-reporting → healthcare-ai → survival-clinical' },
109
- { id: 22, name: 'ćƒ­ćƒœćƒ†ć‚£ć‚Æć‚¹ćƒ»IoT', domain: 'engineering', keywords: ['ćƒ­ćƒœćƒ†ć‚£ć‚Æć‚¹', 'IoT', 'ロボット', 'robotics'], skills: 'robotics-automation → lab-automation → lab-data-management → interactive-dashboard' },
110
- { id: 23, name: 'å®ŸéØ“čØˆē”»ćƒ»ēµ±čØˆ', domain: 'general', keywords: ['å®ŸéØ“čØˆē”»', 'DOE', 'ę¤œå‡ŗåŠ›', 'ć‚µćƒ³ćƒ—ćƒ«ć‚µć‚¤ć‚ŗ'], skills: 'experimental-design → statistical-testing → reproducibility-assessment → publication-figures' },
111
- { id: 24, name: 'ē§‘å­¦ēš„åÆč¦–åŒ–', domain: 'general', keywords: ['åÆč¦–åŒ–', 'visualization', 'ćƒ€ćƒƒć‚·ćƒ„ćƒœćƒ¼ćƒ‰', 'dashboard'], skills: 'publication-figures → interactive-dashboard' },
112
- { id: 25, name: 'å­¦č”“å‡ŗē‰ˆ', domain: 'literature', keywords: ['č«–ę–‡ęŠ•ēØæ', 'journal', 'ć‚°ćƒ©ćƒ³ćƒˆ', 'grant'], skills: 'academic-writing → critical-review → citation-network' },
113
- { id: 26, name: '科学教育', domain: 'education', keywords: ['教育', 'education', 'ć‚«ćƒŖć‚­ćƒ„ćƒ©ćƒ '], skills: 'science-education → reproducibility-assessment' },
93
+ {
94
+ id: 1,
95
+ name: 'ä»®čŖ¬ę¤œčØ¼ā†’č«–ę–‡åŒ–',
96
+ domain: 'general',
97
+ keywords: ['仮説', '統計', 'č«–ę–‡', 'hypothesis'],
98
+ skills:
99
+ 'hypothesis-engine → data-preprocessing → statistical-testing → ml-classification → publication-figures → academic-writing → critical-review',
100
+ },
101
+ {
102
+ id: 2,
103
+ name: 'ćƒćƒŖć‚¢ćƒ³ćƒˆā†’č‡ØåŗŠ',
104
+ domain: 'genomics',
105
+ keywords: ['ćƒćƒŖć‚¢ćƒ³ćƒˆ', 'variant', 'VCF', 'WGS', 'WES'],
106
+ skills:
107
+ 'variant-interpretation → pharmacogenomics → precision-oncology → clinical-decision-support → clinical-reporting',
108
+ },
109
+ {
110
+ id: 3,
111
+ name: 'ćƒˆćƒ©ćƒ³ć‚¹ć‚ÆćƒŖćƒ—ćƒˆćƒ¼ćƒ ',
112
+ domain: 'genomics',
113
+ keywords: ['RNA-seq', 'ćƒˆćƒ©ćƒ³ć‚¹ć‚ÆćƒŖćƒ—ćƒˆćƒ¼ćƒ ', 'DEG', 'ē™ŗē¾'],
114
+ skills: 'rnaseq-analysis → pathway-enrichment → network-analysis → publication-figures',
115
+ },
116
+ {
117
+ id: 4,
118
+ name: 'ć‚Øćƒ”ć‚øć‚§ćƒćƒ†ć‚£ć‚Æć‚¹',
119
+ domain: 'genomics',
120
+ keywords: ['ć‚Øćƒ”ć‚²ćƒŽćƒ ', 'ChIP-seq', 'ATAC-seq', 'ćƒ”ćƒćƒ«åŒ–'],
121
+ skills: 'epigenomics-chromatin → regulatory-genomics → noncoding-rna → gene-regulation',
122
+ },
123
+ {
124
+ id: 5,
125
+ name: 'AlphaFold ę§‹é€ č§£ęž',
126
+ domain: 'structural',
127
+ keywords: ['AlphaFold', 'ć‚æćƒ³ćƒ‘ć‚Æč³Ŗę§‹é€ ', '3D', 'protein structure'],
128
+ skills: 'alphafold-structures → protein-structure-analysis → molecular-docking',
129
+ },
130
+ {
131
+ id: 6,
132
+ name: 'ć‚Øćƒ“ćƒ‡ćƒ³ć‚¹åˆęˆ',
133
+ domain: 'literature',
134
+ keywords: ['ćƒ”ć‚æć‚¢ćƒŠćƒŖć‚·ć‚¹', 'systematic review', 'ę–‡ēŒ®', 'ć‚Øćƒ“ćƒ‡ćƒ³ć‚¹'],
135
+ skills:
136
+ 'deep-research → literature-search → meta-analysis → evidence-synthesis → academic-writing → critical-review',
137
+ },
138
+ {
139
+ id: 7,
140
+ name: 'å‰µč–¬ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³',
141
+ domain: 'pharma',
142
+ keywords: ['創薬', 'drug discovery', 'ADMET', 'ćƒ‰ćƒƒć‚­ćƒ³ć‚°'],
143
+ skills:
144
+ 'drug-target-profiling → compound-screening → molecular-docking → admet-pharmacokinetics → drug-repurposing',
145
+ },
146
+ {
147
+ id: 8,
148
+ name: 'ML/XAI ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³',
149
+ domain: 'ml',
150
+ keywords: ['ę©Ÿę¢°å­¦ēæ’', 'ML', 'SHAP', 'XAI', 'äŗˆęø¬ćƒ¢ćƒ‡ćƒ«'],
151
+ skills:
152
+ 'data-preprocessing → ml-classification → ml-regression → explainable-ai → fairness-bias → publication-figures',
153
+ },
154
+ {
155
+ id: 9,
156
+ name: 'ē’°å¢ƒćƒ»ē”Ÿę…‹å­¦',
157
+ domain: 'ecology',
158
+ keywords: ['ē”Ÿę…‹', 'ē”Ÿē‰©å¤šę§˜ę€§', 'SDM', 'ē’°å¢ƒ', 'ecology'],
159
+ skills: 'environmental-ecology → biodiversity-conservation → species-distribution → time-series-forecasting',
160
+ },
161
+ {
162
+ id: 10,
163
+ name: 'čØˆē®—ęę–™ē§‘å­¦',
164
+ domain: 'materials',
165
+ keywords: ['Ꝑꖙ', 'materials', 'DFT', '物性'],
166
+ skills: 'computational-materials → cheminformatics → molecular-dynamics → ml-regression',
167
+ },
168
+ {
169
+ id: 11,
170
+ name: 'åŒ»č–¬å“å®‰å…Øę€§',
171
+ domain: 'pharma',
172
+ keywords: ['ęœ‰å®³äŗ‹č±”', 'ćƒ•ć‚”ćƒ¼ćƒžć‚³ćƒ“ć‚øćƒ©ćƒ³ć‚¹', '安全性', 'adverse'],
173
+ skills: 'pharmacovigilance → pharmacogenomics → regulatory-science',
174
+ },
175
+ {
176
+ id: 12,
177
+ name: 'åøŒå°‘ē–¾ę‚£',
178
+ domain: 'clinical',
179
+ keywords: ['åøŒå°‘ē–¾ę‚£', 'rare disease', 'Orphanet'],
180
+ skills: 'rare-disease-genetics → gene-panel-design → variant-interpretation → clinical-reporting',
181
+ },
182
+ {
183
+ id: 13,
184
+ name: 'ćŒć‚“ć‚²ćƒŽćƒŸć‚Æć‚¹',
185
+ domain: 'oncology',
186
+ keywords: ['恌悓', 'cancer', 'TMB', 'ä½“ē“°čƒžå¤‰ē•°'],
187
+ skills: 'cancer-genomics → precision-oncology → biomarker-discovery → clinical-reporting',
188
+ },
189
+ {
190
+ id: 14,
191
+ name: 'GWASćƒ»é›†å›£éŗä¼å­¦',
192
+ domain: 'genomics',
193
+ keywords: ['GWAS', 'é›†å›£éŗä¼å­¦', 'population genetics', 'biobank'],
194
+ skills: 'biobank-cohort → population-genetics → statistical-testing → publication-figures',
195
+ },
196
+ {
197
+ id: 15,
198
+ name: 'ć‚·ćƒ³ć‚°ćƒ«ć‚»ćƒ«',
199
+ domain: 'genomics',
200
+ keywords: ['ć‚·ćƒ³ć‚°ćƒ«ć‚»ćƒ«', 'single-cell', 'scRNA-seq', 'ē©ŗé–“ćƒˆćƒ©ćƒ³ć‚¹ć‚ÆćƒŖćƒ—ćƒˆćƒ¼ćƒ '],
201
+ skills: 'cellxgene-census → scvi-integration → spatial-transcriptomics → gene-regulation',
202
+ },
203
+ {
204
+ id: 16,
205
+ name: 'ćƒ—ćƒ­ćƒ†ć‚ŖćƒŸć‚Æć‚¹',
206
+ domain: 'omics',
207
+ keywords: ['ćƒ—ćƒ­ćƒ†ć‚ŖćƒŸć‚Æć‚¹', 'proteomics', 'č³Ŗé‡åˆ†ęž'],
208
+ skills: 'proteomics → protein-structure-analysis → network-analysis',
209
+ },
210
+ {
211
+ id: 17,
212
+ name: 'ćƒ”ć‚æćƒœćƒ­ćƒŸć‚Æć‚¹',
213
+ domain: 'omics',
214
+ keywords: ['ćƒ”ć‚æćƒœćƒ­ćƒŸć‚Æć‚¹', 'metabolomics', 'ä»£č¬ē‰©', 'č„‚č³Ŗ'],
215
+ skills: 'metabolomics → lipidomics → systems-biology → network-analysis',
216
+ },
217
+ {
218
+ id: 18,
219
+ name: 'ćƒžć‚¤ć‚Æćƒ­ćƒć‚¤ć‚Ŗćƒ¼ćƒ ',
220
+ domain: 'ecology',
221
+ keywords: ['ćƒžć‚¤ć‚Æćƒ­ćƒć‚¤ć‚Ŗćƒ¼ćƒ ', 'metagenome', '16S', 'č…øå†…ē“°čŒ'],
222
+ skills: 'microbiome-metagenomics → metagenome-assembled-genomes → phylogenetics → environmental-ecology',
223
+ },
224
+ {
225
+ id: 19,
226
+ name: 'ćƒ‘ć‚¹ć‚¦ć‚§ć‚¤ćƒ»KG',
227
+ domain: 'systems',
228
+ keywords: ['ćƒ‘ć‚¹ć‚¦ć‚§ć‚¤', 'ćƒŠćƒ¬ćƒƒć‚øć‚°ćƒ©ćƒ•', 'knowledge graph', 'pathway'],
229
+ skills: 'gene-id-mapping → pathway-enrichment → ontology-integration → network-analysis → knowledge-graph',
230
+ },
231
+ {
232
+ id: 20,
233
+ name: 'č¾²ę„­ćƒ»é£Ÿå“',
234
+ domain: 'agriculture',
235
+ keywords: ['農愭', '食品', 'agriculture', 'food safety'],
236
+ skills: 'agricultural-science → food-science-nutrition → environmental-ecology',
237
+ },
238
+ {
239
+ id: 21,
240
+ name: 'č‡ØåŗŠęƒ…å ±å­¦',
241
+ domain: 'clinical',
242
+ keywords: ['č‡ØåŗŠ', 'EHR', 'FHIR', 'OMOP', 'é›»å­ć‚«ćƒ«ćƒ†'],
243
+ skills: 'clinical-standards → clinical-nlp → clinical-reporting → healthcare-ai → survival-clinical',
244
+ },
245
+ {
246
+ id: 22,
247
+ name: 'ćƒ­ćƒœćƒ†ć‚£ć‚Æć‚¹ćƒ»IoT',
248
+ domain: 'engineering',
249
+ keywords: ['ćƒ­ćƒœćƒ†ć‚£ć‚Æć‚¹', 'IoT', 'ロボット', 'robotics'],
250
+ skills: 'robotics-automation → lab-automation → lab-data-management → interactive-dashboard',
251
+ },
252
+ {
253
+ id: 23,
254
+ name: 'å®ŸéØ“čØˆē”»ćƒ»ēµ±čØˆ',
255
+ domain: 'general',
256
+ keywords: ['å®ŸéØ“čØˆē”»', 'DOE', 'ę¤œå‡ŗåŠ›', 'ć‚µćƒ³ćƒ—ćƒ«ć‚µć‚¤ć‚ŗ'],
257
+ skills: 'experimental-design → statistical-testing → reproducibility-assessment → publication-figures',
258
+ },
259
+ {
260
+ id: 24,
261
+ name: 'ē§‘å­¦ēš„åÆč¦–åŒ–',
262
+ domain: 'general',
263
+ keywords: ['åÆč¦–åŒ–', 'visualization', 'ćƒ€ćƒƒć‚·ćƒ„ćƒœćƒ¼ćƒ‰', 'dashboard'],
264
+ skills: 'publication-figures → interactive-dashboard',
265
+ },
266
+ {
267
+ id: 25,
268
+ name: 'å­¦č”“å‡ŗē‰ˆ',
269
+ domain: 'literature',
270
+ keywords: ['č«–ę–‡ęŠ•ēØæ', 'journal', 'ć‚°ćƒ©ćƒ³ćƒˆ', 'grant'],
271
+ skills: 'academic-writing → critical-review → citation-network',
272
+ },
273
+ {
274
+ id: 26,
275
+ name: '科学教育',
276
+ domain: 'education',
277
+ keywords: ['教育', 'education', 'ć‚«ćƒŖć‚­ćƒ„ćƒ©ćƒ '],
278
+ skills: 'science-education → reproducibility-assessment',
279
+ },
280
+ // ── ć‚Æćƒ­ć‚¹ćƒ‰ćƒ”ć‚¤ćƒ³ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³ ──
281
+ {
282
+ id: 'A',
283
+ name: 'ć‚²ćƒŽćƒ å‰µč–¬ēµ±åˆ',
284
+ domain: 'cross-domain',
285
+ keywords: ['ć‚²ćƒŽćƒ å‰µč–¬', 'GWAS', 'å‰µč–¬ć‚æćƒ¼ć‚²ćƒƒćƒˆ', 'drug target', 'biobank'],
286
+ skills:
287
+ 'biobank-cohort → population-genetics → drug-target-profiling → compound-screening → molecular-docking → admet-pharmacokinetics',
288
+ },
289
+ {
290
+ id: 'B',
291
+ name: 'AI é§†å‹•č‡ØåŗŠę„ę€ę±ŗå®š',
292
+ domain: 'cross-domain',
293
+ keywords: ['č‡ØåŗŠAI', '予後予測', 'SHAP', '患者', 'clinical AI'],
294
+ skills: 'clinical-decision-support → healthcare-ai → explainable-ai → pharmacovigilance → regulatory-science',
295
+ },
296
+ {
297
+ id: 'C',
298
+ name: 'ē ”ē©¶č‡Ŗå‹•åŒ–',
299
+ domain: 'cross-domain',
300
+ keywords: ['ē ”ē©¶č‡Ŗå‹•åŒ–', 'č«–ę–‡åŒ–', '仮説', 'research automation'],
301
+ skills:
302
+ 'deep-research → hypothesis-pipeline → pipeline-scaffold → data-preprocessing → statistical-testing → publication-figures → academic-writing → systematic-review',
303
+ },
304
+ {
305
+ id: 'D',
306
+ name: 'ćƒžćƒ«ćƒć‚ŖćƒŸć‚Æć‚¹ē–¾ę‚£č§£ę˜Ž',
307
+ domain: 'cross-domain',
308
+ keywords: ['ćƒžćƒ«ćƒć‚ŖćƒŸć‚Æć‚¹', '疾患', 'scRNA-seq', 'GRN', 'multi-omics'],
309
+ skills:
310
+ 'single-cell-genomics → spatial-transcriptomics → disease-research → systems-biology → multi-omics → network-analysis',
311
+ },
312
+ {
313
+ id: 'E',
314
+ name: 'å€‹åˆ„åŒ–č–¬ē‰©ē™‚ę³•',
315
+ domain: 'cross-domain',
316
+ keywords: ['å€‹åˆ„åŒ–åŒ»ē™‚', 'PGx', 'Star ć‚¢ćƒ¬ćƒ«', 'ęŠ•äøŽé‡ęœ€é©åŒ–', 'pharmacogenomics'],
317
+ skills:
318
+ 'variant-interpretation → pharmacogenomics → drug-target-profiling → admet-pharmacokinetics → clinical-decision-support → pharmacovigilance',
319
+ },
320
+ {
321
+ id: 'F',
322
+ name: 'ćƒć‚¤ć‚Ŗć‚¤ćƒ³ćƒ•ć‚©ćƒžćƒ†ć‚£ć‚Æć‚¹å®Œå…Ø',
323
+ domain: 'cross-domain',
324
+ keywords: ['ćƒć‚¤ć‚Ŗć‚¤ćƒ³ćƒ•ć‚©ćƒžćƒ†ć‚£ć‚Æć‚¹', 'FASTQ', 'é…åˆ—č§£ęž', 'ēµ±åˆćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³'],
325
+ skills:
326
+ 'bioinformatics → single-cell-genomics → biobank-cohort → multi-omics → population-genetics → systems-biology → hypothesis-pipeline → academic-writing',
327
+ },
328
+ {
329
+ id: 'G',
330
+ name: 'ćŒć‚“ē²¾åÆ†åŒ»ē™‚ End-to-End',
331
+ domain: 'cross-domain',
332
+ keywords: ['ćŒć‚“ē²¾åÆ†åŒ»ē™‚', 'GDC', 'DepMap', 'ē²¾åÆ†č…«ē˜å­¦', 'TCGA'],
333
+ skills:
334
+ 'gdc-portal → cancer-genomics → depmap-dependencies → civic-evidence → pharos-targets → compound-screening → precision-oncology → clinical-decision-support → healthcare-ai → survival-clinical',
335
+ },
336
+ {
337
+ id: 'H',
338
+ name: 'ćƒžćƒ«ćƒć‚ŖćƒŸć‚Æć‚¹ēø¦ę–­ēµ±åˆ',
339
+ domain: 'cross-domain',
340
+ keywords: ['ēø¦ę–­ēµ±åˆ', 'ć‚Øćƒ”ć‚²ćƒŽćƒ ', 'ćƒ—ćƒ­ćƒ†ć‚Ŗćƒ¼ćƒ ', 'ćƒ‘ć‚¹ć‚¦ć‚§ć‚¤', 'VEP'],
341
+ skills:
342
+ 'genome-sequence-tools → bioinformatics → variant-effect-prediction → epigenomics-chromatin → regulatory-genomics → cellxgene-census → scvi-integration → uniprot-proteome → alphafold-structures → protein-interaction-network → pathway-enrichment → reactome-pathways → network-visualization',
343
+ },
344
+ {
345
+ id: 'I',
346
+ name: 'ē’°å¢ƒćƒ”ć‚æćƒœćƒ»ćƒžć‚¤ć‚Æćƒ­ćƒć‚¤ć‚Ŗćƒ¼ćƒ  One Health',
347
+ domain: 'cross-domain',
348
+ keywords: ['One Health', 'ē’°å¢ƒćƒ”ć‚æćƒœ', '土壌', 'å¾®ē”Ÿē‰©ē¾¤é›†', 'SDM'],
349
+ skills:
350
+ 'environmental-ecology → environmental-geodata → geospatial-analysis → microbiome-metagenomics → metagenome-assembled-genomes → phylogenetics → metabolomics-databases → metabolomics-network → metabolic-modeling → toxicology-env → publication-figures',
351
+ },
352
+ {
353
+ id: 'J',
354
+ name: 'AI é§†å‹•ćƒžćƒ†ćƒŖć‚¢ćƒ«ć‚ŗć‚¤ćƒ³ćƒ•ć‚©ćƒžćƒ†ć‚£ć‚Æć‚¹',
355
+ domain: 'cross-domain',
356
+ keywords: ['ćƒžćƒ†ćƒŖć‚¢ćƒ«ć‚ŗć‚¤ćƒ³ćƒ•ć‚©ćƒžćƒ†ć‚£ć‚Æć‚¹', 'GNN', 'čƒ½å‹•å­¦ēæ’', 'Materials Project', 'ęę–™ęŽ¢ē“¢'],
357
+ skills:
358
+ 'computational-materials → cheminformatics → automl → graph-neural-networks → uncertainty-quantification → active-learning → doe → bayesian-statistics → adaptive-experiments → materials-characterization → advanced-visualization',
359
+ },
360
+ {
361
+ id: 'K',
362
+ name: 'ē ”ē©¶ćƒ©ć‚¤ćƒ•ć‚µć‚¤ć‚Æćƒ«å®Œå…Øč‡Ŗå‹•åŒ–',
363
+ domain: 'cross-domain',
364
+ keywords: ['ē ”ē©¶ćƒ©ć‚¤ćƒ•ć‚µć‚¤ć‚Æćƒ«', 'ćƒ©ćƒœč‡Ŗå‹•åŒ–', 'LIMS', 'ćƒ€ćƒƒć‚·ćƒ„ćƒœćƒ¼ćƒ‰', 'ć‚°ćƒ©ćƒ³ćƒˆ'],
365
+ skills:
366
+ 'lab-automation → lab-data-management → streaming-analytics → model-monitoring → data-profiling → advanced-visualization → interactive-dashboard → scientific-schematics → reproducible-reporting → paper-quality → latex-formatter → peer-review-response → grant-writing → preprint-archive',
367
+ },
368
+ {
369
+ id: 'L',
370
+ name: 'AI é§†å‹•ć‚Øćƒ“ćƒ‡ćƒ³ć‚¹åˆęˆ',
371
+ domain: 'cross-domain',
372
+ keywords: ['ć‚Øćƒ“ćƒ‡ćƒ³ć‚¹åˆęˆAI', 'DLę–‡ēŒ®', 'AutoML', 'ć‚¹ć‚ÆćƒŖćƒ¼ćƒ‹ćƒ³ć‚°'],
373
+ skills:
374
+ 'deep-research → literature-search → text-mining-nlp → deep-learning → transfer-learning → automl → meta-analysis → explainable-ai → systematic-review → academic-writing',
375
+ },
376
+ {
377
+ id: 'M',
378
+ name: 'ćŒć‚“ćƒžćƒ«ćƒćƒ¬ć‚¤ćƒ¤ćƒ¼ć‚²ćƒŽćƒ å‰µč–¬',
379
+ domain: 'cross-domain',
380
+ keywords: ['ćŒć‚“ć‚²ćƒŽćƒ å‰µč–¬', 'ICGC', 'ChEMBL', 'ć‚Øćƒ”ć‚²ćƒŽćƒ '],
381
+ skills:
382
+ 'gdc-portal → cancer-genomics → icgc-cancer-data → ensembl-genomics → variant-effect-prediction → epigenomics-chromatin → gwas-catalog → pharos-targets → chembl-assay-mining → compound-screening',
383
+ },
384
+ {
385
+ id: 'N',
386
+ name: 'č‡ØåŗŠā†’č¦åˆ¶ā†’å‡ŗē‰ˆćƒćƒŖćƒ„ćƒ¼ćƒć‚§ćƒ¼ćƒ³',
387
+ domain: 'cross-domain',
388
+ keywords: ['ćƒćƒŖćƒ„ćƒ¼ćƒć‚§ćƒ¼ćƒ³', 'EHR', 'č¦åˆ¶å ±å‘Š', 'å­¦č”“å‡ŗē‰ˆ', 'HL7'],
389
+ skills:
390
+ 'clinical-standards → clinical-nlp → clinical-reporting → healthcare-ai → pharmacovigilance → regulatory-science → reproducible-reporting → paper-quality → latex-formatter → peer-review-response',
391
+ },
392
+ {
393
+ id: 'O',
394
+ name: 'ć‚·ćƒ³ć‚°ćƒ«ć‚»ćƒ«ćƒ—ćƒ­ćƒ†ć‚Ŗćƒ¼ćƒ ēµ±åˆ',
395
+ domain: 'cross-domain',
396
+ keywords: ['ć‚·ćƒ³ć‚°ćƒ«ć‚»ćƒ«ćƒ—ćƒ­ćƒ†ć‚Ŗćƒ¼ćƒ ', 'č³Ŗé‡åˆ†ęž', 'ä»£č¬ćƒ¢ćƒ‡ćƒ«', 'MOFA+'],
397
+ skills:
398
+ 'single-cell-genomics → spatial-transcriptomics → proteomics-mass-spectrometry → structural-proteomics → alphafold-structures → metabolomics-databases → metabolic-modeling → systems-biology → multi-omics',
399
+ },
400
+ // ── ć‚¤ćƒ³ćƒ€ć‚¹ćƒˆćƒŖćƒ¼ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³ ──
401
+ {
402
+ id: 'Ind-1',
403
+ name: 'č£½č–¬ä¼ę„­ćƒ¬ć‚®ćƒ„ćƒ©ćƒˆćƒŖćƒ¼',
404
+ domain: 'industry',
405
+ keywords: ['製薬', 'CTD', 'ćƒ¬ć‚®ćƒ„ćƒ©ćƒˆćƒŖćƒ¼', 'č¦åˆ¶ē”³č«‹', 'regulatory'],
406
+ skills:
407
+ 'drug-target-profiling → molecular-docking → admet-pharmacokinetics → clinical-trials-analytics → pharmacovigilance → regulatory-science → reproducible-reporting → paper-quality',
408
+ },
409
+ {
410
+ id: 'Ind-2',
411
+ name: 'č¾²ę„­ćƒć‚¤ć‚Ŗćƒ†ć‚ÆćƒŽćƒ­ć‚øćƒ¼',
412
+ domain: 'industry',
413
+ keywords: ['č¾²ę„­ćƒć‚¤ć‚Ŗ', 'åœŸå£Œå¾®ē”Ÿē‰©', 'CRISPR', '圃堓', 'ć‚²ćƒŽćƒ ē·Øé›†'],
414
+ skills:
415
+ 'environmental-ecology → microbiome-metagenomics → geospatial-analysis → plant-biology → crispr-design → gene-expression-transcriptomics → doe → publication-figures',
416
+ },
417
+ {
418
+ id: 'Ind-3',
419
+ name: 'č‡ØåŗŠę¤œęŸ»å®¤ćƒÆćƒ¼ć‚Æćƒ•ćƒ­ćƒ¼',
420
+ domain: 'industry',
421
+ keywords: ['č‡ØåŗŠę¤œęŸ»', 'NGS', 'ACMG', 'PGx', 'č‡ØåŗŠćƒ¬ćƒćƒ¼ćƒˆ'],
422
+ skills:
423
+ 'genome-sequence-tools → variant-interpretation → pharmacogenomics → clinical-decision-support → clinical-standards → clinical-nlp → clinical-reporting',
424
+ },
425
+ {
426
+ id: 'Ind-4',
427
+ name: 'é£Ÿå“å®‰å…Øćƒ»ęÆ’ę€§č©•ä¾”',
428
+ domain: 'industry',
429
+ keywords: ['é£Ÿå“å®‰å…Ø', '毒性', '残留農薬', 'ćƒ•ćƒ¼ćƒ‰ć‚»ćƒ¼ćƒ•ćƒ†ć‚£', 'food safety'],
430
+ skills:
431
+ 'microbiome-metagenomics → rrna-taxonomy → metabolomics-databases → metabolomics-network → toxicology-env → data-profiling → regulatory-science → publication-figures',
432
+ },
433
+ {
434
+ id: 'Ind-5',
435
+ name: 'ę³•åŒ»ćƒ»å…¬č”†č”›ē”Ÿ',
436
+ domain: 'industry',
437
+ keywords: ['ę³•åŒ»å­¦', 'å…¬č”†č”›ē”Ÿ', 'ć‚¢ć‚¦ćƒˆćƒ–ćƒ¬ć‚¤ć‚Æ', 'ć‚µćƒ¼ćƒ™ć‚¤ćƒ©ćƒ³ć‚¹', 'forensic'],
438
+ skills:
439
+ 'variant-interpretation → population-genetics → infectious-disease → phylogenetics → immunoinformatics → epidemiology-public-health → public-health-data → biobank-cohort',
440
+ },
441
+ // ── ćƒ”ć‚½ćƒ‰ćƒ­ć‚øćƒ¼ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³ ──
442
+ {
443
+ id: 'M-α',
444
+ name: 'ćƒ™ć‚¤ć‚ŗęŽØč«–ćƒÆćƒ¼ć‚Æćƒ•ćƒ­ćƒ¼',
445
+ domain: 'methodology',
446
+ keywords: ['ćƒ™ć‚¤ć‚ŗ', 'MCMC', 'äŗ‹å¾Œåˆ†åøƒ', 'Bayesian', 'äŗ‹å‰åˆ†åøƒ'],
447
+ skills:
448
+ 'data-preprocessing → bayesian-statistics → statistical-simulation → uncertainty-quantification → doe → adaptive-experiments',
449
+ },
450
+ {
451
+ id: 'M-β',
452
+ name: 'å› ęžœęŽØč«–ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³',
453
+ domain: 'methodology',
454
+ keywords: ['å› ęžœęŽØč«–', 'DAG', '傾向スコア', 'CATE', 'causal'],
455
+ skills:
456
+ 'data-preprocessing → missing-data-analysis → causal-inference → causal-ml → explainable-ai → statistical-testing → publication-figures',
457
+ },
458
+ {
459
+ id: 'M-γ',
460
+ name: 'ę™‚ē³»åˆ—äŗˆęø¬ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³',
461
+ domain: 'methodology',
462
+ keywords: ['ę™‚ē³»åˆ—', 'Prophet', 'ARIMA', 'LSTM', 'ē•°åøøę¤œēŸ„', 'forecasting'],
463
+ skills:
464
+ 'data-preprocessing → time-series → time-series-forecasting → anomaly-detection → streaming-analytics → model-monitoring',
465
+ },
466
+ {
467
+ id: 'M-Ī“',
468
+ name: 'ćƒ†ć‚­ć‚¹ćƒˆćƒžć‚¤ćƒ‹ćƒ³ć‚°ćƒ»NLP',
469
+ domain: 'methodology',
470
+ keywords: ['ćƒ†ć‚­ć‚¹ćƒˆćƒžć‚¤ćƒ‹ćƒ³ć‚°', 'NLP', 'PubTator', 'å¼•ē”ØćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æ', 'NER'],
471
+ skills:
472
+ 'deep-research → literature-search → text-mining-nlp → biomedical-pubtator → clinical-nlp → semantic-scholar → citation-checker',
473
+ },
114
474
  ];
115
475
 
116
476
  function pipelineSuggest() {
117
- const readline = require('readline');
477
+ const readline = require('node:readline');
118
478
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
119
479
 
120
480
  const ask = (q) => new Promise((resolve) => rl.question(q, resolve));
@@ -162,6 +522,7 @@ function pipelineSuggest() {
162
522
  console.log(` ... 他 ${scored.length - 5} ä»¶`);
163
523
  }
164
524
  console.log('詳瓰は docs/SATORI_PIPELINE_EXAMPLES.md ć‚’å‚ē…§ć—ć¦ćć ć•ć„ć€‚');
525
+ console.log('å…Øćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³äø€č¦§ćÆ `satori pipeline list` ć§ē¢ŗčŖć§ćć¾ć™ć€‚');
165
526
  }
166
527
 
167
528
  rl.close();
@@ -169,14 +530,42 @@ function pipelineSuggest() {
169
530
  }
170
531
 
171
532
  function pipelineList() {
172
- console.log('\nšŸ“‹ SATORI ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³äø€č¦§ (26 ćƒ‰ćƒ”ć‚¤ćƒ³ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³)\n');
173
- for (const p of PIPELINES) {
533
+ const domain = PIPELINES.filter((p) => typeof p.id === 'number');
534
+ const cross = PIPELINES.filter((p) => p.domain === 'cross-domain');
535
+ const industry = PIPELINES.filter((p) => p.domain === 'industry');
536
+ const methodology = PIPELINES.filter((p) => p.domain === 'methodology');
537
+
538
+ console.log(`\nšŸ“‹ SATORI ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³äø€č¦§ (å…Ø ${PIPELINES.length} ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³)\n`);
539
+
540
+ console.log('── ćƒ‰ćƒ”ć‚¤ćƒ³ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³ (26) ──\n');
541
+ for (const p of domain) {
174
542
  console.log(` #${String(p.id).padStart(2, ' ')} ${p.name}`);
175
543
  console.log(` ${p.skills}`);
176
544
  console.log('');
177
545
  }
178
- console.log('ć‚Æćƒ­ć‚¹ćƒ‰ćƒ”ć‚¤ćƒ³ (15), ē”£ę„­ē‰¹åŒ– (5), ę–¹ę³•č«–ē‰¹åŒ– (4) ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³ćÆ');
179
- console.log('docs/SATORI_PIPELINE_EXAMPLES.md ć‚’å‚ē…§ć—ć¦ćć ć•ć„ć€‚');
546
+
547
+ console.log('── ć‚Æćƒ­ć‚¹ćƒ‰ćƒ”ć‚¤ćƒ³ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³ (15) ──\n');
548
+ for (const p of cross) {
549
+ console.log(` #${p.id} ${p.name}`);
550
+ console.log(` ${p.skills}`);
551
+ console.log('');
552
+ }
553
+
554
+ console.log('── ć‚¤ćƒ³ćƒ€ć‚¹ćƒˆćƒŖćƒ¼ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³ (5) ──\n');
555
+ for (const p of industry) {
556
+ console.log(` #${p.id} ${p.name}`);
557
+ console.log(` ${p.skills}`);
558
+ console.log('');
559
+ }
560
+
561
+ console.log('── ćƒ”ć‚½ćƒ‰ćƒ­ć‚øćƒ¼ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³ (4) ──\n');
562
+ for (const p of methodology) {
563
+ console.log(` #${p.id} ${p.name}`);
564
+ console.log(` ${p.skills}`);
565
+ console.log('');
566
+ }
567
+
568
+ console.log('詳瓰は docs/SATORI_PIPELINE_EXAMPLES.md ć‚’å‚ē…§ć—ć¦ćć ć•ć„ć€‚');
180
569
  }
181
570
 
182
571
  function showVersion() {
@@ -184,10 +573,343 @@ function showVersion() {
184
573
  console.log(pkg.version);
185
574
  }
186
575
 
576
+ // ── Validate ──
577
+
578
+ function parseFrontmatter(content) {
579
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
580
+ if (!match) return null;
581
+ const yaml = match[1];
582
+ const name = yaml.match(/^name:\s*(.+)$/m)?.[1]?.trim();
583
+ const hasDescription = /^description:/m.test(yaml);
584
+ return { name, hasDescription };
585
+ }
586
+
587
+ function validate() {
588
+ const verbose = FLAGS.includes('--verbose');
589
+ const skillsDir = path.join(SOURCE_DIR, 'skills');
590
+
591
+ if (!fs.existsSync(skillsDir)) {
592
+ console.error('Error: skills directory not found:', skillsDir);
593
+ process.exit(1);
594
+ }
595
+
596
+ const dirs = fs
597
+ .readdirSync(skillsDir)
598
+ .filter((d) => d.startsWith('scientific-'))
599
+ .sort();
600
+ let pass = 0;
601
+ let fail = 0;
602
+ const errors = [];
603
+
604
+ for (const dir of dirs) {
605
+ const filePath = path.join(skillsDir, dir, 'SKILL.md');
606
+ const issues = [];
607
+
608
+ if (!fs.existsSync(filePath)) {
609
+ issues.push('SKILL.md ćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“');
610
+ } else {
611
+ const content = fs.readFileSync(filePath, 'utf-8');
612
+ const fm = parseFrontmatter(content);
613
+
614
+ if (!fm) issues.push('YAML Frontmatter ćŒć‚ć‚Šć¾ć›ć‚“');
615
+ else {
616
+ if (!fm.name) issues.push('Frontmatter 恫 name ćŒć‚ć‚Šć¾ć›ć‚“');
617
+ else if (fm.name !== dir) issues.push(`name äøäø€č‡“: "${fm.name}" (ęœŸå¾…å€¤: "${dir}")`);
618
+ if (!fm.hasDescription) issues.push('Frontmatter 恫 description ćŒć‚ć‚Šć¾ć›ć‚“');
619
+ }
620
+
621
+ if (!/^# .+$/m.test(content)) issues.push('H1 ć‚æć‚¤ćƒˆćƒ«ćŒć‚ć‚Šć¾ć›ć‚“');
622
+ if (!/^## When to Use/m.test(content)) issues.push('## When to Use ć‚»ć‚Æć‚·ćƒ§ćƒ³ćŒć‚ć‚Šć¾ć›ć‚“');
623
+ if (!/^## Quick Start/m.test(content)) issues.push('## Quick Start ć‚»ć‚Æć‚·ćƒ§ćƒ³ćŒć‚ć‚Šć¾ć›ć‚“');
624
+ if (!/```(?:python|markdown|json)/.test(content)) issues.push('ć‚³ćƒ¼ćƒ‰ćƒ–ćƒ­ćƒƒć‚ÆćŒć‚ć‚Šć¾ć›ć‚“');
625
+ }
626
+
627
+ if (issues.length === 0) {
628
+ pass++;
629
+ if (verbose) console.log(` āœ” ${dir}`);
630
+ } else {
631
+ fail++;
632
+ errors.push({ dir, issues });
633
+ if (verbose) {
634
+ console.log(` ✘ ${dir}`);
635
+ for (const issue of issues) console.log(` - ${issue}`);
636
+ }
637
+ }
638
+ }
639
+
640
+ console.log(`\nšŸ“‹ SKILL.md ę¤œčØ¼ēµęžœ: ${pass} pass / ${fail} fail (å…Ø ${dirs.length} ć‚¹ć‚­ćƒ«)`);
641
+
642
+ if (errors.length > 0 && !verbose) {
643
+ console.log('\nå•é”Œć®ć‚ć‚‹ć‚¹ć‚­ćƒ«:');
644
+ for (const e of errors) {
645
+ console.log(` ✘ ${e.dir}: ${e.issues.join(', ')}`);
646
+ }
647
+ }
648
+
649
+ if (fail > 0) {
650
+ console.log('\n詳瓰は --verbose ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ć§ē¢ŗčŖć—ć¦ćć ć•ć„ć€‚');
651
+ process.exit(1);
652
+ } else {
653
+ console.log('\nāœ” å…Øć‚¹ć‚­ćƒ«ć®ę¤œčØ¼ć«ęˆåŠŸć—ć¾ć—ćŸć€‚');
654
+ }
655
+ }
656
+
657
+ // ── Stats ──
658
+
659
+ function stats() {
660
+ const skillsDir = path.join(SOURCE_DIR, 'skills');
661
+
662
+ if (!fs.existsSync(skillsDir)) {
663
+ console.error('Error: skills directory not found:', skillsDir);
664
+ process.exit(1);
665
+ }
666
+
667
+ const dirs = fs
668
+ .readdirSync(skillsDir)
669
+ .filter((d) => d.startsWith('scientific-'))
670
+ .sort();
671
+ const totalSkills = dirs.length;
672
+ let tuLinked = 0;
673
+ let totalCodeBlocks = 0;
674
+ const tuPattern = /ToolUniverse|åˆ©ē”ØåÆčƒ½ćƒ„ćƒ¼ćƒ«|SMCP/i;
675
+ const tuKeyPattern = /`([A-Z][a-zA-Z]*_[a-z]+_[a-z_]+)`/g;
676
+ const allTuKeys = new Set();
677
+
678
+ for (const dir of dirs) {
679
+ const filePath = path.join(skillsDir, dir, 'SKILL.md');
680
+ if (!fs.existsSync(filePath)) continue;
681
+ const content = fs.readFileSync(filePath, 'utf-8');
682
+
683
+ if (tuPattern.test(content)) tuLinked++;
684
+
685
+ const codeBlocks = content.match(/```(?:python|markdown|json)/g);
686
+ if (codeBlocks) totalCodeBlocks += codeBlocks.length;
687
+
688
+ for (const m of content.matchAll(tuKeyPattern)) {
689
+ allTuKeys.add(m[1]);
690
+ }
691
+ }
692
+
693
+ const coverage = ((tuLinked / totalSkills) * 100).toFixed(1);
694
+ const pkg = require(path.join(PACKAGE_ROOT, 'package.json'));
695
+
696
+ console.log(`
697
+ šŸ“Š SATORI v${pkg.version} — 統計
698
+
699
+ ć‚¹ć‚­ćƒ«ē·ę•°: ${totalSkills}
700
+ ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³ę•°: ${PIPELINES.length}
701
+ TU é€£ęŗć‚¹ć‚­ćƒ«: ${tuLinked} (${coverage}%)
702
+ TU ęœŖé€£ęŗ: ${totalSkills - tuLinked}
703
+ ćƒ¦ćƒ‹ćƒ¼ć‚Æ TU ć‚­ćƒ¼: ${allTuKeys.size}
704
+ ć‚³ćƒ¼ćƒ‰ćƒ–ćƒ­ćƒƒć‚Æē·ę•°: ${totalCodeBlocks}
705
+ `);
706
+ }
707
+
708
+ // ── Skill Search / Info ──
709
+
710
+ function loadAllSkills() {
711
+ const skillsDir = path.join(SOURCE_DIR, 'skills');
712
+ if (!fs.existsSync(skillsDir)) {
713
+ console.error('Error: skills directory not found:', skillsDir);
714
+ process.exit(1);
715
+ }
716
+ const dirs = fs
717
+ .readdirSync(skillsDir)
718
+ .filter((d) => d.startsWith('scientific-'))
719
+ .sort();
720
+ const skills = [];
721
+ for (const dir of dirs) {
722
+ const filePath = path.join(skillsDir, dir, 'SKILL.md');
723
+ if (!fs.existsSync(filePath)) continue;
724
+ const content = fs.readFileSync(filePath, 'utf-8');
725
+ const fm = parseFrontmatter(content);
726
+ const descMatch = content.match(/^description:\s*\|?\s*\n([\s\S]*?)(?=\n\w|\n---)/m);
727
+ const description = descMatch ? descMatch[1].replace(/^\s+/gm, '').trim() : fm?.hasDescription ? '' : '';
728
+ const tuKeyPattern = /`([A-Z][a-zA-Z]*_[a-z]+_[a-z_]+)`/g;
729
+ const tuKeys = [];
730
+ for (const m of content.matchAll(tuKeyPattern)) {
731
+ tuKeys.push(m[1]);
732
+ }
733
+ const h1Match = content.match(/^# (.+)$/m);
734
+ const title = h1Match ? h1Match[1].trim() : dir;
735
+ skills.push({ dir, name: fm?.name || dir, title, description, content, tuKeys });
736
+ }
737
+ return skills;
738
+ }
739
+
740
+ function skillSearch() {
741
+ const query = process.argv.slice(4).join(' ').toLowerCase();
742
+ if (!query) {
743
+ console.error('Error: ę¤œē“¢ć‚Æć‚ØćƒŖć‚’ęŒ‡å®šć—ć¦ćć ć•ć„ć€‚');
744
+ console.log('Usage: satori skill search <query>');
745
+ process.exit(1);
746
+ }
747
+
748
+ const skills = loadAllSkills();
749
+ const scored = skills
750
+ .map((s) => {
751
+ let score = 0;
752
+ // åå‰ć®å®Œå…Øäø€č‡“
753
+ if (s.name.toLowerCase() === query) score += 10;
754
+ // åå‰ć«å«ć¾ć‚Œć‚‹
755
+ else if (s.name.toLowerCase().includes(query)) score += 5;
756
+ // ć‚æć‚¤ćƒˆćƒ«ć«å«ć¾ć‚Œć‚‹
757
+ if (s.title.toLowerCase().includes(query)) score += 3;
758
+ // čŖ¬ę˜Žć«å«ć¾ć‚Œć‚‹
759
+ if (s.description.toLowerCase().includes(query)) score += 2;
760
+ // TU ć‚­ćƒ¼ć«å«ć¾ć‚Œć‚‹
761
+ for (const k of s.tuKeys) {
762
+ if (k.toLowerCase().includes(query)) score += 1;
763
+ }
764
+ return { ...s, score };
765
+ })
766
+ .filter((s) => s.score > 0)
767
+ .sort((a, b) => b.score - a.score);
768
+
769
+ console.log(`\nšŸ” "${process.argv.slice(4).join(' ')}" ć®ę¤œē“¢ēµęžœ\n`);
770
+ if (scored.length === 0) {
771
+ console.log('āŒ č©²å½“ć™ć‚‹ć‚¹ć‚­ćƒ«ćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć§ć—ćŸć€‚');
772
+ console.log('');
773
+ console.log('ćƒ’ćƒ³ćƒˆ: č‹±čŖžåļ¼ˆä¾‹: deep-learning, cancer-genomics)や');
774
+ console.log(' ę—„ęœ¬čŖžć‚­ćƒ¼ćƒÆćƒ¼ćƒ‰ļ¼ˆä¾‹: 創薬, ę©Ÿę¢°å­¦ēæ’ļ¼‰ć§ę¤œē“¢ć—ć¦ćæć¦ćć ć•ć„ć€‚');
775
+ } else {
776
+ const top = scored.slice(0, 10);
777
+ for (const s of top) {
778
+ const desc = s.description ? s.description.split('\n')[0].substring(0, 60) : '';
779
+ console.log(` šŸ“– ${s.name}`);
780
+ if (desc) console.log(` ${desc}`);
781
+ console.log('');
782
+ }
783
+ if (scored.length > 10) {
784
+ console.log(` ... 他 ${scored.length - 10} 件`);
785
+ }
786
+ console.log(`合計 ${scored.length} ä»¶ćŒćƒ’ćƒƒćƒˆć—ć¾ć—ćŸć€‚`);
787
+ console.log('詳瓰は `satori skill info <name>` ć§ē¢ŗčŖć§ćć¾ć™ć€‚');
788
+ }
789
+ }
790
+
791
+ function skillInfo() {
792
+ const name = process.argv[4];
793
+ if (!name) {
794
+ console.error('Error: ć‚¹ć‚­ćƒ«åć‚’ęŒ‡å®šć—ć¦ćć ć•ć„ć€‚');
795
+ console.log('Usage: satori skill info <name>');
796
+ console.log('ć‚¹ć‚­ćƒ«ę¤œē“¢ćÆ `satori skill search <query>` ć‚’ä½æć£ć¦ćć ć•ć„ć€‚');
797
+ process.exit(1);
798
+ }
799
+
800
+ const skillsDir = path.join(SOURCE_DIR, 'skills');
801
+ // scientific- ćƒ—ćƒ¬ćƒ•ć‚£ćƒƒć‚Æć‚¹ć‚’č‡Ŗå‹•č£œå®Œ
802
+ const dirName = name.startsWith('scientific-') ? name : `scientific-${name}`;
803
+ const filePath = path.join(skillsDir, dirName, 'SKILL.md');
804
+
805
+ if (!fs.existsSync(filePath)) {
806
+ console.error(`Error: ć‚¹ć‚­ćƒ« "${name}" ćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć€‚`);
807
+ console.log('');
808
+ // éƒØåˆ†äø€č‡“å€™č£œć‚’ęē¤ŗ
809
+ if (fs.existsSync(skillsDir)) {
810
+ const dirs = fs
811
+ .readdirSync(skillsDir)
812
+ .filter((d) => d.startsWith('scientific-') && d.includes(name))
813
+ .slice(0, 5);
814
+ if (dirs.length > 0) {
815
+ console.log('悂恗恋恗恦:');
816
+ for (const d of dirs) {
817
+ console.log(` - ${d.replace('scientific-', '')}`);
818
+ }
819
+ }
820
+ }
821
+ process.exit(1);
822
+ }
823
+
824
+ const content = fs.readFileSync(filePath, 'utf-8');
825
+ const fm = parseFrontmatter(content);
826
+ const h1Match = content.match(/^# (.+)$/m);
827
+ const title = h1Match ? h1Match[1].trim() : dirName;
828
+
829
+ // čŖ¬ę˜ŽęŠ½å‡ŗ
830
+ const descMatch = content.match(/^description:\s*\|?\s*\n([\s\S]*?)(?=\n\w|\n---)/m);
831
+ const description = descMatch ? descMatch[1].replace(/^\s+/gm, '').trim() : '';
832
+
833
+ // When to Use ć‚»ć‚Æć‚·ćƒ§ćƒ³ęŠ½å‡ŗ
834
+ const whenMatch = content.match(/^## When to Use\s*\n([\s\S]*?)(?=\n## )/m);
835
+ const whenToUse = whenMatch ? whenMatch[1].trim() : '';
836
+
837
+ // TU ćƒ„ćƒ¼ćƒ«
838
+ const tuKeyPattern = /`([A-Z][a-zA-Z]*_[a-z]+_[a-z_]+)`/g;
839
+ const tuKeys = new Set();
840
+ for (const m of content.matchAll(tuKeyPattern)) {
841
+ tuKeys.add(m[1]);
842
+ }
843
+
844
+ // tu_tools from frontmatter
845
+ const tuToolMatches = content.match(/^tu_tools:\s*\n([\s\S]*?)(?=\n---|\n[a-z])/m);
846
+ const tuToolNames = [];
847
+ if (tuToolMatches) {
848
+ const toolLines = tuToolMatches[1].matchAll(/name:\s*(.+)/g);
849
+ for (const m of toolLines) {
850
+ tuToolNames.push(m[1].trim());
851
+ }
852
+ }
853
+
854
+ // é–¢é€£ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³
855
+ const shortName = dirName.replace('scientific-', '');
856
+ const relatedPipelines = PIPELINES.filter((p) => p.skills.includes(shortName));
857
+
858
+ console.log(`\nšŸ“– ${title}`);
859
+ console.log(` 名前: ${fm?.name || dirName}`);
860
+ if (description) {
861
+ console.log(` čŖ¬ę˜Ž: ${description}`);
862
+ }
863
+ console.log('');
864
+
865
+ if (whenToUse) {
866
+ console.log('── When to Use ──');
867
+ console.log(whenToUse);
868
+ console.log('');
869
+ }
870
+
871
+ if (tuKeys.size > 0 || tuToolNames.length > 0) {
872
+ console.log('── ToolUniverse 連携 ──');
873
+ if (tuToolNames.length > 0) {
874
+ for (const t of tuToolNames) {
875
+ console.log(` šŸ”§ ${t}`);
876
+ }
877
+ }
878
+ if (tuKeys.size > 0) {
879
+ console.log(` TU ć‚­ćƒ¼: ${[...tuKeys].join(', ')}`);
880
+ }
881
+ console.log('');
882
+ }
883
+
884
+ if (relatedPipelines.length > 0) {
885
+ console.log('── é–¢é€£ćƒ‘ć‚¤ćƒ—ćƒ©ć‚¤ćƒ³ ──');
886
+ for (const p of relatedPipelines.slice(0, 5)) {
887
+ console.log(` šŸ“‹ #${p.id}: ${p.name}`);
888
+ }
889
+ if (relatedPipelines.length > 5) {
890
+ console.log(` ... 他 ${relatedPipelines.length - 5} 件`);
891
+ }
892
+ console.log('');
893
+ }
894
+
895
+ console.log(`ćƒ•ć‚”ć‚¤ćƒ«: src/.github/skills/${dirName}/SKILL.md`);
896
+ }
897
+
187
898
  switch (COMMAND) {
188
899
  case 'init':
189
900
  init();
190
901
  break;
902
+ case 'skill':
903
+ if (SUBCOMMAND === 'search') {
904
+ skillSearch();
905
+ } else if (SUBCOMMAND === 'info') {
906
+ skillInfo();
907
+ } else {
908
+ console.error(`Unknown skill subcommand: ${SUBCOMMAND || '(none)'}`);
909
+ console.log('Usage: satori skill search <query> | satori skill info <name>');
910
+ process.exit(1);
911
+ }
912
+ break;
191
913
  case 'pipeline':
192
914
  if (SUBCOMMAND === 'suggest') {
193
915
  pipelineSuggest();
@@ -199,6 +921,12 @@ switch (COMMAND) {
199
921
  process.exit(1);
200
922
  }
201
923
  break;
924
+ case 'validate':
925
+ validate();
926
+ break;
927
+ case 'stats':
928
+ stats();
929
+ break;
202
930
  case 'help':
203
931
  case '--help':
204
932
  case '-h':