@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 +88 -30
- package/CHANGELOG.md +56 -0
- package/mcp-server/src/index.ts +31 -5
- package/mcp-server/src/tools/__tests__/save.test.ts +60 -3
- package/mcp-server/src/tools/save.ts +61 -8
- package/package.json +1 -1
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.
|
|
267
|
+
### 4.1 プロンプト保存ルール(v1.28.0 Updated!)
|
|
268
|
+
|
|
269
|
+
> **🚨 重要**: ユーザーが入力した**すべてのプロンプト・回答・指示**を `prompts/` ディレクトリに保存すること。
|
|
270
|
+
> **最初のプロンプトだけでなく、セッション中のすべてのユーザー入力を記録する。**
|
|
263
271
|
|
|
264
|
-
|
|
272
|
+
#### ⚠️ 保存対象(v1.28.0 拡張)
|
|
265
273
|
|
|
266
|
-
|
|
|
274
|
+
| 保存対象 | 説明 | 保存タイミング |
|
|
267
275
|
|---------|------|--------------|
|
|
268
|
-
|
|
|
269
|
-
|
|
|
270
|
-
|
|
|
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:
|
|
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
|
-
#
|
|
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
|
-
|
|
339
|
+
#### 会話ログの一元管理
|
|
340
|
+
|
|
341
|
+
すべてのプロンプトは `prompts/conversation-log.md` にも追記されます:
|
|
342
|
+
|
|
285
343
|
```markdown
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
344
|
+
# Conversation Log
|
|
345
|
+
|
|
346
|
+
## Session: 2026-01-27
|
|
347
|
+
|
|
348
|
+
### [10:00:00] User (original)
|
|
349
|
+
レアメタルについて調べて
|
|
292
350
|
|
|
293
|
-
|
|
351
|
+
### [10:05:00] AI (structured)
|
|
352
|
+
[構造化プロンプトを表示]
|
|
294
353
|
|
|
295
|
-
|
|
296
|
-
|
|
354
|
+
### [10:06:00] User (approval)
|
|
355
|
+
はい、それでお願いします
|
|
297
356
|
|
|
298
|
-
|
|
299
|
-
|
|
357
|
+
### [10:07:00] AI (question)
|
|
358
|
+
この調査結果は誰が使いますか?
|
|
300
359
|
|
|
301
|
-
|
|
302
|
-
|
|
360
|
+
### [10:08:00] User (answer)
|
|
361
|
+
経営会議で使います
|
|
303
362
|
|
|
304
|
-
|
|
305
|
-
|
|
363
|
+
### [10:09:00] AI (question)
|
|
364
|
+
いつまでに必要ですか?
|
|
306
365
|
|
|
307
|
-
|
|
308
|
-
|
|
366
|
+
### [10:10:00] User (answer)
|
|
367
|
+
来週の金曜日までに
|
|
309
368
|
|
|
310
|
-
|
|
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
|
package/mcp-server/src/index.ts
CHANGED
|
@@ -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:
|
|
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('
|
|
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('
|
|
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('
|
|
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.
|
|
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 = `
|
|
94
|
+
filename = `prompt_original_${dateStr}_${timeStr}.md`;
|
|
91
95
|
break;
|
|
92
96
|
case 'structured':
|
|
93
|
-
filename = `
|
|
97
|
+
filename = `prompt_structured_${dateStr}_${timeStr}.md`;
|
|
94
98
|
break;
|
|
95
99
|
case 'refinement':
|
|
96
|
-
filename = `
|
|
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