@ignission/slack-task-mcp 0.1.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.ja.md +112 -0
- package/README.md +112 -0
- package/package.json +40 -0
- package/src/agents/analyze.js +109 -0
- package/src/agents/draft-reply.js +119 -0
- package/src/agents/index.js +161 -0
- package/src/auth.js +216 -0
- package/src/cli.js +92 -0
- package/src/index.js +896 -0
package/README.ja.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# slack-task-mcp
|
|
2
|
+
|
|
3
|
+
Slack タスク管理 MCP サーバー for Claude Code / Claude Desktop
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/slack-task-mcp)
|
|
6
|
+
|
|
7
|
+
[English](./README.md)
|
|
8
|
+
|
|
9
|
+
## こんな人向け
|
|
10
|
+
|
|
11
|
+
- Slackのメンションがたまると、どこから手を付けていいか迷う
|
|
12
|
+
- 難しい依頼が来ると、何を聞けばいいかわからず固まる
|
|
13
|
+
- 返信を書くのに時間がかかる
|
|
14
|
+
- タスクを分解しても、途中で集中が切れて諦めてしまう
|
|
15
|
+
|
|
16
|
+
## インストール
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# 認証(初回のみ)
|
|
20
|
+
npx slack-task-mcp auth
|
|
21
|
+
|
|
22
|
+
# 認証状態を確認
|
|
23
|
+
npx slack-task-mcp auth status
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Claude Desktop 設定
|
|
27
|
+
|
|
28
|
+
### macOS
|
|
29
|
+
|
|
30
|
+
`~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"slack-task": {
|
|
36
|
+
"command": "npx",
|
|
37
|
+
"args": ["-y", "slack-task-mcp"]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Windows
|
|
44
|
+
|
|
45
|
+
`%APPDATA%\Claude\claude_desktop_config.json`:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"mcpServers": {
|
|
50
|
+
"slack-task": {
|
|
51
|
+
"command": "npx.cmd",
|
|
52
|
+
"args": ["-y", "slack-task-mcp"]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
設定後、Claude Desktopを再起動してください。
|
|
59
|
+
|
|
60
|
+
## 機能
|
|
61
|
+
|
|
62
|
+
| ツール | 説明 |
|
|
63
|
+
|--------|------|
|
|
64
|
+
| `get_slack_thread` | SlackスレッドURLからメッセージを取得 |
|
|
65
|
+
| `analyze_request` | 依頼を分析し、目的・不明点・確認案を生成 |
|
|
66
|
+
| `draft_reply` | 返信を添削し、ロジカルに構造化 |
|
|
67
|
+
| `save_task` | タスクを保存(5分以内のステップに分解) |
|
|
68
|
+
| `list_tasks` | タスク一覧を表示 |
|
|
69
|
+
| `search_tasks` | キーワード・日付でタスクを検索 |
|
|
70
|
+
| `complete_step` | ステップを完了にする |
|
|
71
|
+
| `search_slack` | Slackメッセージをキーワードで検索 |
|
|
72
|
+
|
|
73
|
+
## 使い方
|
|
74
|
+
|
|
75
|
+
### Slackスレッドを分析
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
このスレッドを分析して: https://xxx.slack.com/archives/C12345678/p1234567890
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### タスクとして保存
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
5分以内のステップに分解して保存して
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 返信を添削
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
この返信を添削して「レポートできました。確認お願いします。」
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## CLIコマンド
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npx slack-task-mcp auth # 認証
|
|
97
|
+
npx slack-task-mcp auth status # 認証状態を確認
|
|
98
|
+
npx slack-task-mcp auth logout # ログアウト
|
|
99
|
+
npx slack-task-mcp --help # ヘルプ
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## データ保存先
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
~/.slack-task-mcp/
|
|
106
|
+
├── credentials.json # 認証情報
|
|
107
|
+
└── tasks.json # タスクデータ
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## ライセンス
|
|
111
|
+
|
|
112
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# slack-task-mcp
|
|
2
|
+
|
|
3
|
+
Slack Task Management MCP Server for Claude Code / Claude Desktop
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/slack-task-mcp)
|
|
6
|
+
|
|
7
|
+
[日本語](./README.ja.md)
|
|
8
|
+
|
|
9
|
+
## Who is this for?
|
|
10
|
+
|
|
11
|
+
- You get overwhelmed when Slack mentions pile up
|
|
12
|
+
- You freeze when complex requests come in, unsure what to ask
|
|
13
|
+
- Writing replies takes too long
|
|
14
|
+
- You break down tasks but lose focus midway
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Authenticate (first time only)
|
|
20
|
+
npx slack-task-mcp auth
|
|
21
|
+
|
|
22
|
+
# Check authentication status
|
|
23
|
+
npx slack-task-mcp auth status
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Claude Desktop Configuration
|
|
27
|
+
|
|
28
|
+
### macOS
|
|
29
|
+
|
|
30
|
+
`~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"slack-task": {
|
|
36
|
+
"command": "npx",
|
|
37
|
+
"args": ["-y", "slack-task-mcp"]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Windows
|
|
44
|
+
|
|
45
|
+
`%APPDATA%\Claude\claude_desktop_config.json`:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"mcpServers": {
|
|
50
|
+
"slack-task": {
|
|
51
|
+
"command": "npx.cmd",
|
|
52
|
+
"args": ["-y", "slack-task-mcp"]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Restart Claude Desktop after configuration.
|
|
59
|
+
|
|
60
|
+
## Features
|
|
61
|
+
|
|
62
|
+
| Tool | Description |
|
|
63
|
+
|------|-------------|
|
|
64
|
+
| `get_slack_thread` | Fetch messages from a Slack thread URL |
|
|
65
|
+
| `analyze_request` | Analyze requests and generate purpose, questions, and confirmation messages |
|
|
66
|
+
| `draft_reply` | Edit and structure replies logically |
|
|
67
|
+
| `save_task` | Save tasks (broken into 5-minute steps) |
|
|
68
|
+
| `list_tasks` | Display task list |
|
|
69
|
+
| `search_tasks` | Search tasks by keyword or date |
|
|
70
|
+
| `complete_step` | Mark a step as complete |
|
|
71
|
+
| `search_slack` | Search Slack messages by keyword |
|
|
72
|
+
|
|
73
|
+
## Usage
|
|
74
|
+
|
|
75
|
+
### Analyze a Slack thread
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
Analyze this thread: https://xxx.slack.com/archives/C12345678/p1234567890
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Save as a task
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
Break this down into 5-minute steps and save it
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Edit a reply
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
Edit this reply: "The report is done. Please check it."
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## CLI Commands
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npx slack-task-mcp auth # Authenticate
|
|
97
|
+
npx slack-task-mcp auth status # Check auth status
|
|
98
|
+
npx slack-task-mcp auth logout # Logout
|
|
99
|
+
npx slack-task-mcp --help # Help
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Data Storage
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
~/.slack-task-mcp/
|
|
106
|
+
├── credentials.json # Authentication credentials
|
|
107
|
+
└── tasks.json # Task data
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ignission/slack-task-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP Server for Slack task management with Claude Code",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"slack-task-mcp": "./src/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/ignission/slack-task-mcp.git"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/ignission/slack-task-mcp#readme",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/ignission/slack-task-mcp/issues"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"mcp",
|
|
26
|
+
"slack",
|
|
27
|
+
"claude",
|
|
28
|
+
"task-management",
|
|
29
|
+
"model-context-protocol"
|
|
30
|
+
],
|
|
31
|
+
"author": "Ignission G.K.",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@anthropic-ai/claude-agent-sdk": "^0.1.76",
|
|
35
|
+
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
36
|
+
"@slack/web-api": "^7.13.0",
|
|
37
|
+
"open": "^10.1.0",
|
|
38
|
+
"zod": "^4.2.1"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 分析エージェント
|
|
3
|
+
*
|
|
4
|
+
* Slackスレッドの依頼を分析し、目的・不明点・確認案・優先度を生成
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import {
|
|
10
|
+
ANALYZE_SYSTEM_PROMPT,
|
|
11
|
+
AGENT_TIMEOUT_MS,
|
|
12
|
+
createAgentOptions,
|
|
13
|
+
formatAgentError,
|
|
14
|
+
} from "./index.js";
|
|
15
|
+
|
|
16
|
+
// ============================================
|
|
17
|
+
// 分析結果スキーマ(バリデーション用)
|
|
18
|
+
// ============================================
|
|
19
|
+
|
|
20
|
+
const UnclearPointSchema = z.object({
|
|
21
|
+
question: z.string().describe("確認すべき質問"),
|
|
22
|
+
impact: z.string().describe("この点が不明だと何が困るか"),
|
|
23
|
+
suggested_options: z.array(z.string()).optional().describe("想定される選択肢"),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const NextActionSchema = z.object({
|
|
27
|
+
action: z.string().describe("具体的なアクション内容"),
|
|
28
|
+
estimated_time: z.number().describe("推定所要時間(分)"),
|
|
29
|
+
reason: z.string().nullable().optional().describe("なぜこれが最初のアクションなのか"),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const PrioritySchema = z.enum(["high", "medium", "low"]);
|
|
33
|
+
|
|
34
|
+
export const AnalysisResultSchema = z.object({
|
|
35
|
+
purpose: z.string().describe("依頼の目的(1文で言語化)"),
|
|
36
|
+
deliverable: z.string().nullable().optional().describe("成果物"),
|
|
37
|
+
deadline: z.string().nullable().optional().describe("期限"),
|
|
38
|
+
unclear_points: z.array(UnclearPointSchema).describe("不明点のリスト"),
|
|
39
|
+
confirmation_message: z.string().nullable().optional().describe("確認メッセージ案"),
|
|
40
|
+
next_action: NextActionSchema.describe("ネクストアクション"),
|
|
41
|
+
priority: PrioritySchema.describe("優先度"),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Slackスレッドの依頼を分析
|
|
46
|
+
*
|
|
47
|
+
* @param {string} threadContent - スレッドの内容
|
|
48
|
+
* @param {string} [threadUrl] - スレッドのURL(参照用)
|
|
49
|
+
* @returns {Promise<object>} 分析結果
|
|
50
|
+
* @throws {Error} エージェント実行エラーまたはバリデーションエラー
|
|
51
|
+
*/
|
|
52
|
+
export async function analyzeRequest(threadContent, threadUrl) {
|
|
53
|
+
const options = createAgentOptions(ANALYZE_SYSTEM_PROMPT);
|
|
54
|
+
|
|
55
|
+
// タイムアウト用のAbortController
|
|
56
|
+
const controller = new AbortController();
|
|
57
|
+
const timeoutId = setTimeout(() => controller.abort(), AGENT_TIMEOUT_MS);
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const prompt = threadUrl
|
|
61
|
+
? `以下のSlackスレッド(${threadUrl})を分析してください:\n\n${threadContent}`
|
|
62
|
+
: `以下のSlackスレッドを分析してください:\n\n${threadContent}`;
|
|
63
|
+
|
|
64
|
+
const queryGenerator = query({
|
|
65
|
+
prompt,
|
|
66
|
+
options: {
|
|
67
|
+
...options,
|
|
68
|
+
signal: controller.signal,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// AsyncGeneratorからresultメッセージを取得
|
|
73
|
+
let resultText = "";
|
|
74
|
+
for await (const message of queryGenerator) {
|
|
75
|
+
if (message.type === "result" && message.subtype === "success") {
|
|
76
|
+
resultText = message.result;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!resultText) {
|
|
82
|
+
throw new Error("分析結果が取得できませんでした");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// レスポンスからJSON部分を抽出
|
|
86
|
+
const jsonMatch = resultText.match(/\{[\s\S]*\}/);
|
|
87
|
+
if (!jsonMatch) {
|
|
88
|
+
throw new Error("分析結果のJSONが見つかりませんでした");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// JSONパースとバリデーション
|
|
92
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
93
|
+
const validated = AnalysisResultSchema.parse(parsed);
|
|
94
|
+
|
|
95
|
+
return validated;
|
|
96
|
+
} catch (error) {
|
|
97
|
+
if (error.name === "AbortError") {
|
|
98
|
+
throw new Error("処理がタイムアウトしました。再試行してください。");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (error.name === "ZodError") {
|
|
102
|
+
throw new Error(`分析結果の形式が不正です: ${error.message}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
throw new Error(formatAgentError(error));
|
|
106
|
+
} finally {
|
|
107
|
+
clearTimeout(timeoutId);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 返信添削エージェント
|
|
3
|
+
*
|
|
4
|
+
* 下書きを添削し、テンプレートに沿った構造化返信を生成
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import {
|
|
10
|
+
DRAFT_REPLY_SYSTEM_PROMPT,
|
|
11
|
+
AGENT_TIMEOUT_MS,
|
|
12
|
+
createAgentOptions,
|
|
13
|
+
formatAgentError,
|
|
14
|
+
} from "./index.js";
|
|
15
|
+
|
|
16
|
+
// ============================================
|
|
17
|
+
// 返信添削結果スキーマ(バリデーション用)
|
|
18
|
+
// ============================================
|
|
19
|
+
|
|
20
|
+
const TaskTypeSchema = z.enum(["report", "confirm", "request"]);
|
|
21
|
+
const ToneSchema = z.enum(["formal", "casual"]);
|
|
22
|
+
const ChangeTypeSchema = z.enum(["structure", "simplify", "clarify", "tone", "logic", "add"]);
|
|
23
|
+
|
|
24
|
+
const ChangeSchema = z.object({
|
|
25
|
+
type: ChangeTypeSchema.describe("変更の種類"),
|
|
26
|
+
description: z.string().describe("変更内容の説明"),
|
|
27
|
+
reason: z.string().describe("変更の理由"),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const ReplyStructureSchema = z.object({
|
|
31
|
+
conclusion: z.string().describe("結論(何を伝えたいか)"),
|
|
32
|
+
reasoning: z.string().nullable().optional().describe("根拠(なぜそう言えるか)"),
|
|
33
|
+
action: z.string().nullable().optional().describe("アクション"),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const EditedReplySchema = z.object({
|
|
37
|
+
task_type: TaskTypeSchema.describe("タスクタイプ"),
|
|
38
|
+
after: z.string().describe("添削後のテキスト"),
|
|
39
|
+
structure: ReplyStructureSchema.describe("構造化された返信"),
|
|
40
|
+
changes: z.array(ChangeSchema).describe("変更ポイント"),
|
|
41
|
+
tone: ToneSchema.describe("適用されたトーン"),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 返信を添削
|
|
46
|
+
*
|
|
47
|
+
* @param {string} draftText - 添削対象の下書き
|
|
48
|
+
* @param {string} [threadContent] - 文脈用のスレッド内容
|
|
49
|
+
* @param {string} [taskType] - タスクタイプ(report/confirm/request)
|
|
50
|
+
* @param {string} [tone] - トーン(formal/casual)
|
|
51
|
+
* @returns {Promise<object>} 添削結果
|
|
52
|
+
* @throws {Error} エージェント実行エラーまたはバリデーションエラー
|
|
53
|
+
*/
|
|
54
|
+
export async function draftReply(draftText, threadContent, taskType, tone = "formal") {
|
|
55
|
+
const options = createAgentOptions(DRAFT_REPLY_SYSTEM_PROMPT);
|
|
56
|
+
|
|
57
|
+
// タイムアウト用のAbortController
|
|
58
|
+
const controller = new AbortController();
|
|
59
|
+
const timeoutId = setTimeout(() => controller.abort(), AGENT_TIMEOUT_MS);
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
let prompt = `以下の下書きを添削してください:\n\n「${draftText}」`;
|
|
63
|
+
|
|
64
|
+
if (threadContent) {
|
|
65
|
+
prompt += `\n\n文脈となるスレッド内容:\n${threadContent}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (taskType) {
|
|
69
|
+
prompt += `\n\nタスクタイプ: ${taskType}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
prompt += `\n\nトーン: ${tone}`;
|
|
73
|
+
|
|
74
|
+
const queryGenerator = query({
|
|
75
|
+
prompt,
|
|
76
|
+
options: {
|
|
77
|
+
...options,
|
|
78
|
+
signal: controller.signal,
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// AsyncGeneratorからresultメッセージを取得
|
|
83
|
+
let resultText = "";
|
|
84
|
+
for await (const message of queryGenerator) {
|
|
85
|
+
if (message.type === "result" && message.subtype === "success") {
|
|
86
|
+
resultText = message.result;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!resultText) {
|
|
92
|
+
throw new Error("添削結果が取得できませんでした");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// レスポンスからJSON部分を抽出
|
|
96
|
+
const jsonMatch = resultText.match(/\{[\s\S]*\}/);
|
|
97
|
+
if (!jsonMatch) {
|
|
98
|
+
throw new Error("添削結果のJSONが見つかりませんでした");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// JSONパースとバリデーション
|
|
102
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
103
|
+
const validated = EditedReplySchema.parse(parsed);
|
|
104
|
+
|
|
105
|
+
return validated;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
if (error.name === "AbortError") {
|
|
108
|
+
throw new Error("処理がタイムアウトしました。再試行してください。");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (error.name === "ZodError") {
|
|
112
|
+
throw new Error(`添削結果の形式が不正です: ${error.message}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
throw new Error(formatAgentError(error));
|
|
116
|
+
} finally {
|
|
117
|
+
clearTimeout(timeoutId);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent SDK 共通設定
|
|
3
|
+
*
|
|
4
|
+
* エージェントのシステムプロンプトとオプションを定義
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// 分析エージェント用システムプロンプト
|
|
8
|
+
export const ANALYZE_SYSTEM_PROMPT = `あなたはSlackの依頼を分析するエキスパートです。
|
|
9
|
+
ADHDの特性を持つユーザーが、メンションから着手までスムーズに進められるよう支援します。
|
|
10
|
+
|
|
11
|
+
## 分析ルール
|
|
12
|
+
|
|
13
|
+
### 1. 目的の明確化
|
|
14
|
+
「結局何を求められているか」を1文で言語化する。
|
|
15
|
+
- この依頼の最終ゴールは何か?
|
|
16
|
+
- 何を作る/する必要があるか?
|
|
17
|
+
- 誰のため?誰と連携?
|
|
18
|
+
|
|
19
|
+
### 2. 不明点の洗い出し
|
|
20
|
+
「これを聞かないと進めない」を特定する。
|
|
21
|
+
- 依頼文から読み取れない情報をリストアップ
|
|
22
|
+
- 「たぶんこうだろう」で進めると手戻りになる点を特定
|
|
23
|
+
- 不明点がある場合は、確認メッセージ案を提示
|
|
24
|
+
|
|
25
|
+
### 3. 確認メッセージ案
|
|
26
|
+
Slackで聞く文面まで生成する。
|
|
27
|
+
- 簡潔で具体的な質問文
|
|
28
|
+
- 相手が答えやすい選択肢を提示
|
|
29
|
+
- 背景説明は最小限に
|
|
30
|
+
|
|
31
|
+
### 4. タスク分解
|
|
32
|
+
5分以内で完了できる粒度に分解する。
|
|
33
|
+
- 最初のステップは最も簡単で、すぐ終わるものにする
|
|
34
|
+
- 各ステップは「やった感」が得られる区切りにする
|
|
35
|
+
- 途中で止めてもOKな区切りを明示する
|
|
36
|
+
- 曖昧な作業は具体的な動作に変換する
|
|
37
|
+
- ❌「資料を作る」
|
|
38
|
+
- ✅「Googleドキュメントを開いてタイトルを書く」
|
|
39
|
+
|
|
40
|
+
### 5. 優先度の判定
|
|
41
|
+
- 🔴 高: 他の人をブロックしている、期限が近い
|
|
42
|
+
- 🟡 中: 今日〜今週中にやるべき
|
|
43
|
+
- 🟢 低: いつでもいい
|
|
44
|
+
|
|
45
|
+
## 出力形式
|
|
46
|
+
|
|
47
|
+
以下のJSON形式で出力してください:
|
|
48
|
+
{
|
|
49
|
+
"purpose": "依頼の目的(1文)",
|
|
50
|
+
"deliverable": "成果物(あれば)",
|
|
51
|
+
"deadline": "期限(あれば)",
|
|
52
|
+
"unclear_points": [
|
|
53
|
+
{
|
|
54
|
+
"question": "確認すべき質問",
|
|
55
|
+
"impact": "不明だと何が困るか",
|
|
56
|
+
"suggested_options": ["選択肢1", "選択肢2"]
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"confirmation_message": "確認メッセージ案(不明点がある場合)",
|
|
60
|
+
"next_action": {
|
|
61
|
+
"action": "最初にやるべきこと",
|
|
62
|
+
"estimated_time": 5,
|
|
63
|
+
"reason": "なぜこれが最初か"
|
|
64
|
+
},
|
|
65
|
+
"priority": "high" | "medium" | "low"
|
|
66
|
+
}`;
|
|
67
|
+
|
|
68
|
+
// 返信添削エージェント用システムプロンプト
|
|
69
|
+
export const DRAFT_REPLY_SYSTEM_PROMPT = `あなたはSlackの返信を添削するエキスパートです。
|
|
70
|
+
ユーザーの下書きを、論理的で読みやすい構造に整理します。
|
|
71
|
+
|
|
72
|
+
## 添削のポイント
|
|
73
|
+
|
|
74
|
+
- **構造化**: 結論→根拠→アクションの順に整理
|
|
75
|
+
- **簡潔化**: 冗長な表現を要点を絞った文章に変換
|
|
76
|
+
- **ロジカルチェック**: 論理の飛躍や抜け漏れを指摘
|
|
77
|
+
|
|
78
|
+
## タスクタイプ別テンプレート
|
|
79
|
+
|
|
80
|
+
### 報告系
|
|
81
|
+
\`\`\`
|
|
82
|
+
<結論>〇〇の結果、△△となりました。
|
|
83
|
+
<詳細>
|
|
84
|
+
- ポイント1
|
|
85
|
+
- ポイント2
|
|
86
|
+
<次のアクション>□□をお願いできますでしょうか。
|
|
87
|
+
\`\`\`
|
|
88
|
+
|
|
89
|
+
### 確認系
|
|
90
|
+
\`\`\`
|
|
91
|
+
<確認したいこと>〇〇について確認させてください。
|
|
92
|
+
<背景>△△のため、□□を決める必要があります。
|
|
93
|
+
<質問>A案とB案のどちらで進めればよいでしょうか?
|
|
94
|
+
\`\`\`
|
|
95
|
+
|
|
96
|
+
### 依頼系
|
|
97
|
+
\`\`\`
|
|
98
|
+
<お願い>〇〇をお願いできますでしょうか。
|
|
99
|
+
<背景>△△のため、□□が必要です。
|
|
100
|
+
<期限>可能であれば、◯月◯日までにいただけると助かります。
|
|
101
|
+
\`\`\`
|
|
102
|
+
|
|
103
|
+
## 出力形式
|
|
104
|
+
|
|
105
|
+
以下のJSON形式で出力してください:
|
|
106
|
+
{
|
|
107
|
+
"task_type": "report" | "confirm" | "request",
|
|
108
|
+
"after": "添削後のテキスト(テンプレート形式)",
|
|
109
|
+
"structure": {
|
|
110
|
+
"conclusion": "結論",
|
|
111
|
+
"reasoning": "根拠(あれば)",
|
|
112
|
+
"action": "アクション(あれば)"
|
|
113
|
+
},
|
|
114
|
+
"changes": [
|
|
115
|
+
{
|
|
116
|
+
"type": "structure" | "simplify" | "clarify" | "tone" | "logic" | "add",
|
|
117
|
+
"description": "変更内容",
|
|
118
|
+
"reason": "変更理由"
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
"tone": "formal" | "casual"
|
|
122
|
+
}`;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* エージェントオプションを作成
|
|
126
|
+
* @param {string} systemPrompt - システムプロンプト
|
|
127
|
+
* @returns {object} Agent SDKオプション
|
|
128
|
+
*/
|
|
129
|
+
export function createAgentOptions(systemPrompt) {
|
|
130
|
+
return {
|
|
131
|
+
allowedTools: ["Read"],
|
|
132
|
+
permissionMode: "bypassPermissions",
|
|
133
|
+
systemPrompt,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* エージェントエラーをユーザーフレンドリーなメッセージに変換
|
|
139
|
+
* @param {Error} error - エラーオブジェクト
|
|
140
|
+
* @returns {string} ユーザー向けエラーメッセージ
|
|
141
|
+
*/
|
|
142
|
+
export function formatAgentError(error) {
|
|
143
|
+
const message = error.message || String(error);
|
|
144
|
+
|
|
145
|
+
if (message.includes("Claude Code not found") || message.includes("not authenticated")) {
|
|
146
|
+
return "❌ Claude Codeが認証されていません。\n\nターミナルで `claude` を実行して認証してください。";
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (message.includes("timeout") || message.includes("ETIMEDOUT")) {
|
|
150
|
+
return "❌ 処理がタイムアウトしました。\n\n再試行してください。";
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (message.includes("rate limit") || message.includes("429")) {
|
|
154
|
+
return "❌ APIレート制限に達しました。\n\nしばらく待ってから再試行してください。";
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return `❌ エージェント処理中にエラーが発生しました: ${message}`;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// エージェント実行のタイムアウト(ミリ秒)
|
|
161
|
+
export const AGENT_TIMEOUT_MS = 30000;
|