@nahisaho/shikigami 1.27.0 → 1.28.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/AGENTS.md CHANGED
@@ -13,6 +13,9 @@
13
13
  > **🚨 警告2**: search/visitツールを実行したら、**必ず `save_research` MCPツールを呼び出すこと**。
14
14
  > 保存しないと**research/ディレクトリに記録が残らない**。詳細は「4.2 リサーチ結果永続化ルール」参照。
15
15
 
16
+ > **🚨 警告3(v1.28.0)**: ユーザーの入力を受け取ったら、**必ず `save_prompt` MCPツールを呼び出すこと**。
17
+ > 最初のプロンプトだけでなく、**すべての回答・指示・フィードバックを保存する**。詳細は「4.1 プロンプト保存ルール」参照。
18
+
16
19
  ### 正しい実行順序(必ず守ること)
17
20
 
18
21
  ```
@@ -56,6 +59,8 @@
56
59
  | **search後にsave_researchを呼ばない** | **research/に保存されない** |
57
60
  | **visit後にsave_researchを呼ばない** | **research/に保存されない** |
58
61
  | **set_projectを呼ばずに調査開始** | **保存先が不明になる** |
62
+ | **ユーザー入力後にsave_promptを呼ばない** | **prompts/に会話が残らない** |
63
+ | **最初のプロンプトのみ保存する** | **後続の重要な対話が失われる** |
59
64
 
60
65
  ### ✅ 正しい応答例
61
66
 
@@ -259,56 +264,109 @@ Phase 5: Completion(完了)
259
264
 
260
265
  **禁止**: `research/` に最終レポートを保存、`reports/` に調査メモを保存
261
266
 
262
- ### 4.1 プロンプト保存ルール(v1.22.0 NEW!)
267
+ ### 4.1 プロンプト保存ルール(v1.28.0 Updated!)
268
+
269
+ > **🚨 重要**: ユーザーが入力した**すべてのプロンプト・回答・指示**を `prompts/` ディレクトリに保存すること。
270
+ > **最初のプロンプトだけでなく、セッション中のすべてのユーザー入力を記録する。**
263
271
 
264
- ユーザーが入力したプロンプトは `prompts/` ディレクトリに自動保存されます。
272
+ #### ⚠️ 保存対象(v1.28.0 拡張)
265
273
 
266
- | ファイル | 内容 | 保存タイミング |
274
+ | 保存対象 | 説明 | 保存タイミング |
267
275
  |---------|------|--------------|
268
- | `original-prompt.md` | ユーザーの元の入力プロンプト | Phase 0.5開始時 |
269
- | `structured-prompt.md` | 6要素に構造化されたプロンプト | Phase 0.5完了時(承認後) |
270
- | `refinement-history.md` | 修正履歴(修正があった場合) | 修正のたびに追記 |
276
+ | **初回プロンプト** | リサーチ依頼の最初の入力 | Phase 0.5開始時 |
277
+ | **質問への回答** | Phase 1の1問1答での回答 | **回答を受け取るたび** |
278
+ | **修正指示** | 構造化プロンプトの修正要求 | **修正指示を受け取るたび** |
279
+ | **追加指示** | 調査中の追加要求・方向転換 | **追加指示を受け取るたび** |
280
+ | **フィードバック** | レポートへの修正要求 | **フィードバックを受け取るたび** |
281
+ | **承認・確認** | 「はい」「OK」などの承認 | **承認を受け取るたび** |
282
+
283
+ #### ⛔ 禁止行動
284
+
285
+ | 禁止行動 | 理由 |
286
+ |---------|------|
287
+ | 初回プロンプトのみ保存 | 後続の重要な対話が失われる |
288
+ | 回答を記録せずに次に進む | ナレッジの散逸 |
289
+ | save_promptを呼ばずに会話を続ける | prompts/に記録が残らない |
290
+
291
+ #### ✅ 必須フロー(v1.28.0)
292
+
293
+ ```
294
+ ┌─────────────────────────────────────────────────────────────┐
295
+ │ ユーザー入力を受け取るたびに: │
296
+ │ │
297
+ │ 1. save_prompt MCPツールを呼び出す │
298
+ │ {"tool":"save_prompt","arguments":{ │
299
+ │ "content":"ユーザーの入力内容", │
300
+ │ "type":"answer" | "instruction" | "feedback" | "approval"│
301
+ │ }} │
302
+ │ │
303
+ │ 2. 処理を続行 │
304
+ └─────────────────────────────────────────────────────────────┘
305
+ ```
306
+
307
+ #### save_prompt の type パラメータ
308
+
309
+ | type | 用途 | ファイル名例 |
310
+ |------|------|-------------|
311
+ | `"original"` | 最初のリサーチ依頼 | `prompt_original_20260127_100000.md` |
312
+ | `"structured"` | 構造化プロンプト(AI生成) | `prompt_structured_20260127_100500.md` |
313
+ | `"answer"` | 質問への回答 | `prompt_answer_20260127_101000.md` |
314
+ | `"instruction"` | 追加指示・修正要求 | `prompt_instruction_20260127_102000.md` |
315
+ | `"feedback"` | レポートへのフィードバック | `prompt_feedback_20260127_150000.md` |
316
+ | `"approval"` | 承認・確認 | `prompt_approval_20260127_101500.md` |
317
+
318
+ #### 保存ファイルフォーマット
271
319
 
272
- **フォーマット(original-prompt.md)**:
273
320
  ```markdown
