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.
- kimi_dev_workflow/__init__.py +3 -0
- kimi_dev_workflow/cli.py +45 -0
- kimi_dev_workflow/commands/__init__.py +1 -0
- kimi_dev_workflow/commands/doctor.py +119 -0
- kimi_dev_workflow/commands/index.py +84 -0
- kimi_dev_workflow/commands/init.py +242 -0
- kimi_dev_workflow/commands/memory.py +47 -0
- kimi_dev_workflow/commands/wiki.py +75 -0
- kimi_dev_workflow/config.py +52 -0
- kimi_dev_workflow/detector.py +130 -0
- kimi_dev_workflow/renderer.py +107 -0
- kimi_dev_workflow/scripts/kimi-index +231 -0
- kimi_dev_workflow/scripts/kimi-wiki +294 -0
- kimi_dev_workflow/scripts/release.sh +71 -0
- kimi_dev_workflow/templates/.grepaiignore.template +97 -0
- kimi_dev_workflow/templates/AGENTS.md.template +109 -0
- kimi_dev_workflow/templates/kimi_dir/README.md +144 -0
- kimi_dev_workflow/templates/kimi_dir/memory.md.template +53 -0
- kimi_dev_workflow/templates/kimi_dir/prompts/01-search.md +24 -0
- kimi_dev_workflow/templates/kimi_dir/prompts/02-code.md +33 -0
- kimi_dev_workflow/templates/kimi_dir/prompts/03-refactor.md +29 -0
- kimi_dev_workflow/templates/kimi_dir/prompts/04-debug.md +34 -0
- kimi_dev_workflow/templates/kimi_dir/prompts/05-review.md +31 -0
- kimi_dev_workflow/templates/kimi_dir/prompts/06-wiki.md +22 -0
- kimi_dev_workflow/templates/kimi_dir/prompts/07-memory.md +32 -0
- kimi_dev_workflow/utils.py +43 -0
- kimi_dev_workflow-0.1.0.dist-info/METADATA +317 -0
- kimi_dev_workflow-0.1.0.dist-info/RECORD +31 -0
- kimi_dev_workflow-0.1.0.dist-info/WHEEL +4 -0
- kimi_dev_workflow-0.1.0.dist-info/entry_points.txt +2 -0
- 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 "$@"
|