MCP test add worklog.md
This commit is contained in:
24
.cursor/rules.md
Normal file
24
.cursor/rules.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Cursor Rules: 開発日記(dev_diary)
|
||||
|
||||
## 目的
|
||||
ユーザーが「開発日記に書いといて」と言ったら、要約・タグ付け・メタデータ補完を行い、MCP の `diary_upsert` で `dev_diary` に保存する。
|
||||
|
||||
## 保存ルール
|
||||
- ツール: `diary_upsert`
|
||||
- collection: `dev_diary`
|
||||
- content: 1〜4文で要約(実作業が分かる具体性)
|
||||
- tags: 2〜5個(下記候補から選び、足りなければ追加)
|
||||
- topic: 1語(下記候補、なければ `general`)
|
||||
- source: `codex`
|
||||
- author: 未指定なら自動補完に任せる
|
||||
- ts: 未指定なら自動補完に任せる
|
||||
|
||||
## タグ候補
|
||||
`pgvecter`, `mcp`, `api`, `deploy`, `ops`, `security`, `db`, `migration`, `embedding`, `search`, `bugfix`, `refactor`, `docs`, `test`
|
||||
|
||||
## トピック候補
|
||||
`api`, `mcp`, `deploy`, `ops`, `security`, `db`, `docs`, `test`, `general`
|
||||
|
||||
## 例
|
||||
ユーザー: 「開発日記に書いといて。今日は削除API追加と監査ログ導入、テストまで完了。」
|
||||
→ `diary_upsert` で content を要約し、tags に `api`, `mcp`, `deploy` などを付与して保存。
|
||||
1
.cursor/worklog.md
Normal file
1
.cursor/worklog.md
Normal file
@@ -0,0 +1 @@
|
||||
# 作業日誌
|
||||
9
.githooks/post-commit
Executable file
9
.githooks/post-commit
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(git rev-parse --show-toplevel)"
|
||||
cd "$repo_root"
|
||||
|
||||
if [[ -x "scripts/worklog_mcp.sh" ]]; then
|
||||
scripts/worklog_mcp.sh || true
|
||||
fi
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -176,3 +176,6 @@ cython_debug/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# worklog MCP hook state
|
||||
.worklog_mcp_state
|
||||
|
||||
19
README.md
19
README.md
@@ -427,6 +427,25 @@ curl -s http://127.0.0.1:8092/health
|
||||
- `diary_upsert` の `content_hash` は本文 (`content`) を trim & LF 正規化して SHA-256 を計算し、`sha256:<hex>` で保存
|
||||
- `*_search_by_id` は `metadata.id` を `eq` で検索するショートカット
|
||||
|
||||
## MCP 運用ルール(開発日記)
|
||||
|
||||
Cursor などの指示ファイルに以下の運用ルールを設定しておくと、会話だけで日記が回せる。
|
||||
|
||||
### ルール概要
|
||||
- ツール: `diary_upsert`
|
||||
- collection: `dev_diary`
|
||||
- content: 1〜4文で要約(実作業が分かる具体性)
|
||||
- tags: 2〜5個(候補から選ぶ)
|
||||
- topic: 1語(候補から選ぶ、なければ `general`)
|
||||
- source: `codex`
|
||||
- author/ts: 未指定なら自動補完
|
||||
|
||||
### タグ候補
|
||||
`pgvecter`, `mcp`, `api`, `deploy`, `ops`, `security`, `db`, `migration`, `embedding`, `search`, `bugfix`, `refactor`, `docs`, `test`
|
||||
|
||||
### topic 候補
|
||||
`api`, `mcp`, `deploy`, `ops`, `security`, `db`, `docs`, `test`, `general`
|
||||
|
||||
### 例: /kb/search
|
||||
|
||||
```bash
|
||||
|
||||
202
scripts/worklog_mcp.sh
Executable file
202
scripts/worklog_mcp.sh
Executable file
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
WORKLOG_PATH="notes/worklog.md"
|
||||
STATE_PATH=".worklog_mcp_state"
|
||||
MCP_SERVER_CMD=(go run /Users/sunamurahideyuki/develop/pgvecterAPI/cmd/mcp-server)
|
||||
|
||||
if [[ ! -f "$WORKLOG_PATH" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Extract the last paragraph (separated by blank lines)
|
||||
entry="$(awk 'BEGIN{RS=""; ORS=""} {block=$0} END{print block}' "$WORKLOG_PATH" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
|
||||
if [[ -z "$entry" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
summary="$(WORKLOG_ENTRY="$entry" python3 - <<'PY'
|
||||
import os, re
|
||||
|
||||
text = os.environ["WORKLOG_ENTRY"]
|
||||
|
||||
def summarize(t: str) -> str:
|
||||
t = t.strip()
|
||||
if not t:
|
||||
return t
|
||||
if "。" in t:
|
||||
parts = [p for p in t.split("。") if p.strip()]
|
||||
return "。".join(parts[:2]) + ("。" if len(parts) > 0 else "")
|
||||
if "." in t:
|
||||
parts = [p for p in t.split(".") if p.strip()]
|
||||
return ".".join(parts[:2]) + ("." if len(parts) > 0 else "")
|
||||
if len(t) > 240:
|
||||
return t[:240].rstrip() + "..."
|
||||
return t
|
||||
|
||||
print(summarize(text))
|
||||
PY
|
||||
)"
|
||||
|
||||
hash="$(printf "%s" "$entry" | shasum -a 256 | awk '{print $1}')"
|
||||
if [[ -f "$STATE_PATH" ]]; then
|
||||
last_hash="$(cat "$STATE_PATH" 2>/dev/null || true)"
|
||||
if [[ "$hash" == "$last_hash" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -f ".env" ]]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1091
|
||||
. ./.env
|
||||
set +a
|
||||
fi
|
||||
|
||||
if [[ -z "${PGVECTER_BASE_URL:-}" || -z "${PGVECTER_API_KEY:-}" ]]; then
|
||||
echo "worklog_mcp: PGVECTER_BASE_URL / PGVECTER_API_KEY が未設定のため送信をスキップしました。" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
has_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
contains() {
|
||||
local pattern="$1"
|
||||
if has_cmd rg; then
|
||||
printf "%s" "$entry" | rg -q "$pattern"
|
||||
else
|
||||
printf "%s" "$entry" | grep -Eq "$pattern"
|
||||
fi
|
||||
}
|
||||
|
||||
tags=()
|
||||
add_tag() {
|
||||
local t="$1"
|
||||
for e in "${tags[@]}"; do
|
||||
if [[ "$e" == "$t" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
tags+=("$t")
|
||||
}
|
||||
|
||||
contains "pgvecter|pgvecterAPI" && add_tag "pgvecter"
|
||||
contains "MCP|mcp" && add_tag "mcp"
|
||||
contains "API|api" && add_tag "api"
|
||||
contains "デプロイ|deploy|リリース" && add_tag "deploy"
|
||||
contains "運用|ops|監視" && add_tag "ops"
|
||||
contains "セキュリティ|security" && add_tag "security"
|
||||
contains "DB|db|database|マイグレーション|migration" && add_tag "db" && add_tag "migration"
|
||||
contains "埋め込み|embedding" && add_tag "embedding"
|
||||
contains "検索|search" && add_tag "search"
|
||||
contains "バグ|bug" && add_tag "bugfix"
|
||||
contains "リファクタ|refactor" && add_tag "refactor"
|
||||
contains "ドキュメント|docs" && add_tag "docs"
|
||||
contains "テスト|test" && add_tag "test"
|
||||
|
||||
if [[ "${#tags[@]}" -lt 2 ]]; then
|
||||
add_tag "pgvecter"
|
||||
add_tag "ops"
|
||||
fi
|
||||
if [[ "${#tags[@]}" -gt 5 ]]; then
|
||||
tags=("${tags[@]:0:5}")
|
||||
fi
|
||||
|
||||
topic="general"
|
||||
if contains "MCP|mcp"; then
|
||||
topic="mcp"
|
||||
elif contains "デプロイ|deploy|リリース"; then
|
||||
topic="deploy"
|
||||
elif contains "運用|ops|監視"; then
|
||||
topic="ops"
|
||||
elif contains "セキュリティ|security"; then
|
||||
topic="security"
|
||||
elif contains "DB|db|database|マイグレーション|migration"; then
|
||||
topic="db"
|
||||
elif contains "ドキュメント|docs"; then
|
||||
topic="docs"
|
||||
elif contains "テスト|test"; then
|
||||
topic="test"
|
||||
elif contains "API|api"; then
|
||||
topic="api"
|
||||
fi
|
||||
|
||||
if has_cmd uuidgen; then
|
||||
entry_id="$(uuidgen | tr '[:upper:]' '[:lower:]')"
|
||||
else
|
||||
entry_id="$(python3 - <<'PY'
|
||||
import uuid
|
||||
print(str(uuid.uuid4()))
|
||||
PY
|
||||
)"
|
||||
fi
|
||||
|
||||
tags_joined=""
|
||||
if [[ "${#tags[@]}" -gt 0 ]]; then
|
||||
tags_joined="$(IFS="::"; echo "${tags[*]}")"
|
||||
fi
|
||||
|
||||
export WORKLOG_ENTRY="$entry"
|
||||
export WORKLOG_SUMMARY="$summary"
|
||||
export WORKLOG_TAGS="$tags_joined"
|
||||
export WORKLOG_TOPIC="$topic"
|
||||
export WORKLOG_ID="$entry_id"
|
||||
|
||||
payload="$(python3 - <<'PY'
|
||||
import json, os
|
||||
|
||||
entry = os.environ["WORKLOG_ENTRY"]
|
||||
tags_raw = os.environ.get("WORKLOG_TAGS", "")
|
||||
tags = tags_raw.split("::") if tags_raw else []
|
||||
topic = os.environ["WORKLOG_TOPIC"]
|
||||
entry_id = os.environ["WORKLOG_ID"]
|
||||
|
||||
init = {
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "initialize",
|
||||
"params": {
|
||||
"protocolVersion": "2025-03-26",
|
||||
"capabilities": {},
|
||||
"clientInfo": {"name": "worklog-hook", "version": "0.1"}
|
||||
}
|
||||
}
|
||||
|
||||
metadata = {"worklog_path": "notes/worklog.md"}
|
||||
if entry != os.environ["WORKLOG_SUMMARY"]:
|
||||
metadata["original"] = entry
|
||||
|
||||
call = {
|
||||
"jsonrpc": "2.0",
|
||||
"id": 2,
|
||||
"method": "tools/call",
|
||||
"params": {
|
||||
"name": "diary_upsert",
|
||||
"arguments": {
|
||||
"id": entry_id,
|
||||
"collection": "dev_diary",
|
||||
"content": os.environ["WORKLOG_SUMMARY"],
|
||||
"tags": tags,
|
||||
"topic": topic,
|
||||
"source": "codex",
|
||||
"metadata": metadata
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print(json.dumps(init))
|
||||
print(json.dumps(call))
|
||||
PY
|
||||
)"
|
||||
|
||||
response="$(printf "%s\n" "$payload" | "${MCP_SERVER_CMD[@]}")"
|
||||
|
||||
if printf "%s" "$response" | grep -q '"isError":true'; then
|
||||
echo "worklog_mcp: MCP 送信に失敗しました。" >&2
|
||||
echo "$response" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "$hash" > "$STATE_PATH"
|
||||
Reference in New Issue
Block a user