274
321
  ---
275
- timestamp: "2026-01-27T10:00:00+09:00"
322
+ timestamp: "2026-01-27T10:10:00+09:00"
276
323
  project_id: "pj00001"
324
+ type: "answer"
325
+ phase: "1"
326
+ sequence: 3
277
327
  ---
278
328
 
279
- # Original Prompt
329
+ # User Input
280
330
 
281
- [ユーザーの入力プロンプトをそのまま記録]
331
+ [ユーザーの入力内容をそのまま記録]
332
+
333
+ ## Context
334
+
335
+ - Previous question: [AIが聞いた質問]
336
+ - Phase: 1 (Purpose Discovery)
282
337
  ```
283
338
 
284
- **フォーマット(structured-prompt.md)**:
339
+ #### 会話ログの一元管理
340
+
341
+ すべてのプロンプトは `prompts/conversation-log.md` にも追記されます:
342
+
285
343
  ```markdown
286
- ---
287
- timestamp: "2026-01-27T10:05:00+09:00"
288
- project_id: "pj00001"
289
- version: 1
290
- approved: true
291
- ---
344
+ # Conversation Log
345
+
346
+ ## Session: 2026-01-27
347
+
348
+ ### [10:00:00] User (original)
349
+ レアメタルについて調べて
292
350
 
293
- # Structured Prompt
351
+ ### [10:05:00] AI (structured)
352
+ [構造化プロンプトを表示]
294
353
 
295
- ## PURPOSE(目的)
296
- [内容]
354
+ ### [10:06:00] User (approval)
355
+ はい、それでお願いします
297
356
 
298
- ## TARGET(調査対象)
299
- [内容]
357
+ ### [10:07:00] AI (question)
358
+ この調査結果は誰が使いますか?
300
359
 
301
- ## SCOPE(調査範囲)
302
- [内容]
360
+ ### [10:08:00] User (answer)
361
+ 経営会議で使います
303
362
 
304
- ## TIMELINE(時間軸)
305
- [内容]
363
+ ### [10:09:00] AI (question)
364
+ いつまでに必要ですか?
306
365
 
307
- ## CONSTRAINTS(制約条件)
308
- [内容]
366
+ ### [10:10:00] User (answer)
367
+ 来週の金曜日までに
309
368
 
