kimi-dev-workflow 0.1.0__py3-none-any.whl

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.
Files changed (31) hide show
  1. kimi_dev_workflow/__init__.py +3 -0
  2. kimi_dev_workflow/cli.py +45 -0
  3. kimi_dev_workflow/commands/__init__.py +1 -0
  4. kimi_dev_workflow/commands/doctor.py +119 -0
  5. kimi_dev_workflow/commands/index.py +84 -0
  6. kimi_dev_workflow/commands/init.py +242 -0
  7. kimi_dev_workflow/commands/memory.py +47 -0
  8. kimi_dev_workflow/commands/wiki.py +75 -0
  9. kimi_dev_workflow/config.py +52 -0
  10. kimi_dev_workflow/detector.py +130 -0
  11. kimi_dev_workflow/renderer.py +107 -0
  12. kimi_dev_workflow/scripts/kimi-index +231 -0
  13. kimi_dev_workflow/scripts/kimi-wiki +294 -0
  14. kimi_dev_workflow/scripts/release.sh +71 -0
  15. kimi_dev_workflow/templates/.grepaiignore.template +97 -0
  16. kimi_dev_workflow/templates/AGENTS.md.template +109 -0
  17. kimi_dev_workflow/templates/kimi_dir/README.md +144 -0
  18. kimi_dev_workflow/templates/kimi_dir/memory.md.template +53 -0
  19. kimi_dev_workflow/templates/kimi_dir/prompts/01-search.md +24 -0
  20. kimi_dev_workflow/templates/kimi_dir/prompts/02-code.md +33 -0
  21. kimi_dev_workflow/templates/kimi_dir/prompts/03-refactor.md +29 -0
  22. kimi_dev_workflow/templates/kimi_dir/prompts/04-debug.md +34 -0
  23. kimi_dev_workflow/templates/kimi_dir/prompts/05-review.md +31 -0
  24. kimi_dev_workflow/templates/kimi_dir/prompts/06-wiki.md +22 -0
  25. kimi_dev_workflow/templates/kimi_dir/prompts/07-memory.md +32 -0
  26. kimi_dev_workflow/utils.py +43 -0
  27. kimi_dev_workflow-0.1.0.dist-info/METADATA +317 -0
  28. kimi_dev_workflow-0.1.0.dist-info/RECORD +31 -0
  29. kimi_dev_workflow-0.1.0.dist-info/WHEEL +4 -0
  30. kimi_dev_workflow-0.1.0.dist-info/entry_points.txt +2 -0
  31. kimi_dev_workflow-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,130 @@
