@unlaxer/dge-toolkit 2.1.1 → 2.2.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/bin/dge-tool.js CHANGED
@@ -82,19 +82,112 @@ function cmdVersion() {
82
82
  console.log(`dge-tool v${VERSION}`);
83
83
  }
84
84
 
85
+ function cmdCompare() {
86
+ // Reads two JSON gap lists from stdin and generates comparison table
87
+ // Input format: { "dge": [...gaps], "plain": [...gaps] }
88
+ let input = '';
89
+ process.stdin.setEncoding('utf8');
90
+ process.stdin.on('data', chunk => { input += chunk; });
91
+ process.stdin.on('end', () => {
92
+ try {
93
+ const data = JSON.parse(input);
94
+ const dge = data.dge || [];
95
+ const plain = data.plain || [];
96
+
97
+ // Simple title-based dedup
98
+ const dgeSet = new Set(dge.map(g => g.gap.toLowerCase().trim()));
99
+ const plainSet = new Set(plain.map(g => g.gap.toLowerCase().trim()));
100
+
101
+ const both = [];
102
+ const dgeOnly = [];
103
+ const plainOnly = [];
104
+
105
+ for (const g of dge) {
106
+ const key = g.gap.toLowerCase().trim();
107
+ // Check if any plain gap is similar (substring match or word overlap)
108
+ let found = false;
109
+ for (const p of plain) {
110
+ const pKey = p.gap.toLowerCase().trim();
111
+ // Substring check (works for Japanese)
112
+ const isSubstring = key.includes(pKey) || pKey.includes(key);
113
+ // Word overlap for English
114
+ const gWords = new Set(key.split(/[\s/・、。]+/).filter(w => w.length > 1));
115
+ const pWords = new Set(pKey.split(/[\s/・、。]+/).filter(w => w.length > 1));
116
+ const overlap = [...gWords].filter(w => pWords.has(w)).length;
117
+ const similarity = overlap / Math.min(gWords.size, pWords.size);
118
+ if (isSubstring || similarity > 0.5) {
119
+ both.push({ ...g, source: '両方', plain_match: p.gap });
120
+ found = true;
121
+ plainSet.delete(pKey);
122
+ break;
123
+ }
124
+ }
125
+ if (!found) dgeOnly.push({ ...g, source: 'DGE のみ' });
126
+ }
127
+
128
+ for (const p of plain) {
129
+ const pKey = p.gap.toLowerCase().trim();
130
+ if (plainSet.has(pKey)) {
131
+ plainOnly.push({ ...p, source: '素のみ' });
132
+ }
133
+ }
134
+
135
+ // Stats
136
+ const dgeC = dge.filter(g => g.severity === 'Critical').length;
137
+ const dgeH = dge.filter(g => g.severity === 'High').length;
138
+ const plainC = plain.filter(g => g.severity === 'Critical').length;
139
+ const plainH = plain.filter(g => g.severity === 'High').length;
140
+
141
+ console.log('## マージ結果: DGE + 素の LLM(isolated)');
142
+ console.log('');
143
+ console.log('### 数値比較');
144
+ console.log('| 指標 | DGE | 素の LLM |');
145
+ console.log('|------|-----|---------|');
146
+ console.log(`| Gap 総数 | ${dge.length} | ${plain.length} |`);
147
+ console.log(`| Critical | ${dgeC} | ${plainC} |`);
148
+ console.log(`| High | ${dgeH} | ${plainH} |`);
149
+ console.log('');
150
+ console.log('### Gap 一覧(統合)');
151
+ console.log('| # | Gap | Source | Severity |');
152
+ console.log('|---|-----|--------|----------|');
153
+
154
+ let n = 1;
155
+ for (const g of both) {
156
+ console.log(`| ${n++} | ${g.gap} | 両方 | ${g.severity} |`);
157
+ }
158
+ for (const g of dgeOnly) {
159
+ console.log(`| ${n++} | ${g.gap} | DGE のみ | ${g.severity} |`);
160
+ }
161
+ for (const g of plainOnly) {
162
+ console.log(`| ${n++} | ${g.gap} | 素のみ | ${g.severity} |`);
163
+ }
164
+
165
+ console.log('');
166
+ console.log(`DGE のみ: ${dgeOnly.length} 件(深い洞察)`);
167
+ console.log(`素のみ: ${plainOnly.length} 件(網羅的チェック)`);
168
+ console.log(`両方: ${both.length} 件(確実に重要)`);
169
+ } catch (e) {
170
+ console.error('ERROR: invalid JSON input. Expected: { "dge": [...], "plain": [...] }');
171
+ process.exit(1);
172
+ }
173
+ });
174
+ }
175
+
85
176
  function cmdHelp() {
86
177
  console.log(`dge-tool v${VERSION} — DGE MUST enforcement CLI
87
178
 
88
179
  Commands:
89
180
  save <file> Save stdin to file (ensures MUST: always save)
90
181
  prompt [flow] Show numbered choices from flow YAML (ensures MUST: show choices)
182
+ compare Merge DGE + plain gaps from stdin JSON (isolated comparison)
91
183
  version Show version
92
184
  help Show this help
93
185
 
94
186
  Examples:
95
187
  echo "session content" | dge-tool save dge/sessions/auth-api.md
96
188
  dge-tool prompt quick
97
- dge-tool prompt design-review`);
189
+ dge-tool prompt design-review
190
+ echo '{"dge":[...],"plain":[...]}' | dge-tool compare`);
98
191
  }
99
192
 
100
193
  // Dispatch
@@ -105,6 +198,9 @@ switch (command) {
105
198
  case 'prompt':
106
199
  cmdPrompt();
107
200
  break;
201
+ case 'compare':
202
+ cmdCompare();
203
+ break;
108
204
  case 'version':
109
205
  case '-v':
110
206
  case '--version':
@@ -1,5 +1,6 @@
1
1
  name: brainstorm
2
2
  display_name: "💡 ブレスト — アイデアを発散させる"
3
+ auto_merge: false # ブレストは素のレビュー不要
3
4
 
4
5
  trigger_keywords: ["ブレスト", "brainstorm", "アイデア", "発想"]
5
6
 
@@ -1,5 +1,6 @@
1
1
  name: design-review
2
2
  display_name: "🔍 設計レビュー — 仕様の穴を見つけて Spec に変換"
3
+ auto_merge: true
3
4
 
4
5
  trigger_keywords: ["詳しく", "本格的に", "full", "設計レビュー", "Spec"]
5
6
 
package/flows/quick.yaml CHANGED
@@ -1,5 +1,6 @@
1
1
  name: quick
2
2
  display_name: "⚡ クイック — 会話劇で Gap を見つける"
3
+ auto_merge: true # 素の LLM レビューを自動でバックグラウンド実行。false で無効化
3
4
 
4
5
  trigger_keywords: ["DGE して", "DGE", "壁打ち", "gap を探して"]
5
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unlaxer/dge-toolkit",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "DGE (Dialogue-driven Gap Extraction) — 会話劇で設計の穴を発見するメソッドkit",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -59,6 +59,8 @@ built-in + カスタムキャラを統合表示。
59
59
  ### Step 5: 会話劇生成(全 flow 共通)
60
60
  - flow の extract.marker を使う(デフォルト: `→ Gap 発見:`、brainstorm: `→ アイデア:`)
61
61
  - 先輩(ナレーション)で背景設定 → キャラ対話 → マーカー挿入
62
+ - **auto_merge が true(デフォルト)の場合**: 会話劇生成と同時に、バックグラウンドで isolated subagent を起動して素の LLM レビューを開始する。subagent は `isolation: "worktree"` で DGE の context を持たない。会話劇が終わる頃には素のレビューも完了している。
63
+ - auto_merge を OFF にしたい場合: 「マージなしで DGE して」と指示するか、flow YAML で `auto_merge: false` を設定
62
64
 
63
65
  ### Step 6: 構造化(flow による)
64
66
  - quick / design-review: Gap に Category + Severity を付与
@@ -84,29 +86,39 @@ flow の output_dir に保存(デフォルト: `dge/sessions/`)。
84
86
 
85
87
  **Flow**: [flow 名]
86
88
  **テーマ**: [テーマ]
87
- **Gap/アイデア数**: N 件
88
89
 
89
- | # | Gap/Idea | Severity |
90
- |---|---------|----------|
90
+ ### DGE の発見
91
+ **Gap 数**: N 件(Critical: X / High: X / Medium: X)
92
+
93
+ | # | Gap | Severity |
94
+ |---|-----|----------|
91
95
  (主要なものを表示)
92
96
 
97
+ ### 素の LLM の発見(auto_merge ON の場合)
98
+ **Gap 数**: N 件(isolated subagent による独立レビュー)
99
+
100
+ ### マージ結果(auto_merge ON の場合)
101
+ | # | Gap | Source | Severity |
102
+ |---|-----|--------|----------|
103
+ | 1 | ... | DGE のみ | High |
104
+ | 2 | ... | 両方 | Critical |
105
+ | 3 | ... | 素のみ | Medium |
106
+
107
+ DGE のみ: N 件(深い洞察) / 素のみ: N 件(網羅的) / 両方: N 件(確実に重要)
108
+
93
109
  **全文**: `[ファイルパス]`
94
110
  ```
95
111
 
96
- **Tool mode**: Bash で実行:
97
- ```
98
- dge-tool prompt <flow>
99
- ```
100
- → 番号付き選択肢が返る。そのまま表示。失敗したらデフォルト選択肢でフォールバック。
112
+ auto_merge OFF の場合はマージ結果を省略し、DGE の発見のみ表示。
101
113
 
102
- **Skill mode**: 選択肢は flow YAML の post_actions から表示。YAML がない場合のデフォルト:
114
+ 選択肢は flow YAML の post_actions から表示。デフォルト:
103
115
  ```
104
116
  1. DGE を回す
105
117
  2. 実装できるまで回す
106
118
  3. 実装する
107
- 4. 素の LLM でも回してマージ
108
- 5. 後で
119
+ 4. 後で
109
120
  ```
121
+ auto_merge OFF の場合のみ追加: `5. 素の LLM でも回してマージ`
110
122
 
111
123
  **ユーザーの応答を待つ。**
112
124
 
@@ -133,8 +145,62 @@ flow YAML の post_actions の id に応じて分岐:
133
145
  ### Step 9B: 前回コンテキスト + プロジェクトナビゲーション
134
146
  プロジェクトファイルがあれば TreeView 表示。なければ前回サマリー + 3 択。
135
147
 
136
- ### Step 9C: 素の LLM マージ
137
- subagent で同じテーマを素でレビュー → DGE Gap とマージ → DGE のみ / 素のみ / 両方 をラベル付け。
148
+ ### Step 9C: 素の LLM マージ(isolated subagent)
149
+
150
+ **重要: DGE の結果を知らない独立した agent で素のレビューを行う。** これにより DGE の Gap を「補完する」バイアスを排除する。
151
+
152
+ 1. **isolated subagent を起動**: Agent ツールで `isolation: "worktree"` を指定。
153
+ DGE session の context を一切持たない別プロセスが実行する。
154
+
155
+ subagent へのプロンプト:
156
+ ```
157
+ 以下の設計ドキュメントをレビューしてください。
158
+ 問題点、考慮漏れ、矛盾を全て挙げてください。
159
+ 各問題に Category と Severity (Critical / High / Medium / Low) をつけてください。
160
+ テーブル形式で出力: | # | Gap | Category | Severity |
161
+
162
+ [テーマの設計ドキュメント / コンテキスト]
163
+ ```
164
+
165
+ **subagent には DGE の Gap 一覧や会話劇を渡さない。** 完全に独立したレビュー。
166
+
167
+ 2. **素の Gap 一覧を受け取る**
168
+
169
+ 3. **DGE の Gap と素の Gap をマージ**:
170
+ - Gap タイトルの意味的類似度で重複を判定
171
+ - 同じ問題 → 「両方」ラベル(信頼度が高い)
172
+ - DGE のみ → 「DGE のみ」ラベル(深い洞察の可能性)
173
+ - 素のみ → 「素のみ」ラベル(網羅的チェック)
174
+
175
+ 4. **比較表を表示**:
176
+ ```
177
+ ## マージ結果: DGE + 素の LLM(isolated)
178
+
179
+ ### 数値比較
180
+ | 指標 | DGE | 素の LLM |
181
+ |------|-----|---------|
182
+ | Gap 総数 | N | N |
183
+ | Critical | N | N |
184
+ | High | N | N |
185
+ | カテゴリ数 | N/11 | N/11 |
186
+
187
+ ### Gap 一覧(統合)
188
+ | # | Gap | Source | Severity |
189
+ |---|-----|--------|----------|
190
+ | 1 | [gap] | DGE のみ | High |
191
+ | 2 | [gap] | 両方 | Critical |
192
+ | 3 | [gap] | 素のみ | Medium |
193
+
194
+ DGE のみ: N 件(深い洞察)
195
+ 素のみ: N 件(網羅的チェック)
196
+ 両方: N 件(確実に重要)
197
+
198
+ どうしますか?
199
+ 1. 実装する → マージ済み Gap から Spec 化
200
+ 2. 後で
201
+ ```
202
+
203
+ 5. **マージ結果をファイルに保存**: `dge/sessions/{theme}-merged.md`
138
204
 
139
205
  ### Step 10: 累積 Spec 化(design-review のみ)
140
206
  同テーマの全 session Gap を統合 → Critical/High を Spec 化 → `dge/specs/` に保存。
package/version.txt CHANGED
@@ -1 +1 @@
1
- 2.1.1
1
+ 2.2.0