310
- ## DELIVERABLES(期待する成果物)
311
- [内容]
369
+ ...
312
370
  ```
313
371
 
314
372
  ### 4.2 ⛔⛔⛔ リサーチ結果永続化ルール(v1.27.0 必須)⛔⛔⛔
package/CHANGELOG.md CHANGED
@@ -5,6 +5,62 @@ All notable changes to SHIKIGAMI will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.28.0] - 2026-01-27
9
+
10
+ ### Fixed
11
+
12
+ - **最初のプロンプトのみが保存される問題を修正**
13
+ - 問題: Phase 0.5の初回プロンプトだけが保存され、その後の回答・指示・フィードバックが保存されない
14
+ - 原因: save_promptのtypeが`original`, `structured`, `refinement`の3種のみだった
15
+ - 対策: 4つの新しいtypeを追加し、全てのユーザー入力を保存可能に
16
+
17
+ ### Added
18
+
19
+ - **save_prompt MCPツールの拡張**
20
+ - 新しいtypeパラメータ:
21
+ - `answer`: 質問への回答
22
+ - `instruction`: 追加指示・修正要求
23
+ - `feedback`: レポートへのフィードバック
24
+ - `approval`: 承認・確認
25
+ - 新しいパラメータ:
26
+ - `phase`: 現在のフェーズ(0, 0.5, 1, 2, 3, 4, 5)
27
+ - `sequence`: セッション内の連番
28
+ - `context`: コンテキスト情報(前の質問など)
29
+
30
+ - **会話ログ機能(conversation-log.md)**
31
+ - 全てのプロンプトを`prompts/conversation-log.md`に自動追記
32
+ - タイムスタンプ付きの時系列記録
33
+ - User/AIの役割とtypeを明記
34
+
35
+ - **AGENTS.md: 「最重要ルール」セクション強化**
36
+ - 警告3を追加: 「ユーザー入力を受け取ったら必ずsave_promptを呼ぶこと」
37
+ - 禁止行動パターンに2項目追加
38
+
39
+ - **AGENTS.md: 「4.1 プロンプト保存ルール」セクション全面更新**
40
+ - 保存対象表に6種類の入力タイプを追加
41
+ - 禁止行動セクション追加
42
+ - 必須フロー図解追加
43
+ - save_promptのtypeパラメータ表追加
44
+ - 保存ファイルフォーマット追加
45
+ - 会話ログの例追加
46
+
47
+ ### Changed
48
+
49
+ - **ファイル命名規則の統一**
50
+ - 旧: `original-prompt_YYYYMMDD_HHMMSS.md`
51
+ - 新: `prompt_original_YYYYMMDD_HHMMSS.md`
52
+ - 全typeで`prompt_<type>_<date>_<time>.md`形式に統一
53
+
54
+ - **プロンプト保存の必須化**
55
+ ```
56
+ ユーザー入力を受け取るたびに:
57
+ 1. save_prompt MCPツールを呼び出す
58
+ 2. 適切なtypeを指定 (answer/instruction/feedback/approval)
59
+ 3. 処理を続行
60
+ ```
61
+
62
+ ---
63
+
8
64
  ## [1.27.0] - 2026-01-27
9
65
 
10
66
  ### Fixed
@@ -77,19 +77,27 @@ save_prompt, save_researchの前に必ず実行。
77
77
  {
78
78
  name: 'save_prompt',
79
79
  description: `プロンプトをプロジェクトのprompts/ディレクトリに保存。