1
+ """Project type auto-detection."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ from dataclasses import dataclass
8
+ from pathlib import Path
9
+ from typing import Optional
10
+
11
+
12
+ @dataclass
13
+ class ProjectInfo:
14
+ """Detected project information."""
15
+
16
+ project_type: str
17
+ framework: str
18
+ language: str
19
+ build_tool: str
20
+ state_manager: str = ""
21
+ router: str = ""
22
+ style: str = ""
23
+ http_client: str = ""
24
+ validator: str = ""
25
+ form_lib: str = ""
26
+
27
+
28
+ def _read_json(path: Path) -> dict:
29
+ """Safely read a JSON file."""
30
+ try:
31
+ return json.loads(path.read_text(encoding="utf-8"))
32
+ except (json.JSONDecodeError, OSError):
33
+ return {}
34
+
35
+
36
+ def _has_dep(package_json: dict, name: str) -> bool:
37
+ """Check if a dependency exists in package.json."""
38
+ deps = package_json.get("dependencies", {})
39
+ dev_deps = package_json.get("devDependencies", {})
40
+ return name in deps or name in dev_deps
41
+
42
+
43
+ def detect_project(cwd: Optional[Path] = None) -> ProjectInfo:
44
+ """Auto-detect project type from current directory."""
45
+ cwd = cwd or Path.cwd()
46
+
47
+ # Check for package.json (Node.js projects)
48
+ package_json_path = cwd / "package.json"
49
+ if package_json_path.exists():
50
+ package = _read_json(package_json_path)
51
+
52
+ # Detect framework
53
+ if _has_dep(package, "react"):
54
+ framework = "React"
55
+ language = "TypeScript" if _has_dep(package, "typescript") else "JavaScript"
56
+ build_tool = "Vite" if (cwd / "vite.config.ts").exists() or (cwd / "vite.config.js").exists() else "Webpack"
57
+ state = "Zustand" if _has_dep(package, "zustand") else "Redux" if _has_dep(package, "redux") else "Context"
58
+ router = "React Router" if _has_dep(package, "react-router-dom") else ""
59
+ style = "Tailwind" if _has_dep(package, "tailwindcss") else "Styled Components" if _has_dep(package, "styled-components") else "CSS Modules"
60
+ http = "TanStack Query" if _has_dep(package, "@tanstack/react-query") else "Axios" if _has_dep(package, "axios") else "Fetch"
61
+ validator = "Zod" if _has_dep(package, "zod") else "Yup" if _has_dep(package, "yup") else ""
62
+ form_lib = "react-hook-form" if _has_dep(package, "react-hook-form") else ""
63
+ return ProjectInfo("react", framework, language, build_tool, state, router, style, http, validator, form_lib)
64
+
65
+ elif _has_dep(package, "vue"):
66
+ framework = "Vue"
67
+ language = "TypeScript" if _has_dep(package, "typescript") else "JavaScript"
68
+ build_tool = "Vite" if (cwd / "vite.config.ts").exists() or (cwd / "vite.config.js").exists() else "Webpack"
69
+ state = "Pinia" if _has_dep(package, "pinia") else "Vuex" if _has_dep(package, "vuex") else ""
70
+ router = "Vue Router" if _has_dep(package, "vue-router") else ""
71
+ style = "Tailwind" if _has_dep(package, "tailwindcss") else "SCSS" if _has_dep(package, "sass") else "CSS"
72
+ http = "Axios" if _has_dep(package, "axios") else "Fetch"
73
+ validator = "Zod" if _has_dep(package, "zod") else ""
74
+ form_lib = "VeeValidate" if _has_dep(package, "vee-validate") else ""
75
+ return ProjectInfo("vue", framework, language, build_tool, state, router, style, http, validator, form_lib)
76
+
77
+ else:
78
+ # Generic Node.js project
79
+ language = "TypeScript" if _has_dep(package, "typescript") else "JavaScript"
80
+ return ProjectInfo("node", "Node.js", language, "Unknown")
81
+
82
+ # Check for Go
83
+ if (cwd / "go.mod").exists():
84
+ return ProjectInfo("go", "Go", "Go", "go build")
85
+
86
+ # Check for Python
87
+ if (cwd / "pyproject.toml").exists() or (cwd / "requirements.txt").exists() or (cwd / "setup.py").exists():
88
+ build_tool = "hatchling" if (cwd / "pyproject.toml").exists() else "setuptools"
89
+ return ProjectInfo("python", "Python", "Python", build_tool, "", "", "", "", "", "")
90
+
91
+ # Check for Rust
92
+ if (cwd / "Cargo.toml").exists():
93
+ return ProjectInfo("rust", "Rust", "Rust", "Cargo", "", "", "", "", "", "")
94
+
95
+ # Unknown
96
+ return ProjectInfo("unknown", "Unknown", "Unknown", "Unknown", "", "", "", "", "", "")
97
+
98
+
99
+ def detect_project_name(cwd: Optional[Path] = None) -> str:
100
+ """Detect project name from directory or package files."""
101
+ cwd = cwd or Path.cwd()
102
+
103
+ # Try package.json name
104
+ package_json = cwd / "package.json"
105
+ if package_json.exists():
106
+ data = _read_json(package_json)
107
+ name = data.get("name", "")
108
+ if name:
109
+ return name
110
+
111
+ # Try go.mod module name
112
+ go_mod = cwd / "go.mod"
113
+ if go_mod.exists():
114
+ content = go_mod.read_text(encoding="utf-8")
115
+ for line in content.splitlines():
116
+ if line.startswith("module "):
117
+ return line.split()[1].split("/")[-1]
118
+
119
+ # Try pyproject.toml name
120
+ pyproject = cwd / "pyproject.toml"
121
+ if pyproject.exists():
122
+ import tomllib
123
+ try:
124
+ data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
125
+ return data.get("project", {}).get("name", "")
126
+ except Exception:
127
+ pass
128
+
129
+ # Fallback to directory name
130
+ return cwd.name
@@ -0,0 +1,107 @@
1
+ """AGENTS.md template rendering."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib.resources as pkg_resources
6
+ from pathlib import Path
7
+ from typing import Optional
8
+
9
+ from .config import AGENTS_FILE, PACKAGE_NAME
10
+ from .detector import ProjectInfo
11
+
12
+
13
+ def _get_template_content() -> str:
14
+ """Read the AGENTS.md template from package resources."""
15
+ template_module = f"{PACKAGE_NAME}.templates"
16
+ try:
17
+ return pkg_resources.files(template_module).joinpath("AGENTS.md.template").read_text(encoding="utf-8")
18
+ except (AttributeError, OSError):
19
+ # Fallback for older Python versions
20
+ with pkg_resources.path(template_module, "AGENTS.md.template") as p:
21
+ return p.read_text(encoding="utf-8")
22
+
23
+
24
+ def _get_python_replacements(info: ProjectInfo, project_name: str) -> dict[str, str]:
25
+ """Get replacements for Python projects."""
26
+ return {
27
+ "{项目名}": project_name,
28
+ "{React/Vue/Svelte} {版本} + {TypeScript/JavaScript}": f"{info.framework} + {info.build_tool}",
29
+ "{React/Vue/Svelte}": info.framework,
30
+ "{版本}": "",
31
+ "{TypeScript/JavaScript}": info.language,
32
+ "{Vite/Webpack/Rollup}": info.build_tool,
33
+ "{Zustand/Redux/Pinia}": "—",
34
+ "{React Router/Vue Router/TanStack Router}": "—",
35
+ "{Tailwind/Styled Components/SCSS/Less}": "—",
36
+ "{Axios/Fetch/TanStack Query}": "requests / httpx",
37
+ "{Zod/Yup/Joi}": "pydantic",
38
+ "{react-hook-form/VeeValidate}": "—",
39
+ "{store}": "—",
40
+ "{Context/useState}": "—",
41
+ "{ErrorClass}": "自定义 Exception",
42
+ "{校验库}": "pydantic",
43
+ "{路由文件路径}": "src/",
44
+ "{store 目录路径}": "—",
45
+ "{API 封装路径}": "src/",
46
+ "{认证相关文件}": "—",
47
+ "{布局组件路径}": "—",
48
+ "{路由文件}": "—",
49
+ }
50
+
51
+
52
+ def _get_frontend_replacements(info: ProjectInfo, project_name: str) -> dict[str, str]:
53
+ """Get replacements for frontend projects."""
54
+ return {
55
+ "{项目名}": project_name,
56
+ "{React/Vue/Svelte}": info.framework,
57
+ "{版本}": "",
58
+ "{TypeScript/JavaScript}": info.language,
59
+ "{Vite/Webpack/Rollup}": info.build_tool,
60
+ "{Zustand/Redux/Pinia}": info.state_manager or "Zustand/Redux/Pinia",
61
+ "{React Router/Vue Router/TanStack Router}": info.router or "React Router/Vue Router",
62
+ "{Tailwind/Styled Components/SCSS/Less}": info.style or "Tailwind/CSS",
63
+ "{Axios/Fetch/TanStack Query}": info.http_client or "Axios/Fetch",
64
+ "{Zod/Yup/Joi}": info.validator or "Zod/Yup",
65
+ "{react-hook-form/VeeValidate}": info.form_lib or "react-hook-form/VeeValidate",
66
+ "{store}": info.state_manager or "store",
67
+ "{Context/useState}": "Context/useState",
68
+ "{ErrorClass}": "ErrorBoundary",
69
+ "{校验库}": info.validator or "校验库",
70
+ "{路由文件路径}": "src/router/",
71
+ "{store 目录路径}": "src/stores/",
72
+ "{API 封装路径}": "src/api/",
73
+ "{认证相关文件}": "src/api/auth.ts",
74
+ "{布局组件路径}": "src/components/layout/",
75
+ "{路由文件}": "src/router/index.ts",
76
+ }
77
+
78
+
79
+ def render_agents(info: ProjectInfo, project_name: str) -> str:
80
+ """Render AGENTS.md template with detected project info."""
81
+ content = _get_template_content()
82
+
83
+ if info.project_type == "python":
84
+ replacements = _get_python_replacements(info, project_name)
85
+ else:
86
+ replacements = _get_frontend_replacements(info, project_name)
87
+
88
+ for placeholder, value in replacements.items():
89
+ content = content.replace(placeholder, value)
90
+
91
+ return content
92
+
93
+
94
+ def write_agents(cwd: Optional[Path] = None, info: Optional[ProjectInfo] = None, project_name: str = "") -> Path:
95
+ """Write rendered AGENTS.md to the project directory."""
96
+ cwd = cwd or Path.cwd()
97
+ if info is None:
98
+ from .detector import detect_project
99
+ info = detect_project(cwd)
100
+ if not project_name:
101
+ from .detector import detect_project_name
102
+ project_name = detect_project_name(cwd)
103
+
104
+ content = render_agents(info, project_name)
105
+ path = cwd / AGENTS_FILE
106
+ path.write_text(content, encoding="utf-8")
107
+ return path
@@ -0,0 +1,231 @@
1
+ #!/bin/bash
2
+ # kimi-index — Kimi CLI 代码索引一键管理脚本
3
+ # 项目地址: https://github.com/<GITHUB_USERNAME>/kimi-dev-workflow
4
+ # 用法: kimi-index [start|stop|status|search "query"|reset|reindex|logs]
5
+
6
+ set -e
7
+
8
+ INDEX_DIR=".grepai"
9
+ GREPAI_BIN="${HOME}/.local/bin/grepai"
10
+ OLLAMA_HOST="http://localhost:11434"
11
+
12
+ RED='\033[0;31m'
13
+ GREEN='\033[0;32m'
14
+ YELLOW='\033[1;33m'
15
+ BLUE='\033[0;34m'
16
+ NC='\033[0m'
17
+
18
+ log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
19
+ log_ok() { echo -e "${GREEN}[OK]${NC} $1"; }
20
+ log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
21
+ log_err() { echo -e "${RED}[ERR]${NC} $1"; }
22
+
23
+ check_grepai() {
24
+ if ! command -v grepai &> /dev/null; then
25
+ if [ -x "$GREPAI_BIN" ]; then
26
+ export PATH="${HOME}/.local/bin:$PATH"
27
+ else
28
+ log_err "grepai 未安装"
29
+ echo " 安装: curl -fsSL https://raw.githubusercontent.com/yoanbernabeu/grepai/main/install.sh | INSTALL_DIR=\$HOME/.local/bin sh"
30
+ exit 1
31
+ fi
32
+ fi
33
+ }
34
+
35
+ check_ollama() {
36
+ if ! curl -s "$OLLAMA_HOST/api/tags" > /dev/null 2>&1; then
37
+ log_warn "Ollama 未运行,尝试启动..."
38
+ if command -v ollama &> /dev/null; then
39
+ export OLLAMA_NUM_PARALLEL=4
40
+ ollama serve > /tmp/ollama-serve.log 2>&1 &
41
+ local pid=$!
42
+ sleep 3
43
+ if ! curl -s "$OLLAMA_HOST/api/tags" > /dev/null 2>&1; then
44
+ log_err "Ollama 启动失败"
45
+ exit 1
46
+ fi
47
+ log_ok "Ollama 已启动 (PID: $pid)"
48
+ else
49
+ log_err "Ollama 未安装"
50
+ echo " https://ollama.com/download"
51
+ exit 1
52
+ fi
53
+ fi
54
+ }
55
+
56
+ check_model() {
57
+ local model="${1:-all-minilm:l6-v2}"
58
+ if ! curl -s "$OLLAMA_HOST/api/tags" | grep -q "$model"; then
59
+ log_warn "模型 $model 未下载,正在拉取..."
60
+ ollama pull "$model"
61
+ log_ok "模型 $model 已就绪"
62
+ fi
63
+ }
64
+
65
+ check_project() {
66
+ if [ ! -d "$INDEX_DIR" ]; then
67
+ log_warn "当前目录未初始化 grepai"
68
+ echo " 运行: grepai init"
69
+ exit 1
70
+ fi
71
+ }
72
+
73
+ cleanup_locks() {
74
+ if [ -d "$INDEX_DIR" ]; then
75
+ local count=$(find "$INDEX_DIR" -name "*.lock" -type f 2>/dev/null | wc -l)
76
+ if [ "$count" -gt 0 ]; then
77
+ rm -f "$INDEX_DIR"/*.lock
78
+ log_warn "已清理 $count 个残留锁文件"
79
+ fi
80
+ fi
81
+ }
82
+
83
+ cmd_start() {
84
+ log_info "启动 Kimi 代码索引..."
85
+ check_grepai
86
+ check_ollama
87
+ check_project
88
+ cleanup_locks
89
+
90
+ local model=$(grep -A1 "^model:" "$INDEX_DIR/config.yaml" 2>/dev/null | tail -1 | xargs || echo "all-minilm:l6-v2")
91
+ check_model "$model"
92
+
93
+ export PATH="${HOME}/.local/bin:$PATH"
94
+ export OLLAMA_NUM_PARALLEL=4
95
+ nohup grepai watch > /tmp/grepai-watch.log 2>&1 &
96
+ local pid=$!
97
+
98
+ sleep 2
99
+ if ps -p $pid > /dev/null 2>&1; then
100
+ log_ok "索引守护进程已启动!PID: $pid"
101
+ echo ""
102
+ echo " 📊 查看进度: tail -f /tmp/grepai-watch.log"
103
+ echo " 🔍 查看状态: kimi-index status"
104
+ echo " 💡 开始开发: cd $(pwd) && kimi"
105
+ echo ""
106
+ sleep 3
107
+ cmd_status
108
+ else
109
+ log_err "启动失败"
110
+ echo " tail -f /tmp/grepai-watch.log"
111
+ exit 1
112
+ fi
113
+ }
114
+
115
+ cmd_stop() {
116
+ log_info "停止索引监听..."
117
+ local found=0
118
+ if pgrep -f "grepai watch" > /dev/null 2>&1; then
119
+ pkill -f "grepai watch" 2>/dev/null || true
120
+ log_ok "索引进程已停止"
121
+ found=1
122
+ fi
123
+ cleanup_locks
124
+ [ "$found" -eq 0 ] && log_warn "没有找到运行中的索引进程"
125
+ }
126
+
127
+ cmd_status() {
128
+ if [ ! -d "$INDEX_DIR" ]; then
129
+ log_warn "当前目录未初始化索引"
130
+ return 1
131
+ fi
132
+
133
+ echo ""
134
+ echo "┌─────────────────────────────────────────┐"
135
+ echo "│ Kimi 代码索引状态 │"
136
+ echo "├─────────────────────────────────────────┤"
137
+
138
+ if pgrep -f "grepai watch" > /dev/null 2>&1; then
139
+ echo "│ 🟢 守护进程 运行中 │"
140
+ else
141
+ echo "│ 🔴 守护进程 未运行 │"
142
+ fi
143
+
144
+ if grepai status 2>/dev/null | grep -q "indexed"; then
145
+ grepai status 2>/dev/null | head -6 | sed 's/^/│ /'
146
+ else
147
+ echo "│ ⚪ 索引数据 未建立 │"
148
+ fi
149
+
150
+ echo "│ │"
151
+ echo "│ 项目: $(basename "${PWD}")"
152
+ echo "└─────────────────────────────────────────┘"
153
+ echo ""
154
+ }
155
+
156
+ cmd_search() {
157
+ check_grepai; check_project
158
+ [ $# -eq 0 ] && { log_err "用法: kimi-index search \"关键词\""; exit 1; }
159
+ log_info "搜索: $*"
160
+ echo ""
161
+ grepai search "$*"
162
+ }
163
+
164
+ cmd_reset() {
165
+ local force=0
166
+ [ "$1" = "--force" ] || [ "$1" = "-f" ] && force=1
167
+
168
+ if [ "$force" -eq 0 ]; then
169
+ log_warn "即将删除所有索引数据!"
170
+ echo " 当前目录: ${PWD}"
171
+ echo " 输入 'yes' 确认:"
172
+ read -r confirm
173
+ [ "$confirm" != "yes" ] && { log_info "已取消"; return 0; }
174
+ fi
175
+
176
+ cmd_stop
177
+ [ -d "$INDEX_DIR" ] && rm -f "$INDEX_DIR"/*.gob "$INDEX_DIR"/*.lock 2>/dev/null || true
178
+ log_ok "索引数据已清除"
179
+ }
180
+
181
+ cmd_reindex() {
182
+ log_info "重新索引..."
183
+ cmd_stop
184
+ [ -d "$INDEX_DIR" ] && rm -f "$INDEX_DIR"/*.gob "$INDEX_DIR"/*.lock 2>/dev/null || true
185
+ cmd_start
186
+ }
187
+
188
+ cmd_logs() {
189
+ if [ -f /tmp/grepai-watch.log ]; then
190
+ log_info "索引日志:"
191
+ tail -20 /tmp/grepai-watch.log
192
+ else
193
+ log_warn "暂无日志"
194
+ fi
195
+ }
196
+
197
+ cmd_help() {
198
+ cat << 'EOF'
199
+
200
+ kimi-index — Kimi CLI 代码索引管理
201
+
202
+ 用法:
203
+ kimi-index start 启动索引监听(后台)
204
+ kimi-index stop 停止索引监听
205
+ kimi-index status 查看索引状态
206
+ kimi-index search "xxx" 手动语义搜索
207
+ kimi-index reset 重置索引数据
208
+ kimi-index reset -f 强制重置(免确认)
209
+ kimi-index reindex 重置并重新索引
210
+ kimi-index logs 查看索引日志
211
+ kimi-index help 帮助
212
+
213
+ EOF
214
+ }
215
+
216
+ main() {
217
+ local cmd="${1:-help}"
218
+ case "$cmd" in
219
+ start) cmd_start ;;
220
+ stop) cmd_stop ;;
221
+ status) cmd_status ;;
222
+ search) shift; cmd_search "$@" ;;
223
+ reset) shift; cmd_reset "$@" ;;
224
+ reindex) cmd_reindex ;;
225
+ logs) cmd_logs ;;
226
+ help|--help|-h) cmd_help ;;
227
+ *) log_err "未知命令: $cmd"; cmd_help; exit 1 ;;
228
+ esac
229
+ }
230
+
231
+ main "$@"