@nahisaho/satori 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +1042 -0
- package/README.md +0 -1
- package/bin/satori.js +320 -18
- package/package.json +1 -1
- package/src/.github/skills/scientific-audit-report/SKILL.md +91 -0
- package/src/.github/skills/scientific-experiment-fork/SKILL.md +69 -0
- package/src/.github/skills/scientific-experiment-template/SKILL.md +85 -0
- package/src/.github/skills/scientific-latex-export/SKILL.md +88 -0
- package/src/.github/skills/scientific-peer-review/SKILL.md +87 -0
package/README.md
CHANGED
|
@@ -1037,6 +1037,5 @@ GitHub Actions で以下の 4 ジョブが `main` ブランチへの push / PR
|
|
|
1037
1037
|
|
|
1038
1038
|
## 参考
|
|
1039
1039
|
|
|
1040
|
-
- [SATORI 使い方ガイド](../../docs/qiita-satori-guide.md)
|
|
1041
1040
|
- [GitHub Copilot Agent Skills ドキュメント](https://docs.github.com/en/copilot/concepts/agents/about-agent-skills)
|
|
1042
1041
|
- [Agent Skills オープン標準](https://github.com/agentskills/agentskills)
|
package/bin/satori.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const fs = require('node:fs');
|
|
4
|
+
const os = require('node:os');
|
|
4
5
|
const path = require('node:path');
|
|
5
6
|
|
|
6
7
|
const COMMAND = process.argv[2];
|
|
@@ -9,6 +10,7 @@ const FLAGS = process.argv.slice(3);
|
|
|
9
10
|
|
|
10
11
|
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
11
12
|
const SOURCE_DIR = path.join(PACKAGE_ROOT, 'src', '.github');
|
|
13
|
+
const CUSTOM_PIPELINES_PATH = path.join(process.env.HOME || os.homedir(), '.satori', 'custom-pipelines.json');
|
|
12
14
|
|
|
13
15
|
function copyDirSync(src, dest) {
|
|
14
16
|
fs.mkdirSync(dest, { recursive: true });
|
|
@@ -77,6 +79,7 @@ Usage:
|
|
|
77
79
|
satori pipeline suggest Interactive pipeline recommendation
|
|
78
80
|
satori pipeline list List all available pipelines
|
|
79
81
|
satori pipeline custom <action> Manage custom pipelines
|
|
82
|
+
satori docs generate [--preview] Generate docs/ and docs/qiita/ files
|
|
80
83
|
satori validate [--verbose] Validate all SKILL.md files
|
|
81
84
|
satori stats Show skill/TU coverage statistics
|
|
82
85
|
satori help Show this help message
|
|
@@ -86,6 +89,7 @@ Options:
|
|
|
86
89
|
--force Overwrite existing .github/ directory
|
|
87
90
|
--dry-run Preview what would be installed without making changes
|
|
88
91
|
--verbose Show detailed validation output
|
|
92
|
+
--preview Show docs generation summary without writing files
|
|
89
93
|
|
|
90
94
|
Custom Pipelines:
|
|
91
95
|
satori pipeline custom list List custom pipelines
|
|
@@ -261,7 +265,8 @@ const PIPELINES = [
|
|
|
261
265
|
name: '実験計画・統計',
|
|
262
266
|
domain: 'general',
|
|
263
267
|
keywords: ['実験計画', 'DOE', '検出力', 'サンプルサイズ'],
|
|
264
|
-
skills:
|
|
268
|
+
skills:
|
|
269
|
+
'experimental-design → experiment-fork → statistical-testing → experiment-template → reproducibility-assessment → publication-figures',
|
|
265
270
|
},
|
|
266
271
|
{
|
|
267
272
|
id: 24,
|
|
@@ -275,7 +280,7 @@ const PIPELINES = [
|
|
|
275
280
|
name: '学術出版',
|
|
276
281
|
domain: 'literature',
|
|
277
282
|
keywords: ['論文投稿', 'journal', 'グラント', 'grant'],
|
|
278
|
-
skills: 'academic-writing → critical-review → citation-network',
|
|
283
|
+
skills: 'academic-writing → peer-review → latex-export → critical-review → citation-network',
|
|
279
284
|
},
|
|
280
285
|
{
|
|
281
286
|
id: 26,
|
|
@@ -306,7 +311,7 @@ const PIPELINES = [
|
|
|
306
311
|
domain: 'cross-domain',
|
|
307
312
|
keywords: ['研究自動化', '論文化', '仮説', 'research automation'],
|
|
308
313
|
skills:
|
|
309
|
-
'deep-research → hypothesis-pipeline → pipeline-scaffold → data-preprocessing → statistical-testing → publication-figures → academic-writing → systematic-review',
|
|
314
|
+
'deep-research → hypothesis-pipeline → experiment-template → pipeline-scaffold → data-preprocessing → statistical-testing → publication-figures → academic-writing → systematic-review',
|
|
310
315
|
},
|
|
311
316
|
{
|
|
312
317
|
id: 'D',
|
|
@@ -370,7 +375,7 @@ const PIPELINES = [
|
|
|
370
375
|
domain: 'cross-domain',
|
|
371
376
|
keywords: ['研究ライフサイクル', 'ラボ自動化', 'LIMS', 'ダッシュボード', 'グラント'],
|
|
372
377
|
skills:
|
|
373
|
-
'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',
|
|
378
|
+
'lab-automation → lab-data-management → streaming-analytics → model-monitoring → data-profiling → advanced-visualization → interactive-dashboard → scientific-schematics → reproducible-reporting → audit-report → paper-quality → peer-review → latex-formatter → latex-export → peer-review-response → grant-writing → preprint-archive',
|
|
374
379
|
},
|
|
375
380
|
{
|
|
376
381
|
id: 'L',
|
|
@@ -394,7 +399,7 @@ const PIPELINES = [
|
|
|
394
399
|
domain: 'cross-domain',
|
|
395
400
|
keywords: ['バリューチェーン', 'EHR', '規制報告', '学術出版', 'HL7'],
|
|
396
401
|
skills:
|
|
397
|
-
'clinical-standards → clinical-nlp → clinical-reporting → healthcare-ai → pharmacovigilance → regulatory-science → reproducible-reporting → paper-quality → latex-formatter → peer-review-response',
|
|
402
|
+
'clinical-standards → clinical-nlp → clinical-reporting → healthcare-ai → pharmacovigilance → regulatory-science → audit-report → reproducible-reporting → paper-quality → latex-formatter → peer-review-response',
|
|
398
403
|
},
|
|
399
404
|
{
|
|
400
405
|
id: 'O',
|
|
@@ -480,6 +485,54 @@ const PIPELINES = [
|
|
|
480
485
|
},
|
|
481
486
|
];
|
|
482
487
|
|
|
488
|
+
// ── Synonym Dictionary ──
|
|
489
|
+
const SYNONYM_DICT = {
|
|
490
|
+
// 機械学習・AI
|
|
491
|
+
ml: ['machine learning', '機械学習', 'ML'],
|
|
492
|
+
ai: ['artificial intelligence', '人工知能', 'AI', 'AI'],
|
|
493
|
+
dl: ['deep learning', '深層学習', 'DL'],
|
|
494
|
+
'neural network': ['NN', 'ニューラルネットワーク'],
|
|
495
|
+
|
|
496
|
+
// バイオインフォマティクス
|
|
497
|
+
bioinfo: ['バイオインフォマティクス', 'bioinformatics'],
|
|
498
|
+
genomics: ['ゲノミクス', 'ゲノム', 'genomics'],
|
|
499
|
+
seq: ['シーケンシング', 'sequencing'],
|
|
500
|
+
rna: ['RNA', 'RNA-seq', 'トランスクリプトーム'],
|
|
501
|
+
protein: ['プロテイン', 'タンパク質'],
|
|
502
|
+
|
|
503
|
+
// 創薬・化学
|
|
504
|
+
'drug discovery': ['創薬', '創薬', 'drug-discovery'],
|
|
505
|
+
admet: ['ADMET', '薬物動態'],
|
|
506
|
+
docking: ['ドッキング', 'molecular docking'],
|
|
507
|
+
cheminformatics: ['ケモインフォマティクス'],
|
|
508
|
+
|
|
509
|
+
// データ分析
|
|
510
|
+
'data analysis': ['データ解析', 'data analysis'],
|
|
511
|
+
statistics: ['統計', '統計学'],
|
|
512
|
+
visualization: ['可視化', 'ビジュアル'],
|
|
513
|
+
pipeline: ['パイプライン'],
|
|
514
|
+
|
|
515
|
+
// 医療・臨床
|
|
516
|
+
clinical: ['臨床', 'クリニカル'],
|
|
517
|
+
precision: ['精密医療', '精密'],
|
|
518
|
+
oncology: ['腫瘍学', 'がん'],
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
function normalizeKeyword(keyword) {
|
|
522
|
+
const lower = keyword.toLowerCase().trim();
|
|
523
|
+
|
|
524
|
+
// 同義語チェック
|
|
525
|
+
for (const [key, synonyms] of Object.entries(SYNONYM_DICT)) {
|
|
526
|
+
for (const syn of synonyms) {
|
|
527
|
+
if (lower.includes(syn.toLowerCase()) || syn.toLowerCase().includes(lower)) {
|
|
528
|
+
return key;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return lower;
|
|
534
|
+
}
|
|
535
|
+
|
|
483
536
|
function pipelineSuggest() {
|
|
484
537
|
const readline = require('node:readline');
|
|
485
538
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -493,15 +546,20 @@ function pipelineSuggest() {
|
|
|
493
546
|
|
|
494
547
|
const input = await ask('何を解析しますか? キーワードや研究テーマを入力してください:\n> ');
|
|
495
548
|
const query = input.toLowerCase();
|
|
549
|
+
const normalizedQuery = normalizeKeyword(query);
|
|
496
550
|
|
|
497
|
-
// Score each pipeline by keyword match
|
|
551
|
+
// Score each pipeline by keyword match (with synonym support)
|
|
498
552
|
const scored = PIPELINES.map((p) => {
|
|
499
553
|
let score = 0;
|
|
500
554
|
for (const kw of p.keywords) {
|
|
555
|
+
const normalizedKw = normalizeKeyword(kw);
|
|
556
|
+
// 完全一致:2点、同義語マッチ:1.5点、部分一致:1点
|
|
501
557
|
if (query.includes(kw.toLowerCase())) score += 2;
|
|
558
|
+
else if (normalizedQuery === normalizedKw) score += 1.5;
|
|
559
|
+
else if (normalizedKw.includes(normalizedQuery) || query.includes(normalizedKw)) score += 1;
|
|
502
560
|
}
|
|
503
561
|
// Partial match on name
|
|
504
|
-
if (query.includes(p.name.toLowerCase()) || p.name.toLowerCase().includes(query)) score +=
|
|
562
|
+
if (query.includes(p.name.toLowerCase()) || p.name.toLowerCase().includes(query)) score += 0.5;
|
|
505
563
|
return { ...p, score };
|
|
506
564
|
})
|
|
507
565
|
.filter((p) => p.score > 0)
|
|
@@ -663,7 +721,7 @@ function validate() {
|
|
|
663
721
|
|
|
664
722
|
// ── Stats ──
|
|
665
723
|
|
|
666
|
-
function
|
|
724
|
+
function collectStats() {
|
|
667
725
|
const skillsDir = path.join(SOURCE_DIR, 'skills');
|
|
668
726
|
|
|
669
727
|
if (!fs.existsSync(skillsDir)) {
|
|
@@ -697,21 +755,142 @@ function stats() {
|
|
|
697
755
|
}
|
|
698
756
|
}
|
|
699
757
|
|
|
700
|
-
const
|
|
758
|
+
const pipelineBreakdown = {
|
|
759
|
+
domain: PIPELINES.filter((p) => typeof p.id === 'number').length,
|
|
760
|
+
cross: PIPELINES.filter((p) => p.domain === 'cross-domain').length,
|
|
761
|
+
industry: PIPELINES.filter((p) => p.domain === 'industry').length,
|
|
762
|
+
methodology: PIPELINES.filter((p) => p.domain === 'methodology').length,
|
|
763
|
+
};
|
|
764
|
+
|
|
701
765
|
const pkg = require(path.join(PACKAGE_ROOT, 'package.json'));
|
|
766
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
767
|
+
const coverage = ((tuLinked / totalSkills) * 100).toFixed(1);
|
|
768
|
+
|
|
769
|
+
return {
|
|
770
|
+
version: pkg.version,
|
|
771
|
+
date,
|
|
772
|
+
totalSkills,
|
|
773
|
+
pipelinesCount: PIPELINES.length,
|
|
774
|
+
pipelineBreakdown,
|
|
775
|
+
tuLinked,
|
|
776
|
+
tuKeysCount: allTuKeys.size,
|
|
777
|
+
totalCodeBlocks,
|
|
778
|
+
coverage,
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
function stats() {
|
|
783
|
+
const summary = collectStats();
|
|
702
784
|
|
|
703
785
|
console.log(`
|
|
704
|
-
📊 SATORI v${
|
|
705
|
-
|
|
706
|
-
スキル総数: ${totalSkills}
|
|
707
|
-
パイプライン数: ${
|
|
708
|
-
TU 連携スキル: ${tuLinked} (${coverage}%)
|
|
709
|
-
TU 未連携: ${totalSkills - tuLinked}
|
|
710
|
-
ユニーク TU キー: ${
|
|
711
|
-
コードブロック総数: ${totalCodeBlocks}
|
|
786
|
+
📊 SATORI v${summary.version} — 統計
|
|
787
|
+
|
|
788
|
+
スキル総数: ${summary.totalSkills}
|
|
789
|
+
パイプライン数: ${summary.pipelinesCount}
|
|
790
|
+
TU 連携スキル: ${summary.tuLinked} (${summary.coverage}%)
|
|
791
|
+
TU 未連携: ${summary.totalSkills - summary.tuLinked}
|
|
792
|
+
ユニーク TU キー: ${summary.tuKeysCount}
|
|
793
|
+
コードブロック総数: ${summary.totalCodeBlocks}
|
|
712
794
|
`);
|
|
713
795
|
}
|
|
714
796
|
|
|
797
|
+
// ── Docs Generate ──
|
|
798
|
+
|
|
799
|
+
function updateReverseIndexDoc(content, summary) {
|
|
800
|
+
const pipelineLine = `| パイプライン数 | **${summary.pipelinesCount}** (ドメイン ${summary.pipelineBreakdown.domain} + クロスドメイン ${summary.pipelineBreakdown.cross} + インダストリー ${summary.pipelineBreakdown.industry} + メソドロジー ${summary.pipelineBreakdown.methodology}) |`;
|
|
801
|
+
|
|
802
|
+
return content
|
|
803
|
+
.replace(/\n\| SATORI バージョン \| \*\*v[^*]+\*\* \|/g, `\n| SATORI バージョン | **v${summary.version}** |`)
|
|
804
|
+
.replace(/\n\| 生成日 \| .* \|/g, `\n| 生成日 | ${summary.date} |`)
|
|
805
|
+
.replace(/\n\| スキル数 \| \*\*\d+\*\* \|/g, `\n| スキル数 | **${summary.totalSkills}** |`)
|
|
806
|
+
.replace(/\n\| パイプライン数 \| .* \|/g, `\n${pipelineLine}`)
|
|
807
|
+
.replace(
|
|
808
|
+
/\n\| ToolUniverse 連携スキル数 \| \*\*\d+\*\* \|/g,
|
|
809
|
+
`\n| ToolUniverse 連携スキル数 | **${summary.tuLinked}** |`,
|
|
810
|
+
)
|
|
811
|
+
.replace(
|
|
812
|
+
/\n\| ToolUniverse キー数(ユニーク) \| \*\*\d+\*\* \|/g,
|
|
813
|
+
`\n| ToolUniverse キー数(ユニーク) | **${summary.tuKeysCount}** |`,
|
|
814
|
+
);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
function updatePipelineExamplesDoc(content, summary) {
|
|
818
|
+
const pipelineLine = `| 掲載パイプライン数 | ${summary.pipelineBreakdown.domain} ドメイン + ${summary.pipelineBreakdown.cross} クロスドメイン + ${summary.pipelineBreakdown.industry} インダストリー + ${summary.pipelineBreakdown.methodology} メソドロジー = **${summary.pipelinesCount}** |`;
|
|
819
|
+
|
|
820
|
+
return content
|
|
821
|
+
.replace(
|
|
822
|
+
/^> \*\*SATORI v[^*]+\*\* — .*$/m,
|
|
823
|
+
`> **SATORI v${summary.version}** — ${summary.totalSkills} スキル + ${summary.pipelinesCount} パイプラインの連携レシピ集`,
|
|
824
|
+
)
|
|
825
|
+
.replace(/\n\| 生成日 \| .* \|/g, `\n| 生成日 | ${summary.date} |`)
|
|
826
|
+
.replace(/\n\| 対象バージョン \| .* \|/g, `\n| 対象バージョン | v${summary.version} |`)
|
|
827
|
+
.replace(/\n\| 掲載パイプライン数 \| .* \|/g, `\n${pipelineLine}`)
|
|
828
|
+
.replace(
|
|
829
|
+
/\n\| スキル総数 \| \d+ \(.*\) \|/g,
|
|
830
|
+
`\n| スキル総数 | ${summary.totalSkills} (\`src/.github/skills/scientific-*/SKILL.md\`) |`,
|
|
831
|
+
)
|
|
832
|
+
.replace(/\n\| ToolUniverse キー数 \| .* \|/g, `\n| ToolUniverse キー数 | ${summary.tuKeysCount} (ユニーク) |`);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
function updateQiitaReverseIndexDoc(content, summary) {
|
|
836
|
+
const title = `title: 【SATORI v${summary.version}】${summary.totalSkills}スキル×${summary.pipelinesCount}パイプライン逆引き辞書 完全索引`;
|
|
837
|
+
const intro = `**[SATORI](https://github.com/nahisaho/satori)** は **GitHub Copilot** 上で動作する、${summary.totalSkills} の専門スキルと ${summary.pipelinesCount} の統合パイプライン(${summary.pipelineBreakdown.domain} ドメイン + ${summary.pipelineBreakdown.cross} クロスドメイン + ${summary.pipelineBreakdown.industry} インダストリー + ${summary.pipelineBreakdown.methodology} メソドロジー)により、仮説構築から論文出版まで、あらゆる科学研究ワークフローを自動化するフレームワークです。`;
|
|
838
|
+
|
|
839
|
+
return content.replace(/^title: .+$/m, title).replace(/^\*\*\[SATORI\][\s\S]*?フレームワークです。$/m, intro);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function updateQiitaPipelineExamplesDoc(content, summary) {
|
|
843
|
+
const title = `title: 【SATORI v${summary.version}】${summary.totalSkills}スキル×${summary.pipelinesCount}パイプラインで実現する科学研究自動化 完全ガイド`;
|
|
844
|
+
const intro = `**[SATORI](https://github.com/nahisaho/satori)** は **GitHub Copilot** 上で動作する、${summary.totalSkills} の専門スキルを組み合わせて構築した ${summary.pipelinesCount} 個のパイプライン(${summary.pipelineBreakdown.domain} ドメイン + ${summary.pipelineBreakdown.cross} クロスドメイン + ${summary.pipelineBreakdown.industry} インダストリー + ${summary.pipelineBreakdown.methodology} メソドロジー)により、仮説構築から論文出版まで、あらゆる科学研究ワークフローを自動化するフレームワークです。`;
|
|
845
|
+
|
|
846
|
+
return content.replace(/^title: .+$/m, title).replace(/^\*\*\[SATORI\][\s\S]*?フレームワークです。$/m, intro);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
function applyDocUpdate(filePath, updater, summary, preview) {
|
|
850
|
+
if (!fs.existsSync(filePath)) {
|
|
851
|
+
console.error(`Error: ドキュメントが見つかりません: ${filePath}`);
|
|
852
|
+
return false;
|
|
853
|
+
}
|
|
854
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
855
|
+
const updated = updater(content, summary);
|
|
856
|
+
if (updated !== content && !preview) {
|
|
857
|
+
fs.writeFileSync(filePath, updated);
|
|
858
|
+
}
|
|
859
|
+
return updated !== content;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
function docsGenerate() {
|
|
863
|
+
const summary = collectStats();
|
|
864
|
+
const docsFlags = process.argv.slice(4);
|
|
865
|
+
const preview = docsFlags.includes('--preview');
|
|
866
|
+
|
|
867
|
+
const targets = [
|
|
868
|
+
{ path: path.join(PACKAGE_ROOT, 'docs', 'SATORI_REVERSE_INDEX.md'), update: updateReverseIndexDoc },
|
|
869
|
+
{ path: path.join(PACKAGE_ROOT, 'docs', 'SATORI_PIPELINE_EXAMPLES.md'), update: updatePipelineExamplesDoc },
|
|
870
|
+
{
|
|
871
|
+
path: path.join(PACKAGE_ROOT, 'docs', 'qiita', 'SATORI_REVERSE_INDEX_QIITA.md'),
|
|
872
|
+
update: updateQiitaReverseIndexDoc,
|
|
873
|
+
},
|
|
874
|
+
{
|
|
875
|
+
path: path.join(PACKAGE_ROOT, 'docs', 'qiita', 'SATORI_PIPELINE_EXAMPLES_QIITA.md'),
|
|
876
|
+
update: updateQiitaPipelineExamplesDoc,
|
|
877
|
+
},
|
|
878
|
+
];
|
|
879
|
+
|
|
880
|
+
let updatedCount = 0;
|
|
881
|
+
for (const target of targets) {
|
|
882
|
+
if (applyDocUpdate(target.path, target.update, summary, preview)) {
|
|
883
|
+
updatedCount++;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
if (preview) {
|
|
888
|
+
console.log(`✔ docs generate (preview) 完了: ${updatedCount} 件更新予定`);
|
|
889
|
+
} else {
|
|
890
|
+
console.log(`✔ docs generate 完了: ${updatedCount} 件更新`);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
715
894
|
// ── Skill Search / Info ──
|
|
716
895
|
|
|
717
896
|
function loadAllSkills() {
|
|
@@ -962,6 +1141,118 @@ function skillRecommend() {
|
|
|
962
1141
|
}
|
|
963
1142
|
}
|
|
964
1143
|
|
|
1144
|
+
// ── Custom Pipeline Management ──
|
|
1145
|
+
|
|
1146
|
+
function loadCustomPipelines() {
|
|
1147
|
+
if (!fs.existsSync(CUSTOM_PIPELINES_PATH)) {
|
|
1148
|
+
return [];
|
|
1149
|
+
}
|
|
1150
|
+
try {
|
|
1151
|
+
const content = fs.readFileSync(CUSTOM_PIPELINES_PATH, 'utf-8');
|
|
1152
|
+
const data = JSON.parse(content);
|
|
1153
|
+
return data.customPipelines || [];
|
|
1154
|
+
} catch (err) {
|
|
1155
|
+
console.error('Warning: Failed to load custom pipelines:', err.message);
|
|
1156
|
+
return [];
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
function saveCustomPipelines(pipelines) {
|
|
1161
|
+
const dir = path.dirname(CUSTOM_PIPELINES_PATH);
|
|
1162
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1163
|
+
fs.writeFileSync(CUSTOM_PIPELINES_PATH, JSON.stringify({ customPipelines: pipelines }, null, 2));
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
function pipelineCustom() {
|
|
1167
|
+
const action = process.argv[4];
|
|
1168
|
+
const customPipelines = loadCustomPipelines();
|
|
1169
|
+
|
|
1170
|
+
if (action === 'list') {
|
|
1171
|
+
listCustomPipelines(customPipelines);
|
|
1172
|
+
} else if (action === 'add') {
|
|
1173
|
+
addCustomPipeline(customPipelines);
|
|
1174
|
+
} else if (action === 'remove') {
|
|
1175
|
+
removeCustomPipeline(customPipelines);
|
|
1176
|
+
} else {
|
|
1177
|
+
console.error(`Unknown custom pipeline action: ${action || '(none)'}`);
|
|
1178
|
+
console.log('Usage: satori pipeline custom list | add <file> | remove <id>');
|
|
1179
|
+
process.exit(1);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
function listCustomPipelines(pipelines) {
|
|
1184
|
+
if (pipelines.length === 0) {
|
|
1185
|
+
console.log('\n📋 カスタムパイプライン: 0 件\n');
|
|
1186
|
+
console.log('新しいカスタムパイプラインを追加するには:');
|
|
1187
|
+
console.log(' satori pipeline custom add <file>');
|
|
1188
|
+
return;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
console.log(`\n📋 カスタムパイプライン一覧 (${pipelines.length} 件)\n`);
|
|
1192
|
+
for (const p of pipelines) {
|
|
1193
|
+
console.log(` 🔧 [${p.id}] ${p.name}`);
|
|
1194
|
+
console.log(` スキル連鎖: ${p.skills}`);
|
|
1195
|
+
console.log('');
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
function addCustomPipeline(pipelines) {
|
|
1200
|
+
const filePath = process.argv[5];
|
|
1201
|
+
if (!filePath) {
|
|
1202
|
+
console.error('Error: ファイルパスを指定してください。');
|
|
1203
|
+
console.log('Usage: satori pipeline custom add <file>');
|
|
1204
|
+
process.exit(1);
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
if (!fs.existsSync(filePath)) {
|
|
1208
|
+
console.error(`Error: ファイルが見つかりません: ${filePath}`);
|
|
1209
|
+
process.exit(1);
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
try {
|
|
1213
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
1214
|
+
const pipelineData = JSON.parse(content);
|
|
1215
|
+
|
|
1216
|
+
// バリデーション
|
|
1217
|
+
if (!pipelineData.id || !pipelineData.name || !pipelineData.skills) {
|
|
1218
|
+
console.error('Error: パイプラインは id, name, skills を含む必要があります。');
|
|
1219
|
+
process.exit(1);
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// 重複チェック
|
|
1223
|
+
if (pipelines.some((p) => p.id === pipelineData.id)) {
|
|
1224
|
+
console.error(`Error: ID "${pipelineData.id}" は既に存在します。`);
|
|
1225
|
+
process.exit(1);
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
pipelines.push(pipelineData);
|
|
1229
|
+
saveCustomPipelines(pipelines);
|
|
1230
|
+
console.log(`✔ カスタムパイプライン "${pipelineData.name}" を追加しました。`);
|
|
1231
|
+
} catch (err) {
|
|
1232
|
+
console.error('Error: パイプラインファイルの解析に失敗しました:', err.message);
|
|
1233
|
+
process.exit(1);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
function removeCustomPipeline(pipelines) {
|
|
1238
|
+
const id = process.argv[5];
|
|
1239
|
+
if (!id) {
|
|
1240
|
+
console.error('Error: パイプライン ID を指定してください。');
|
|
1241
|
+
console.log('Usage: satori pipeline custom remove <id>');
|
|
1242
|
+
process.exit(1);
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
const index = pipelines.findIndex((p) => p.id === id);
|
|
1246
|
+
if (index === -1) {
|
|
1247
|
+
console.error(`Error: パイプライン "${id}" が見つかりません。`);
|
|
1248
|
+
process.exit(1);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
const removed = pipelines.splice(index, 1)[0];
|
|
1252
|
+
saveCustomPipelines(pipelines);
|
|
1253
|
+
console.log(`✔ カスタムパイプライン "${removed.name}" を削除しました。`);
|
|
1254
|
+
}
|
|
1255
|
+
|
|
965
1256
|
switch (COMMAND) {
|
|
966
1257
|
case 'init':
|
|
967
1258
|
init();
|
|
@@ -984,9 +1275,20 @@ switch (COMMAND) {
|
|
|
984
1275
|
pipelineSuggest();
|
|
985
1276
|
} else if (SUBCOMMAND === 'list') {
|
|
986
1277
|
pipelineList();
|
|
1278
|
+
} else if (SUBCOMMAND === 'custom') {
|
|
1279
|
+
pipelineCustom();
|
|
987
1280
|
} else {
|
|
988
1281
|
console.error(`Unknown pipeline subcommand: ${SUBCOMMAND || '(none)'}`);
|
|
989
|
-
console.log('Usage: satori pipeline suggest | satori pipeline list');
|
|
1282
|
+
console.log('Usage: satori pipeline suggest | satori pipeline list | satori pipeline custom list|add|remove');
|
|
1283
|
+
process.exit(1);
|
|
1284
|
+
}
|
|
1285
|
+
break;
|
|
1286
|
+
case 'docs':
|
|
1287
|
+
if (SUBCOMMAND === 'generate') {
|
|
1288
|
+
docsGenerate();
|
|
1289
|
+
} else {
|
|
1290
|
+
console.error(`Unknown docs subcommand: ${SUBCOMMAND || '(none)'}`);
|
|
1291
|
+
console.log('Usage: satori docs generate [--preview]');
|
|
990
1292
|
process.exit(1);
|
|
991
1293
|
}
|
|
992
1294
|
break;
|
package/package.json
CHANGED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scientific-audit-report
|
|
3
|
+
description: |
|
|
4
|
+
実験の監査レポート・データ来歴(プロベナンス)生成スキル。
|
|
5
|
+
データ変換履歴・使用ツールのバージョン・データ整合性チェックを
|
|
6
|
+
含むトレーサビリティレポートを自動生成する。
|
|
7
|
+
「監査レポート作成」「データ来歴を記録」「トレーサビリティ」で発火。
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Scientific Audit Report
|
|
11
|
+
|
|
12
|
+
実験のデータ来歴(プロベナンス)と変更履歴を追跡し、
|
|
13
|
+
規制対応・再現性確保のための監査レポートを生成するスキル。
|
|
14
|
+
|
|
15
|
+
## When to Use
|
|
16
|
+
|
|
17
|
+
- 規制当局への提出用監査証跡が必要なとき
|
|
18
|
+
- GLP / GMP / GCP 準拠のドキュメントを作成するとき
|
|
19
|
+
- データの来歴・変換履歴を記録するとき
|
|
20
|
+
- 実験の再現性を第三者に証明するとき
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### Step 1: 実験ログのスキャン
|
|
25
|
+
- `messages.jsonl` の全エントリを読解
|
|
26
|
+
- `conversation.md` のタイムラインを構築
|
|
27
|
+
- 成果物の作成時刻・変更時刻を記録
|
|
28
|
+
|
|
29
|
+
### Step 2: データ変換の追跡
|
|
30
|
+
- 入力データ → 中間データ → 最終出力のフロー図
|
|
31
|
+
- 各変換ステップで使用したツール・コマンド
|
|
32
|
+
- データ形式の変換記録(CSV → DataFrame → 統計結果)
|
|
33
|
+
|
|
34
|
+
### Step 3: 環境・バージョン情報
|
|
35
|
+
- Python / R / Node.js バージョン
|
|
36
|
+
- 使用ライブラリとバージョン(pip freeze / npm list)
|
|
37
|
+
- OS・コンテナイメージ情報
|
|
38
|
+
- AI モデル・バージョン
|
|
39
|
+
|
|
40
|
+
### Step 4: データ整合性チェック
|
|
41
|
+
- ファイルのチェックサム(SHA-256)
|
|
42
|
+
- 行数・カラム数の検証
|
|
43
|
+
- 欠損値・異常値の記録
|
|
44
|
+
- 入力データと出力データの整合性
|
|
45
|
+
|
|
46
|
+
### Step 5: コンプライアンス確認
|
|
47
|
+
- データ保護(個人情報のマスキング)
|
|
48
|
+
- 倫理審査の承認状況
|
|
49
|
+
- ライセンス・利用規約の準拠
|
|
50
|
+
|
|
51
|
+
## Output Format
|
|
52
|
+
|
|
53
|
+
`audit_report.md`:
|
|
54
|
+
|
|
55
|
+
```markdown
|
|
56
|
+
# 監査レポート
|
|
57
|
+
|
|
58
|
+
## 実験概要
|
|
59
|
+
- 実験ID, 名称, 作成者, 期間
|
|
60
|
+
|
|
61
|
+
## データ来歴(プロベナンス)
|
|
62
|
+
### 入力データ
|
|
63
|
+
### 変換フロー
|
|
64
|
+
### 出力データ
|
|
65
|
+
|
|
66
|
+
## 使用ツール・バージョン
|
|
67
|
+
| ツール | バージョン | 用途 |
|
|
68
|
+
|--------|-----------|------|
|
|
69
|
+
|
|
70
|
+
## データ整合性チェック
|
|
71
|
+
| ファイル | SHA-256 | サイズ | 検証結果 |
|
|
72
|
+
|---------|---------|--------|---------|
|
|
73
|
+
|
|
74
|
+
## タイムライン
|
|
75
|
+
| 時刻 | 操作 | ユーザー |
|
|
76
|
+
|------|------|---------|
|
|
77
|
+
|
|
78
|
+
## コンプライアンス状況
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Examples
|
|
82
|
+
|
|
83
|
+
- 「この実験の監査レポートを作成して」
|
|
84
|
+
- 「データ来歴を記録して」
|
|
85
|
+
- 「GLP準拠のトレーサビリティレポートを生成して」
|
|
86
|
+
|
|
87
|
+
## ToolUniverse 連携
|
|
88
|
+
|
|
89
|
+
| TU Key | ツール名 | 連携内容 |
|
|
90
|
+
|--------|---------|--------|
|
|
91
|
+
| `biotools` | bio.tools | データ来歴追跡・再現性確保ツール検索 |
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scientific-experiment-fork
|
|
3
|
+
description: |
|
|
4
|
+
派生実験設計スキル。既存の実験をベースに条件を変更した派生実験を
|
|
5
|
+
設計する。実験計画法(DOE)に基づくパラメータ探索を支援。
|
|
6
|
+
「派生実験を設計して」「条件を変えて実験」「パラメータ探索」で発火。
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Scientific Experiment Fork
|
|
10
|
+
|
|
11
|
+
既存の実験をベースに、パラメータを変更した派生実験を体系的に設計するスキル。
|
|
12
|
+
実験計画法(DOE: Design of Experiments)に基づく効率的なパラメータ探索を支援。
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- 成功した実験の条件を最適化するとき
|
|
17
|
+
- パラメータ空間を体系的に探索するとき
|
|
18
|
+
- 他のユーザーの実験をベースに発展させるとき
|
|
19
|
+
- 直交表・応答曲面法を適用するとき
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### Step 1: ベース実験の分析
|
|
24
|
+
- 元の実験条件・結果の要約
|
|
25
|
+
- 主要パラメータの特定
|
|
26
|
+
- 成功/失敗の要因分析
|
|
27
|
+
|
|
28
|
+
### Step 2: 変更パラメータの選定
|
|
29
|
+
- 感度分析による重要パラメータの抽出
|
|
30
|
+
- 各パラメータの変動範囲の決定
|
|
31
|
+
- 固定パラメータと変動パラメータの分離
|
|
32
|
+
|
|
33
|
+
### Step 3: 実験計画の設計
|
|
34
|
+
- 完全因子実験 / 部分因子実験
|
|
35
|
+
- 直交表(L8, L16, L27)
|
|
36
|
+
- 応答曲面法(Box-Behnken, CCD)
|
|
37
|
+
- ラテン超方格サンプリング
|
|
38
|
+
|
|
39
|
+
### Step 4: 実験条件マトリクスの生成
|
|
40
|
+
|
|
41
|
+
### Step 5: 期待される結果の予測
|
|
42
|
+
|
|
43
|
+
## Output Format
|
|
44
|
+
|
|
45
|
+
`forked_experiment.md`:
|
|
46
|
+
|
|
47
|
+
```markdown
|
|
48
|
+
# 派生実験計画
|
|
49
|
+
|
|
50
|
+
## ベース実験の要約
|
|
51
|
+
## 変更パラメータ
|
|
52
|
+
## 実験条件マトリクス
|
|
53
|
+
| Run | Param A | Param B | Param C | Expected |
|
|
54
|
+
|-----|---------|---------|---------|----------|
|
|
55
|
+
## 期待される結果
|
|
56
|
+
## 比較・評価計画
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Examples
|
|
60
|
+
|
|
61
|
+
- 「ZnO薄膜の基板温度を200-500°Cで振って派生実験を設計して」
|
|
62
|
+
- 「このPCR条件をベースにアニーリング温度を最適化して」
|
|
63
|
+
- 「薬剤濃度の用量反応曲線実験を設計して」
|
|
64
|
+
|
|
65
|
+
## ToolUniverse 連携
|
|
66
|
+
|
|
67
|
+
| TU Key | ツール名 | 連携内容 |
|
|
68
|
+
|--------|---------|--------|
|
|
69
|
+
| `biotools` | bio.tools | 実験計画法・パラメータ探索ツール検索 |
|