80
- 元のプロンプト、構造化プロンプト、修正履歴を記録。
80
+ v1.28.0: 最初のプロンプトだけでなく、すべてのユーザー入力(回答・指示・フィードバック)を保存。
81
+ ユーザーから入力を受け取るたびに必ず呼び出すこと。
81
82
  set_projectでプロジェクトを設定してから使用。`,
82
83
  inputSchema: {
83
84
  type: 'object',
84
85
  properties: {
85
86
  content: {
86
87
  type: 'string',
87
- description: '保存するプロンプト内容',
88
+ description: '保存するプロンプト/ユーザー入力の内容',
88
89
  },
89
90
  type: {
90
91
  type: 'string',
91
- enum: ['original', 'structured', 'refinement'],
92
- description: 'プロンプトの種類(original: 元のプロンプト, structured: 構造化後, refinement: 修正)',
92
+ enum: ['original', 'structured', 'refinement', 'answer', 'instruction', 'feedback', 'approval'],
93
+ description: `入力の種類:
94
+ - original: 最初のリサーチ依頼
95
+ - structured: 構造化プロンプト(AI生成)
96
+ - refinement: 構造化プロンプトの修正
97
+ - answer: 質問への回答(v1.28.0)
98
+ - instruction: 追加指示・修正要求(v1.28.0)
99
+ - feedback: レポートへのフィードバック(v1.28.0)
100
+ - approval: 承認・確認(v1.28.0)`,
93
101
  },
94
102
  filename: {
95
103
  type: 'string',
@@ -99,6 +107,18 @@ set_projectでプロジェクトを設定してから使用。`,
99
107
  type: 'number',
100
108
  description: '修正バージョン番号(refinementタイプの場合)',
101
109
  },
110
+ phase: {
111
+ type: 'string',
112
+ description: '現在のフェーズ(0, 0.5, 1, 2, 3, 4, 5)',
113
+ },
114
+ sequence: {
115
+ type: 'number',
116
+ description: 'セッション内の連番',
117
+ },
118
+ context: {
119
+ type: 'string',
120
+ description: 'コンテキスト情報(前の質問など)',
121
+ },
102
122
  metadata: {
103
123
  type: 'object',
104
124
  description: '追加のメタデータ',
@@ -435,15 +455,21 @@ server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest)
435
455
 
436
456
  case 'save_prompt': {
437
457
  const content = args?.content as string;
438
- const type = args?.type as 'original' | 'structured' | 'refinement';
458
+ const type = args?.type as 'original' | 'structured' | 'refinement' | 'answer' | 'instruction' | 'feedback' | 'approval';
439
459
  const filename = args?.filename as string | undefined;
440
460
  const version = args?.version as number | undefined;
461
+ const phase = args?.phase as string | undefined;
462
+ const sequence = args?.sequence as number | undefined;
463
+ const context = args?.context as string | undefined;
441
464
  const metadata = args?.metadata as Record<string, unknown> | undefined;
442
465
 
443
466
  const result = await savePrompt(content, {
444
467
  type,
445
468
  filename,
446
469
  version,
470
+ phase,
471
+ sequence,
472
+ context,
447
473
  metadata,
448
474
  });
449
475
 
@@ -70,7 +70,7 @@ describe('Save Module', () => {
70
70
 
71
71
  expect(result.success).toBe(true);
72
72
  expect(result.filePath).toContain('prompts');
73
- expect(result.filePath).toContain('original-prompt');
73
+ expect(result.filePath).toContain('prompt_original');
74
74
  expect(fs.writeFileSync).toHaveBeenCalled();
75
75
 
76
76
  // Check content includes frontmatter
@@ -88,7 +88,7 @@ describe('Save Module', () => {
88
88
  });
89
89
 
90
90
  expect(result.success).toBe(true);
91
- expect(result.filePath).toContain('structured-prompt');
91
+ expect(result.filePath).toContain('prompt_structured');
92
92
 
93
93
  const writeCall = vi.mocked(fs.writeFileSync).mock.calls[0];
94
94
  const content = writeCall[1] as string;
@@ -102,13 +102,70 @@ describe('Save Module', () => {
102
102
  });
103
103
 
104
104
  expect(result.success).toBe(true);
105
- expect(result.filePath).toContain('refinement-2');
105
+ expect(result.filePath).toContain('prompt_refinement-2');
106
106
 
107
107
  const writeCall = vi.mocked(fs.writeFileSync).mock.calls[0];
108
108
  const content = writeCall[1] as string;
109
109
  expect(content).toContain('version: 2');
110
110
  });
111
111
 
112
+ it('should save answer type (v1.28.0)', async () => {
113
+ const result = await savePrompt('User answer', {
114
+ type: 'answer',
115
+ phase: '1',
116
+ sequence: 3,
117
+ });
118
+
119
+ expect(result.success).toBe(true);
120
+ expect(result.filePath).toContain('prompt_answer');
121
+
122
+ const writeCall = vi.mocked(fs.writeFileSync).mock.calls[0];
123
+ const content = writeCall[1] as string;
124
+ expect(content).toContain('type: "answer"');
125
+ expect(content).toContain('phase: "1"');
126
+ expect(content).toContain('sequence: 3');
127
+ });
128
+
129
+ it('should save instruction type (v1.28.0)', async () => {
130
+ const result = await savePrompt('Additional instruction', {
131
+ type: 'instruction',
132
+ });
133
+
134
+ expect(result.success).toBe(true);
135
+ expect(result.filePath).toContain('prompt_instruction');
136
+ });
137
+
138
+ it('should save feedback type (v1.28.0)', async () => {
139
+ const result = await savePrompt('Report feedback', {
140
+ type: 'feedback',
141
+ });
142
+
143
+ expect(result.success).toBe(true);
144
+ expect(result.filePath).toContain('prompt_feedback');
145
+ });
146
+
147
+ it('should save approval type (v1.28.0)', async () => {
148
+ const result = await savePrompt('Yes, approved', {
149
+ type: 'approval',
150
+ });
151
+
152
+ expect(result.success).toBe(true);
153
+ expect(result.filePath).toContain('prompt_approval');
154
+ });
155
+
156
+ it('should include context when provided (v1.28.0)', async () => {
157
+ const result = await savePrompt('User answer', {
158
+ type: 'answer',
159
+ context: 'Previous question: What is the purpose?',
160
+ });
161
+
162
+ expect(result.success).toBe(true);
163
+ const writeCall = vi.mocked(fs.writeFileSync).mock.calls[0];
164
+ const content = writeCall[1] as string;
165
+ expect(content).toContain('## Context');
166
+ expect(content).toContain('Previous question: What is the purpose?');
167
+ });
168
+
112
169
  it('should use custom filename when provided', async () => {
113
170
  const result = await savePrompt('Content', {
114
171
  type: 'original',
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * File Save Module
3
- * v1.23.0 - REQ-SHIKIGAMI-016: プロンプト・検索結果の永続化
3
+ * v1.28.0 - REQ-SHIKIGAMI-016: プロンプト・検索結果の永続化
4
4
  *
5
5
  * プロンプトをprompts/に、検索結果をresearch/に保存する機能
6
+ * v1.28.0: すべてのユーザー入力(回答・指示・フィードバック)を保存
6
7
  */
7
8
 
8
9
  import * as fs from 'fs';
@@ -17,11 +18,14 @@ export interface SaveResult {
17
18
  timestamp: string;
18
19
  }
19
20
 
20
- // プロンプト保存オプション
21
+ // プロンプト保存オプション(v1.28.0 拡張)
21
22
  export interface SavePromptOptions {
22
23
  filename?: string;
23
- type: 'original' | 'structured' | 'refinement';
24
+ type: 'original' | 'structured' | 'refinement' | 'answer' | 'instruction' | 'feedback' | 'approval';
24
25
  version?: number;
26
+ phase?: string;
27
+ sequence?: number;
28
+ context?: string;
25
29
  metadata?: Record<string, unknown>;
26
30
  }
27
31
 
@@ -87,13 +91,25 @@ export async function savePrompt(
87
91
  } else {
88
92
  switch (options.type) {
89
93
  case 'original':
90
- filename = `original-prompt_${dateStr}_${timeStr}.md`;
94
+ filename = `prompt_original_${dateStr}_${timeStr}.md`;
91
95
  break;
92
96
  case 'structured':
93
- filename = `structured-prompt_${dateStr}_${timeStr}.md`;
97
+ filename = `prompt_structured_${dateStr}_${timeStr}.md`;
94
98
  break;
95
99
  case 'refinement':
96
- filename = `refinement-${options.version || 1}_${dateStr}_${timeStr}.md`;
100
+ filename = `prompt_refinement-${options.version || 1}_${dateStr}_${timeStr}.md`;
101
+ break;
102
+ case 'answer':
103
+ filename = `prompt_answer_${dateStr}_${timeStr}.md`;
104
+ break;
105
+ case 'instruction':
106
+ filename = `prompt_instruction_${dateStr}_${timeStr}.md`;
107
+ break;
108
+ case 'feedback':
109
+ filename = `prompt_feedback_${dateStr}_${timeStr}.md`;
110
+ break;
111
+ case 'approval':
112
+ filename = `prompt_approval_${dateStr}_${timeStr}.md`;
97
113
  break;
98
114
  default:
99
115
  filename = `prompt_${dateStr}_${timeStr}.md`;
@@ -106,22 +122,28 @@ export async function savePrompt(
106
122
  project_id: project.projectId,
107
123
  type: options.type,
108
124
  ...(options.version && { version: options.version }),
125
+ ...(options.phase && { phase: options.phase }),
126
+ ...(options.sequence && { sequence: options.sequence }),
109
127
  ...(options.metadata && { metadata: options.metadata }),
110
128
  };
111
129
 
112
130
  const fullContent = `---
113
131
  timestamp: "${frontmatter.timestamp}"
114
132
  project_id: "${frontmatter.project_id}"
115
- type: "${frontmatter.type}"${frontmatter.version ? `\nversion: ${frontmatter.version}` : ''}
133
+ type: "${frontmatter.type}"${frontmatter.version ? `\nversion: ${frontmatter.version}` : ''}${frontmatter.phase ? `\nphase: "${frontmatter.phase}"` : ''}${frontmatter.sequence ? `\nsequence: ${frontmatter.sequence}` : ''}
116
134
  ---
117
135
 
118
136
  ${content}
119
- `;
137
+ ${options.context ? `\n## Context\n\n${options.context}\n` : ''}`;
120
138
 
121
139
  const filePath = path.join(project.promptsDir, filename);
122
140
 
123
141
  try {
124
142
  fs.writeFileSync(filePath, fullContent, 'utf-8');
143
+
144
+ // 会話ログにも追記(v1.28.0)
145
+ await appendToConversationLog(project.promptsDir, content, options.type, timestamp);
146
+
125
147
  return {
126
148
  success: true,
127
149
  filePath,
@@ -134,6 +156,37 @@ ${content}
134
156
  }
135
157
  }
136
158
 
159
+ /**
160
+ * 会話ログに追記(v1.28.0)
161
+ */
162
+ async function appendToConversationLog(
163
+ promptsDir: string,
164
+ content: string,
165
+ type: string,
166
+ timestamp: string
167
+ ): Promise<void> {
168
+ const logPath = path.join(promptsDir, 'conversation-log.md');
169
+ const time = timestamp.split('T')[1].split('.')[0];
170
+ const date = timestamp.split('T')[0];
171
+
172
+ // ログファイルが存在しない場合はヘッダーを作成
173
+ let logContent = '';
174
+ if (!fs.existsSync(logPath)) {
175
+ logContent = `# Conversation Log\n\n## Session: ${date}\n\n`;
176
+ }
177
+
178
+ // エントリを追加
179
+ const role = type === 'structured' ? 'AI' : 'User';
180
+ logContent += `### [${time}] ${role} (${type})\n\n${content}\n\n---\n\n`;
181
+
182
+ try {
183
+ fs.appendFileSync(logPath, logContent, 'utf-8');
184
+ } catch {
185
+ // ログ追記失敗は警告のみ(メイン処理は継続)
186
+ console.warn(`Warning: Failed to append to conversation log`);
187
+ }
188
+ }
189
+
137
190
  /**
138
191
  * 検索結果を保存
139
192
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nahisaho/shikigami",
3
- "version": "1.27.0",
3
+ "version": "1.28.0",
4
4
  "description": "GitHub Copilot Agent Skills for Deep Research & Consulting - AI-Powered Research Assistant with 50+ Consulting Frameworks",
5
5
  "keywords": [
6
6
  "github-copilot",