source-kb 0.2.2__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.
- cli/__init__.py +50 -0
- cli/__main__.py +5 -0
- cli/commands/__init__.py +1 -0
- cli/commands/anchor_fix.py +47 -0
- cli/commands/diff_doc.py +52 -0
- cli/commands/dispatch.py +77 -0
- cli/commands/extract.py +72 -0
- cli/commands/file_list.py +74 -0
- cli/commands/index.py +84 -0
- cli/commands/lock.py +89 -0
- cli/commands/merge.py +60 -0
- cli/commands/merge_delta.py +19 -0
- cli/commands/metadata.py +24 -0
- cli/commands/pipeline.py +45 -0
- cli/commands/post_merge.py +43 -0
- cli/commands/query.py +52 -0
- cli/commands/render.py +101 -0
- cli/commands/scan_repos.py +46 -0
- cli/commands/setup.py +94 -0
- cli/commands/split.py +196 -0
- cli/commands/stale_files.py +98 -0
- cli/commands/validate.py +191 -0
- core/__init__.py +32 -0
- core/config.py +261 -0
- core/docs/__init__.py +7 -0
- core/docs/section_updater.py +286 -0
- core/docs/shared.py +149 -0
- core/git.py +294 -0
- core/interfaces.py +249 -0
- core/monitor/__init__.py +5 -0
- core/monitor/progress.py +83 -0
- core/monitor/prompt_store.py +49 -0
- core/paths.py +141 -0
- core/preset.py +237 -0
- core/preset_accessors.py +202 -0
- core/preset_classify.py +132 -0
- core/preset_hooks.py +129 -0
- core/preset_profile.py +89 -0
- core/prompt/__init__.py +7 -0
- core/prompt/__main__.py +147 -0
- core/prompt/content.py +320 -0
- core/prompt/context_manager.py +164 -0
- core/prompt/renderer.py +236 -0
- core/prompt/response_parser.py +274 -0
- core/prompt/templates.py +357 -0
- core/prompt/validate_parity.py +162 -0
- core/prompt/variables.py +339 -0
- core/rag/__init__.py +22 -0
- core/rag/__main__.py +136 -0
- core/rag/bm25_index.py +268 -0
- core/rag/chunker.py +273 -0
- core/rag/embedder.py +151 -0
- core/rag/indexer.py +292 -0
- core/rag/loader.py +89 -0
- core/rag/retriever.py +82 -0
- core/skeleton/__init__.py +11 -0
- core/skeleton/__main__.py +934 -0
- core/skeleton/anchor_fix.py +250 -0
- core/skeleton/classify.py +331 -0
- core/skeleton/cmd_anchor_fix.py +43 -0
- core/skeleton/cmd_diff_doc.py +44 -0
- core/skeleton/cmd_lock.py +87 -0
- core/skeleton/cmd_merge_delta.py +41 -0
- core/skeleton/community.py +233 -0
- core/skeleton/dependency_graph.py +306 -0
- core/skeleton/diff_doc.py +248 -0
- core/skeleton/dispatch.py +273 -0
- core/skeleton/dispatch_render.py +319 -0
- core/skeleton/dispatch_source.py +111 -0
- core/skeleton/extract.py +218 -0
- core/skeleton/extract_methods.py +298 -0
- core/skeleton/file_list.py +239 -0
- core/skeleton/impact.py +278 -0
- core/skeleton/jar_download.py +177 -0
- core/skeleton/jar_resolver.py +186 -0
- core/skeleton/loader.py +162 -0
- core/skeleton/merge.py +278 -0
- core/skeleton/merge_delta.py +229 -0
- core/skeleton/metadata.py +96 -0
- core/skeleton/metadata_builders.py +264 -0
- core/skeleton/module_dag.py +330 -0
- core/skeleton/parsers/__init__.py +71 -0
- core/skeleton/parsers/jqassistant.py +300 -0
- core/skeleton/parsers/jqassistant_cypher.py +225 -0
- core/skeleton/parsers/regex.py +171 -0
- core/skeleton/parsers/treesitter.py +324 -0
- core/skeleton/parsers/treesitter_java.py +284 -0
- core/skeleton/parsers/treesitter_multi.py +289 -0
- core/skeleton/pom_parser.py +299 -0
- core/skeleton/post_merge.py +295 -0
- core/skeleton/post_merge_llm.py +82 -0
- core/skeleton/query.py +195 -0
- core/skeleton/shard_context.py +177 -0
- core/skeleton/split.py +180 -0
- core/skeleton/split_cache.py +107 -0
- core/skeleton/split_feedback.py +174 -0
- core/skeleton/split_plan.py +219 -0
- core/skeleton/split_plan_helpers.py +305 -0
- core/skeleton/split_plan_llm.py +274 -0
- core/utils.py +135 -0
- core/validators/__init__.py +65 -0
- core/validators/__main__.py +215 -0
- core/validators/consistency.py +203 -0
- core/validators/coverage.py +171 -0
- core/validators/duplicates.py +76 -0
- core/validators/engine.py +224 -0
- core/validators/links.py +76 -0
- core/validators/sampling.py +169 -0
- core/validators/structure.py +144 -0
- engine/__init__.py +7 -0
- engine/assembler.py +231 -0
- engine/confirm.py +65 -0
- engine/dedup.py +106 -0
- engine/main.py +211 -0
- engine/pipeline/__init__.py +163 -0
- engine/pipeline/recovery.py +250 -0
- engine/pipeline/steps/__init__.py +23 -0
- engine/pipeline/steps/audit.py +220 -0
- engine/pipeline/steps/audit_apply.py +195 -0
- engine/pipeline/steps/audit_helpers.py +155 -0
- engine/pipeline/steps/classify_llm.py +236 -0
- engine/pipeline/steps/classify_prompt.py +223 -0
- engine/pipeline/steps/finalize.py +160 -0
- engine/pipeline/steps/generate.py +169 -0
- engine/pipeline/steps/generate_batch.py +197 -0
- engine/pipeline/steps/generate_recovery.py +170 -0
- engine/pipeline/steps/llm_plan_split.py +253 -0
- engine/pipeline/steps/lock.py +64 -0
- engine/pipeline/steps/preflight.py +237 -0
- engine/pipeline/steps/preflight_adjust.py +147 -0
- engine/pipeline/steps/pregenerate.py +130 -0
- engine/pipeline/steps/quality.py +81 -0
- engine/pipeline/steps/skeleton.py +149 -0
- engine/pipeline/steps/source.py +163 -0
- engine/pipeline/steps/sync.py +117 -0
- engine/pipeline/steps/sync_finalize.py +237 -0
- engine/pipeline/steps/sync_update.py +341 -0
- engine/pipelines.py +91 -0
- engine/runner.py +335 -0
- engine/strategies/__init__.py +86 -0
- engine/strategies/api.py +128 -0
- engine/strategies/delegated.py +50 -0
- engine/strategies/dryrun.py +25 -0
- engine/two_phase.py +143 -0
- mcp_server/__init__.py +73 -0
- mcp_server/__main__.py +5 -0
- mcp_server/tools/__init__.py +1 -0
- mcp_server/tools/config.py +63 -0
- mcp_server/tools/discovery.py +276 -0
- mcp_server/tools/generation.py +184 -0
- mcp_server/tools/planning.py +144 -0
- mcp_server/tools/source.py +175 -0
- mcp_server/tools/validation.py +140 -0
- mcp_server/tools/workflow.py +166 -0
- mcp_server/workflow_loader.py +204 -0
- presets/generic/audit_dimensions.md +132 -0
- presets/generic/doc_types.yaml +152 -0
- presets/generic/preset.yaml +115 -0
- presets/java-spring/audit_dimensions.md +228 -0
- presets/java-spring/audit_dimensions.yaml +203 -0
- presets/java-spring/doc_types.yaml +269 -0
- presets/java-spring/hooks.py +122 -0
- presets/java-spring/preset.yaml +341 -0
- presets/java-spring/templates/README.md +34 -0
- presets/java-spring/templates/audit-system.md +15 -0
- presets/java-spring/templates/subagent-aop.md +105 -0
- presets/java-spring/templates/subagent-api.md +63 -0
- presets/java-spring/templates/subagent-architecture.md +111 -0
- presets/java-spring/templates/subagent-async-events.md +107 -0
- presets/java-spring/templates/subagent-audit-api-contracts.md +40 -0
- presets/java-spring/templates/subagent-audit-architecture.md +38 -0
- presets/java-spring/templates/subagent-audit-business.md +40 -0
- presets/java-spring/templates/subagent-audit-data-models.md +40 -0
- presets/java-spring/templates/subagent-business.md +129 -0
- presets/java-spring/templates/subagent-caching.md +75 -0
- presets/java-spring/templates/subagent-database-access.md +114 -0
- presets/java-spring/templates/subagent-enum.md +75 -0
- presets/java-spring/templates/subagent-error-handling.md +91 -0
- presets/java-spring/templates/subagent-external-integrations.md +80 -0
- presets/java-spring/templates/subagent-index.md +122 -0
- presets/java-spring/templates/subagent-messaging.md +97 -0
- presets/java-spring/templates/subagent-model.md +88 -0
- presets/java-spring/templates/subagent-observability.md +91 -0
- presets/java-spring/templates/subagent-scheduled.md +81 -0
- presets/java-spring/templates/subagent-security.md +102 -0
- presets/java-spring/templates/subagent-structure.md +101 -0
- presets/java-spring/templates/subagent-sync-section.md +34 -0
- presets/java-spring/templates/subagent-utils.md +73 -0
- presets/java-spring/templates/sync-system.md +8 -0
- presets/java-spring/workflow-extensions.md +112 -0
- skills/__init__.py +1 -0
- skills/_shared/README.md +30 -0
- skills/_shared/doc-coverage-shared.md +134 -0
- skills/_shared/doc-quality-standard.md +1058 -0
- skills/_shared/doc-subagent-rules.md +762 -0
- skills/_shared/windows-compat.md +89 -0
- skills/kb-audit/SKILL.md +52 -0
- skills/kb-audit/rules.md +88 -0
- skills/kb-audit/steps/step-01-prepare.md +75 -0
- skills/kb-audit/steps/step-02-audit.md +96 -0
- skills/kb-audit/steps/step-03-verify.md +65 -0
- skills/kb-audit/steps/step-04-report.md +64 -0
- skills/kb-init/SKILL.md +146 -0
- skills/kb-init/rules.md +187 -0
- skills/kb-init/steps/step-01-scope.md +62 -0
- skills/kb-init/steps/step-02-source.md +410 -0
- skills/kb-init/steps/step-03-generate.md +307 -0
- skills/kb-init/steps/step-04-quality.md +92 -0
- skills/kb-init/steps/step-05-finalize.md +132 -0
- skills/kb-init/templates/core/execution-modes.md +29 -0
- skills/kb-init/templates/core/output-only.md +4 -0
- skills/kb-init/templates/core/readwrite.md +33 -0
- skills/kb-search/SKILL.md +138 -0
- skills/kb-search/rules.md +64 -0
- skills/kb-sync/SKILL.md +43 -0
- skills/kb-sync/rules.md +70 -0
- skills/kb-sync/scripts/rebuild_module.py +91 -0
- skills/kb-sync/scripts/scan_repos.py +687 -0
- skills/kb-sync/steps/step-01-detect.md +72 -0
- skills/kb-sync/steps/step-02-update.md +71 -0
- skills/kb-sync/steps/step-03-verify.md +47 -0
- skills/kb-sync/steps/step-04-finalize.md +52 -0
- source_kb-0.2.2.dist-info/METADATA +194 -0
- source_kb-0.2.2.dist-info/RECORD +228 -0
- source_kb-0.2.2.dist-info/WHEEL +5 -0
- source_kb-0.2.2.dist-info/entry_points.txt +3 -0
- source_kb-0.2.2.dist-info/licenses/LICENSE +21 -0
- source_kb-0.2.2.dist-info/top_level.txt +6 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"""Workflow guidance tools — orchestration instructions for agents."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from mcp.server.fastmcp import FastMCP
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def register(mcp: FastMCP) -> None:
|
|
13
|
+
"""Register workflow tools on the MCP server."""
|
|
14
|
+
|
|
15
|
+
@mcp.tool()
|
|
16
|
+
def get_workflow(workflow: str, step: str = "", context: str = "{}") -> str:
|
|
17
|
+
"""Get workflow orchestration guidance. Returns step-by-step instructions for the agent to follow.
|
|
18
|
+
|
|
19
|
+
This is the core orchestration tool. The agent executes operations according to the returned
|
|
20
|
+
instructions and requests the next step after completing gate conditions.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
workflow: Workflow name (kb-init | kb-sync | kb-search | kb-audit)
|
|
24
|
+
step: Step identifier. Empty = return overview + first step guidance.
|
|
25
|
+
kb-init: step-01 | step-02 | step-03 | step-04 | step-05
|
|
26
|
+
kb-sync: step-01 | step-02 | step-03 | step-04
|
|
27
|
+
kb-audit: step-01 | step-02 | step-03 | step-04
|
|
28
|
+
context: JSON context, may contain {kb_name, module_name, capabilities: {can_spawn_subagents}}
|
|
29
|
+
"""
|
|
30
|
+
from mcp_server.workflow_loader import (
|
|
31
|
+
load_workflow_overview,
|
|
32
|
+
load_step_with_metadata,
|
|
33
|
+
WORKFLOW_MAP,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
ctx = json.loads(context) if context else {}
|
|
38
|
+
except (json.JSONDecodeError, TypeError):
|
|
39
|
+
ctx = {}
|
|
40
|
+
|
|
41
|
+
if workflow not in WORKFLOW_MAP:
|
|
42
|
+
return json.dumps({
|
|
43
|
+
"error": f"Unknown workflow: {workflow}",
|
|
44
|
+
"available": list(WORKFLOW_MAP.keys()),
|
|
45
|
+
}, ensure_ascii=False, indent=2)
|
|
46
|
+
|
|
47
|
+
if not step:
|
|
48
|
+
result = load_workflow_overview(workflow, ctx)
|
|
49
|
+
else:
|
|
50
|
+
result = load_step_with_metadata(workflow, step, ctx)
|
|
51
|
+
|
|
52
|
+
return json.dumps(result, ensure_ascii=False, indent=2)
|
|
53
|
+
|
|
54
|
+
@mcp.tool()
|
|
55
|
+
def get_subagent_prompt(
|
|
56
|
+
kb_name: str,
|
|
57
|
+
module_name: str,
|
|
58
|
+
doc_type: str,
|
|
59
|
+
shard: int = 0,
|
|
60
|
+
extras: str = "{}",
|
|
61
|
+
) -> str:
|
|
62
|
+
"""Render a complete sub-agent prompt that can be passed directly to a sub-agent for document generation.
|
|
63
|
+
|
|
64
|
+
Internally calls core.prompt.renderer.render_prompt to assemble template + skeleton + file list +
|
|
65
|
+
execution instructions, returning a ready-to-use prompt text.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
kb_name: Knowledge base name (key in kb-project.yaml)
|
|
69
|
+
module_name: Module name
|
|
70
|
+
doc_type: Document type (business-logic | api-contracts | data-models | ...)
|
|
71
|
+
shard: Shard index (0 = no sharding, 1+ = specific shard)
|
|
72
|
+
extras: Additional template variables in JSON format
|
|
73
|
+
"""
|
|
74
|
+
from mcp_server import find_config
|
|
75
|
+
from core.config import load_config
|
|
76
|
+
from core.preset import load_preset, get_template_path
|
|
77
|
+
from core.prompt.renderer import render_prompt
|
|
78
|
+
from core.prompt.variables import ReferencePromptAssembler
|
|
79
|
+
|
|
80
|
+
config_path = find_config()
|
|
81
|
+
if not config_path:
|
|
82
|
+
return json.dumps({"error": "kb-project.yaml not found"}, ensure_ascii=False)
|
|
83
|
+
|
|
84
|
+
config = load_config(config_path)
|
|
85
|
+
kb_cfg = config.get_kb(kb_name)
|
|
86
|
+
preset_name = kb_cfg.get("preset", "generic")
|
|
87
|
+
preset = load_preset(preset_name)
|
|
88
|
+
|
|
89
|
+
# Resolve template path
|
|
90
|
+
template_name = get_template_path(preset, doc_type, preset_name)
|
|
91
|
+
if not template_name:
|
|
92
|
+
template_name = f"subagent-{doc_type}.md"
|
|
93
|
+
|
|
94
|
+
from core.preset import find_preset_template
|
|
95
|
+
from mcp_server import PROJECT_ROOT
|
|
96
|
+
template_path = find_preset_template(preset_name, template_name)
|
|
97
|
+
if not template_path:
|
|
98
|
+
candidate = PROJECT_ROOT / "skills" / "kb-init" / "templates" / template_name
|
|
99
|
+
if candidate.exists():
|
|
100
|
+
template_path = candidate
|
|
101
|
+
|
|
102
|
+
if not template_path:
|
|
103
|
+
return json.dumps({
|
|
104
|
+
"error": f"Template not found: {template_name}",
|
|
105
|
+
"searched": [
|
|
106
|
+
f"presets/{preset_name}/templates/{template_name}",
|
|
107
|
+
f"skills/kb-init/templates/{template_name}",
|
|
108
|
+
],
|
|
109
|
+
}, ensure_ascii=False, indent=2)
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
extra_vars = json.loads(extras) if extras else {}
|
|
113
|
+
except (json.JSONDecodeError, TypeError):
|
|
114
|
+
extra_vars = {}
|
|
115
|
+
|
|
116
|
+
# Handle shard file list override
|
|
117
|
+
if shard > 0:
|
|
118
|
+
base_dir = Path(config.raw.get("_config_dir", config.config_path.parent))
|
|
119
|
+
kb_dir = Path(kb_cfg["knowledge_dir"])
|
|
120
|
+
if not kb_dir.is_absolute():
|
|
121
|
+
kb_dir = (base_dir / kb_dir).resolve()
|
|
122
|
+
module_dir = kb_dir / module_name
|
|
123
|
+
shard_file = module_dir / ".meta" / "shards" / f"{doc_type}-shard-{shard}.txt"
|
|
124
|
+
if shard_file.exists():
|
|
125
|
+
extra_vars["file_list_override"] = str(shard_file)
|
|
126
|
+
|
|
127
|
+
# Render prompt
|
|
128
|
+
assembler = ReferencePromptAssembler(
|
|
129
|
+
project_root=config.config_path.parent,
|
|
130
|
+
preset=preset,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
rendered = render_prompt(
|
|
134
|
+
template_path=template_path,
|
|
135
|
+
config=config.raw,
|
|
136
|
+
kb_name=kb_name,
|
|
137
|
+
module_name=module_name,
|
|
138
|
+
doc_type=doc_type,
|
|
139
|
+
assembler=assembler,
|
|
140
|
+
extras=extra_vars,
|
|
141
|
+
preset=preset,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Compute output path
|
|
145
|
+
base_dir = config.config_path.parent
|
|
146
|
+
kb_dir = Path(kb_cfg["knowledge_dir"])
|
|
147
|
+
if not kb_dir.is_absolute():
|
|
148
|
+
kb_dir = (base_dir / kb_dir).resolve()
|
|
149
|
+
module_dir = kb_dir / module_name
|
|
150
|
+
|
|
151
|
+
# Get filename from preset
|
|
152
|
+
doc_types = preset.get("doc_types", {})
|
|
153
|
+
dt_cfg = doc_types.get(doc_type, {})
|
|
154
|
+
filename = dt_cfg.get("filename", f"{doc_type}.md") if isinstance(dt_cfg, dict) else f"{doc_type}.md"
|
|
155
|
+
output_path = module_dir / filename
|
|
156
|
+
|
|
157
|
+
# Estimate tokens (~4 chars per token)
|
|
158
|
+
estimated_tokens = len(rendered) // 4
|
|
159
|
+
|
|
160
|
+
return json.dumps({
|
|
161
|
+
"status": "ok",
|
|
162
|
+
"prompt": rendered,
|
|
163
|
+
"output_path": str(output_path),
|
|
164
|
+
"estimated_tokens": estimated_tokens,
|
|
165
|
+
"timeout_seconds": 300 if estimated_tokens < 50000 else 600,
|
|
166
|
+
}, ensure_ascii=False, indent=2)
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"""Workflow content loader — reads skills/ files for get_workflow tool.
|
|
2
|
+
|
|
3
|
+
Supports two modes:
|
|
4
|
+
- Development: reads directly from skills/ directory on filesystem
|
|
5
|
+
- Installed package: reads from package data via importlib.resources
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import logging
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
# Project root (where skills/ lives in development)
|
|
18
|
+
_PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
19
|
+
|
|
20
|
+
WORKFLOW_MAP: dict[str, dict[str, str]] = {
|
|
21
|
+
"kb-init": {
|
|
22
|
+
"overview": "kb-init/SKILL.md",
|
|
23
|
+
"rules": "kb-init/rules.md",
|
|
24
|
+
"step-01": "kb-init/steps/step-01-scope.md",
|
|
25
|
+
"step-02": "kb-init/steps/step-02-source.md",
|
|
26
|
+
"step-03": "kb-init/steps/step-03-generate.md",
|
|
27
|
+
"step-04": "kb-init/steps/step-04-quality.md",
|
|
28
|
+
"step-05": "kb-init/steps/step-05-finalize.md",
|
|
29
|
+
},
|
|
30
|
+
"kb-sync": {
|
|
31
|
+
"overview": "kb-sync/SKILL.md",
|
|
32
|
+
"rules": "kb-sync/rules.md",
|
|
33
|
+
"step-01": "kb-sync/steps/step-01-detect.md",
|
|
34
|
+
"step-02": "kb-sync/steps/step-02-update.md",
|
|
35
|
+
"step-03": "kb-sync/steps/step-03-verify.md",
|
|
36
|
+
"step-04": "kb-sync/steps/step-04-finalize.md",
|
|
37
|
+
},
|
|
38
|
+
"kb-search": {
|
|
39
|
+
"overview": "kb-search/SKILL.md",
|
|
40
|
+
"rules": "kb-search/rules.md",
|
|
41
|
+
},
|
|
42
|
+
"kb-audit": {
|
|
43
|
+
"overview": "kb-audit/SKILL.md",
|
|
44
|
+
"rules": "kb-audit/rules.md",
|
|
45
|
+
"step-01": "kb-audit/steps/step-01-prepare.md",
|
|
46
|
+
"step-02": "kb-audit/steps/step-02-audit.md",
|
|
47
|
+
"step-03": "kb-audit/steps/step-03-verify.md",
|
|
48
|
+
"step-04": "kb-audit/steps/step-04-report.md",
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Tools needed per step (for agent guidance)
|
|
53
|
+
STEP_TOOLS: dict[str, dict[str, list[str]]] = {
|
|
54
|
+
"kb-init": {
|
|
55
|
+
"step-01": ["discover", "detect_project", "init_project"],
|
|
56
|
+
"step-02": ["skeleton_extract", "classify_files"],
|
|
57
|
+
"step-03": ["dispatch_plan", "get_subagent_prompt", "generate_doc"],
|
|
58
|
+
"step-04": ["coverage_check", "check_progress"],
|
|
59
|
+
"step-05": ["coverage_check"],
|
|
60
|
+
},
|
|
61
|
+
"kb-sync": {
|
|
62
|
+
"step-01": ["discover"],
|
|
63
|
+
"step-02": ["skeleton_extract", "classify_files", "get_subagent_prompt", "generate_doc"],
|
|
64
|
+
"step-03": ["coverage_check"],
|
|
65
|
+
"step-04": [],
|
|
66
|
+
},
|
|
67
|
+
"kb-search": {
|
|
68
|
+
"overview": ["discover"],
|
|
69
|
+
},
|
|
70
|
+
"kb-audit": {
|
|
71
|
+
"step-01": ["skeleton_extract"],
|
|
72
|
+
"step-02": ["get_subagent_prompt", "generate_doc", "coverage_check"],
|
|
73
|
+
"step-03": ["coverage_check"],
|
|
74
|
+
"step-04": [],
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _skills_dir() -> Path:
|
|
80
|
+
"""Locate skills/ directory."""
|
|
81
|
+
dev_path = _PROJECT_ROOT / "skills"
|
|
82
|
+
if dev_path.is_dir():
|
|
83
|
+
return dev_path
|
|
84
|
+
# Fallback: try importlib.resources for installed package
|
|
85
|
+
try:
|
|
86
|
+
from importlib import resources
|
|
87
|
+
ref = resources.files("skills")
|
|
88
|
+
# resources.files returns a Traversable; if it maps to a real dir, use it
|
|
89
|
+
if hasattr(ref, "_path"):
|
|
90
|
+
return Path(ref._path)
|
|
91
|
+
return Path(str(ref))
|
|
92
|
+
except (ImportError, ModuleNotFoundError, TypeError):
|
|
93
|
+
pass
|
|
94
|
+
return dev_path
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def load_step(workflow: str, step: str) -> str | None:
|
|
98
|
+
"""Load a single step's markdown content.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
workflow: Workflow name (kb-init, kb-sync, etc.)
|
|
102
|
+
step: Step identifier (overview, step-01, etc.)
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
Markdown content string, or None if not found.
|
|
106
|
+
"""
|
|
107
|
+
steps = WORKFLOW_MAP.get(workflow)
|
|
108
|
+
if not steps:
|
|
109
|
+
return None
|
|
110
|
+
rel_path = steps.get(step)
|
|
111
|
+
if not rel_path:
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
full_path = _skills_dir() / rel_path
|
|
115
|
+
if full_path.exists():
|
|
116
|
+
return full_path.read_text(encoding="utf-8")
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def load_workflow_overview(workflow: str, context: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
121
|
+
"""Load workflow overview with metadata for agent consumption.
|
|
122
|
+
|
|
123
|
+
Returns a structured dict with instructions, available steps, and guidance.
|
|
124
|
+
"""
|
|
125
|
+
steps = WORKFLOW_MAP.get(workflow)
|
|
126
|
+
if not steps:
|
|
127
|
+
return {
|
|
128
|
+
"error": f"Unknown workflow: {workflow}. Available: {list(WORKFLOW_MAP.keys())}"
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
overview_content = load_step(workflow, "overview")
|
|
132
|
+
rules_content = load_step(workflow, "rules")
|
|
133
|
+
|
|
134
|
+
available_steps = [s for s in steps.keys() if s.startswith("step-")]
|
|
135
|
+
|
|
136
|
+
result: dict[str, Any] = {
|
|
137
|
+
"workflow": workflow,
|
|
138
|
+
"instructions": overview_content or f"Workflow {workflow} overview not found.",
|
|
139
|
+
"available_steps": available_steps,
|
|
140
|
+
"next_step": available_steps[0] if available_steps else None,
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if rules_content:
|
|
144
|
+
result["rules"] = rules_content
|
|
145
|
+
|
|
146
|
+
return result
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def load_step_with_metadata(workflow: str, step: str, context: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
150
|
+
"""Load a step with full metadata for agent consumption.
|
|
151
|
+
|
|
152
|
+
Returns structured dict with instructions, gate conditions, next step, and tools needed.
|
|
153
|
+
"""
|
|
154
|
+
content = load_step(workflow, step)
|
|
155
|
+
if content is None:
|
|
156
|
+
return {"error": f"Step '{step}' not found in workflow '{workflow}'."}
|
|
157
|
+
|
|
158
|
+
steps = WORKFLOW_MAP.get(workflow, {})
|
|
159
|
+
available_steps = sorted([s for s in steps.keys() if s.startswith("step-")])
|
|
160
|
+
|
|
161
|
+
# Determine next step
|
|
162
|
+
next_step = None
|
|
163
|
+
if step in available_steps:
|
|
164
|
+
idx = available_steps.index(step)
|
|
165
|
+
if idx + 1 < len(available_steps):
|
|
166
|
+
next_step = available_steps[idx + 1]
|
|
167
|
+
|
|
168
|
+
# Get tools needed for this step
|
|
169
|
+
tools = STEP_TOOLS.get(workflow, {}).get(step, [])
|
|
170
|
+
|
|
171
|
+
result: dict[str, Any] = {
|
|
172
|
+
"workflow": workflow,
|
|
173
|
+
"step": step,
|
|
174
|
+
"instructions": content,
|
|
175
|
+
"next_step": next_step,
|
|
176
|
+
"tools_needed": tools,
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
# Include rules if this is step-01 (agent needs them upfront)
|
|
180
|
+
if step == "step-01":
|
|
181
|
+
rules = load_step(workflow, "rules")
|
|
182
|
+
if rules:
|
|
183
|
+
result["rules"] = rules
|
|
184
|
+
|
|
185
|
+
return result
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def list_workflows() -> list[dict[str, Any]]:
|
|
189
|
+
"""List all available workflows with brief descriptions."""
|
|
190
|
+
descriptions = {
|
|
191
|
+
"kb-init": "Initialize knowledge base: clone source -> extract skeleton -> generate docs -> quality check",
|
|
192
|
+
"kb-sync": "Incremental sync: detect changes -> update affected docs -> verify coverage",
|
|
193
|
+
"kb-search": "Knowledge base search: route questions to relevant docs, return answers with citations",
|
|
194
|
+
"kb-audit": "Quality audit: check each document against quality dimensions, generate audit report",
|
|
195
|
+
}
|
|
196
|
+
result = []
|
|
197
|
+
for name, steps in WORKFLOW_MAP.items():
|
|
198
|
+
step_count = len([s for s in steps if s.startswith("step-")])
|
|
199
|
+
result.append({
|
|
200
|
+
"name": name,
|
|
201
|
+
"description": descriptions.get(name, ""),
|
|
202
|
+
"steps": step_count,
|
|
203
|
+
})
|
|
204
|
+
return result
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# 通用检查维度
|
|
2
|
+
|
|
3
|
+
> 语言无关的自检维度,配合 `doc-quality-standard.md` 和 `doc-coverage-shared.md` 使用。
|
|
4
|
+
> 如需 Java/Spring Boot 特定维度,请使用 `presets/java-spring/audit_dimensions.md`。
|
|
5
|
+
|
|
6
|
+
## source-tree-analysis.md
|
|
7
|
+
|
|
8
|
+
修复标准见 `doc-quality-standard.md` 5.7 节(完整文件树 + 每文件详解格式 + 内容深度基准)。
|
|
9
|
+
|
|
10
|
+
1. 文件完整性 — 文档列出的每个文件在源码中存在
|
|
11
|
+
2. 目录结构 — 目录层级与实际一致
|
|
12
|
+
3. 文件职责描述 — 描述与文件的实际功能匹配(检查注释、导出、继承)
|
|
13
|
+
4. 文件数统计 — 文档中的计数与实际一致
|
|
14
|
+
5. 新增/删除文件 — 源码变动在文档中反映
|
|
15
|
+
|
|
16
|
+
## index.md
|
|
17
|
+
|
|
18
|
+
修复标准见 `doc-quality-standard.md` 5.8 节(基本信息表 + 接口总览表 + 缓存策略概览表 + 文档导航 + 内容深度基准)。
|
|
19
|
+
|
|
20
|
+
1. 链接有效性 — 所有 `[text](file.md)` 链接指向存在的文件
|
|
21
|
+
2. 文件数/统计 — 引用的数量与实际一致
|
|
22
|
+
3. 模块描述 — 概述与模块实际功能匹配
|
|
23
|
+
4. 文档完整性 — 所有 .md 文件都在 index.md 中有链接
|
|
24
|
+
|
|
25
|
+
## architecture.md
|
|
26
|
+
|
|
27
|
+
对比源:依赖配置文件(`pom.xml`、`package.json`、`go.mod`、`requirements.txt` 等)、应用配置文件、框架初始化代码。
|
|
28
|
+
|
|
29
|
+
1. 技术栈版本 — 框架、运行时、中间件版本与依赖配置一致
|
|
30
|
+
2. 依赖清单 — 无遗漏的关键依赖
|
|
31
|
+
3. 分层结构 — 模块分层与实际目录/包结构一致
|
|
32
|
+
4. 中间件配置 — 数据库、缓存、消息队列等配置与实际一致
|
|
33
|
+
5. 组件关系 — 远程调用、服务间依赖关系与源码一致
|
|
34
|
+
6. 配置项 — 关键配置项在文档中有记录
|
|
35
|
+
|
|
36
|
+
## data-models.md
|
|
37
|
+
|
|
38
|
+
对比源:模型/实体定义目录(`domain/`、`models/`、`entities/`、`schemas/`、`types/` 等)。
|
|
39
|
+
|
|
40
|
+
1. 实体完整性 — 每个模型/实体类在文档中有记录
|
|
41
|
+
2. 字段一致性 — 字段名、类型与源码一致
|
|
42
|
+
3. 表名映射 — 文档中的表名/集合名与 ORM 映射一致
|
|
43
|
+
4. DTO/VO 覆盖 — 请求/响应数据结构在文档中有记录
|
|
44
|
+
5. 枚举值 — 枚举/常量的所有值完整列出
|
|
45
|
+
6. 继承/实现 — 继承关系、实现的接口与源码一致
|
|
46
|
+
|
|
47
|
+
## api-contracts.md
|
|
48
|
+
|
|
49
|
+
对比源:路由定义、控制器、API handler 目录。
|
|
50
|
+
|
|
51
|
+
1. 接口完整性 — 每个 API 端点在文档中有记录
|
|
52
|
+
2. URL 路径 — 路由路径与文档一致
|
|
53
|
+
3. HTTP 方法 — GET/POST/PUT/DELETE 与源码一致
|
|
54
|
+
4. 请求参数 — 参数名、类型、是否必填与源码一致
|
|
55
|
+
5. 响应类型 — 返回值类型与文档一致
|
|
56
|
+
6. 错误码 — 方法中返回的错误码在文档中有记录
|
|
57
|
+
|
|
58
|
+
## business-logic.md
|
|
59
|
+
|
|
60
|
+
按 `doc-quality-standard.md` 第 5 节 10 项维度,额外关注以下通用模式:
|
|
61
|
+
|
|
62
|
+
1. 事务边界 — 事务注解/装饰器的传播级别、回滚规则
|
|
63
|
+
2. 异步处理 — 异步任务的线程池/队列配置
|
|
64
|
+
3. 定时任务 — cron 表达式、执行频率
|
|
65
|
+
4. 消息消费 — topic、消费组、并发配置
|
|
66
|
+
5. 缓存策略 — 缓存 key、TTL、失效策略
|
|
67
|
+
6. 限流/熔断 — 资源名、降级策略
|
|
68
|
+
7. 重试机制 — 重试次数、退避策略
|
|
69
|
+
8. 外部配置 — 配置项 key、默认值
|
|
70
|
+
|
|
71
|
+
## observability.md
|
|
72
|
+
|
|
73
|
+
对比源:监控指标注册代码、日志配置文件、健康检查端点。
|
|
74
|
+
|
|
75
|
+
1. 指标完整性 — 所有自定义监控指标在文档中有记录
|
|
76
|
+
2. 指标名称 — metric name 与源码中注册的一致
|
|
77
|
+
3. 告警阈值 — 阈值配置与源码/配置文件一致
|
|
78
|
+
4. 日志配置 — 日志级别、格式、输出目标与配置一致
|
|
79
|
+
5. 健康检查 — 自定义健康检查端点与源码一致
|
|
80
|
+
|
|
81
|
+
## utils.md
|
|
82
|
+
|
|
83
|
+
对比源:`util/`、`utils/`、`helper/`、`common/`、`lib/` 目录。
|
|
84
|
+
|
|
85
|
+
1. 工具类完整性 — 有复杂逻辑的工具方法在文档中有记录
|
|
86
|
+
2. 方法签名准确性 — 参数类型、返回类型与源码一致
|
|
87
|
+
3. 边界行为 — null 处理、精度丢失、时区问题等隐式行为与源码一致
|
|
88
|
+
4. 线程安全性 — 并发相关设计(如有)与源码一致
|
|
89
|
+
5. 使用上下文 — 高频调用方法的典型调用场景与实际使用一致
|
|
90
|
+
|
|
91
|
+
## 可选文档
|
|
92
|
+
|
|
93
|
+
### 可选文档触发条件
|
|
94
|
+
|
|
95
|
+
扫描源码时,命中以下模式则对应文档变为必需:
|
|
96
|
+
|
|
97
|
+
| 文档 | 触发模式(任一命中即触发) |
|
|
98
|
+
|------|------------------------|
|
|
99
|
+
| messaging.md | 目录名含 `/consumer/`、`/listener/`、`/subscriber/`;文件名含 `*consumer*`、`*listener*`、`*producer*`、`*publisher*`;代码中引用 Kafka/RabbitMQ/Pulsar/RocketMQ 等消息队列客户端 |
|
|
100
|
+
| caching.md | 目录名含 `/cache/`、`/redis/`;文件名含 `*cache*`、`*redis*`;代码中引用 Redis/Memcached/Caffeine 等缓存客户端 |
|
|
101
|
+
| external-integrations.md | 代码中使用 HTTP 客户端库发起外部调用(排除内部服务间 RPC/Feign 调用) |
|
|
102
|
+
|
|
103
|
+
检测命令示例:
|
|
104
|
+
```shell
|
|
105
|
+
# 检测消息队列使用(通用模式)
|
|
106
|
+
git -C {repo} grep -rl "consumer\|listener\|producer\|publisher" {ref} -- "*/consumer/*" "*/listener/*" "*/mq/*"
|
|
107
|
+
|
|
108
|
+
# 检测缓存使用(通用模式)
|
|
109
|
+
git -C {repo} grep -rl "cache\|redis\|memcache" {ref} -- "*/cache/*" "*/redis/*"
|
|
110
|
+
|
|
111
|
+
# 检测外部 HTTP 调用(通用模式)
|
|
112
|
+
git -C {repo} grep -rl "HttpClient\|http\.request\|requests\.get\|fetch(" {ref}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### messaging.md
|
|
116
|
+
|
|
117
|
+
1. Topic/Queue 完整性 — 所有消息生产/消费的 topic/queue 有记录
|
|
118
|
+
2. 消息体结构 — 生产者发送的对象类型与文档一致
|
|
119
|
+
3. 消费者分组 — 消费组 ID 与源码一致
|
|
120
|
+
4. 生产/消费关系 — 哪个类生产、哪个类消费与源码一致
|
|
121
|
+
|
|
122
|
+
### caching.md
|
|
123
|
+
|
|
124
|
+
1. Key/Cache 完整性 — 所有缓存操作的 key pattern/cache name 有记录
|
|
125
|
+
2. TTL — 过期时间与源码一致
|
|
126
|
+
3. 数据类型 — 使用的数据结构类型与源码一致
|
|
127
|
+
|
|
128
|
+
### external-integrations.md
|
|
129
|
+
|
|
130
|
+
1. 集成方完整性 — 所有外部 HTTP/SDK 调用有记录
|
|
131
|
+
2. 接口地址 — URL/配置项与源码一致
|
|
132
|
+
3. 认证方式 — Token/签名/OAuth 与源码一致
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Generic Preset — doc_types 配置
|
|
2
|
+
# 适用于非 Java 项目(Python, Go, Node.js, Rust 等)
|
|
3
|
+
|
|
4
|
+
doc_types:
|
|
5
|
+
# Batch 1: 全局概览(无源码依赖)
|
|
6
|
+
source-tree-analysis:
|
|
7
|
+
filename: "source-tree-analysis.md"
|
|
8
|
+
batch: 1
|
|
9
|
+
global_view: true
|
|
10
|
+
conditional: false
|
|
11
|
+
search_keywords: ["目录结构", "文件树", "类职责", "包结构", "文件", "源码结构"]
|
|
12
|
+
size_expectations:
|
|
13
|
+
min: 500
|
|
14
|
+
warn_max: 30000
|
|
15
|
+
hard_max: 60000
|
|
16
|
+
|
|
17
|
+
# Batch 2: 数据层
|
|
18
|
+
data-models:
|
|
19
|
+
filename: "data-models.md"
|
|
20
|
+
batch: 2
|
|
21
|
+
conditional: false
|
|
22
|
+
search_keywords: ["表", "字段", "实体", "模型", "Schema", "类型定义"]
|
|
23
|
+
dedup_patterns: ["| 字段 | 类型 |", "字段表格"]
|
|
24
|
+
size_expectations:
|
|
25
|
+
min: 500
|
|
26
|
+
warn_max: 50000
|
|
27
|
+
hard_max: 80000
|
|
28
|
+
|
|
29
|
+
# Batch 3: API + 架构 + 可选文档
|
|
30
|
+
api-contracts:
|
|
31
|
+
filename: "api-contracts.md"
|
|
32
|
+
batch: 3
|
|
33
|
+
conditional: true
|
|
34
|
+
search_keywords: ["接口", "API", "参数", "错误码", "URL", "端点", "路由"]
|
|
35
|
+
depends_on: ["data-models"]
|
|
36
|
+
size_expectations:
|
|
37
|
+
min: 500
|
|
38
|
+
warn_max: 50000
|
|
39
|
+
hard_max: 80000
|
|
40
|
+
|
|
41
|
+
architecture:
|
|
42
|
+
filename: "architecture.md"
|
|
43
|
+
batch: 3
|
|
44
|
+
conditional: false
|
|
45
|
+
search_keywords: ["架构", "依赖", "配置", "技术栈", "中间件", "分层"]
|
|
46
|
+
size_expectations:
|
|
47
|
+
min: 500
|
|
48
|
+
warn_max: 40000
|
|
49
|
+
hard_max: 60000
|
|
50
|
+
|
|
51
|
+
external-integrations:
|
|
52
|
+
filename: "external-integrations.md"
|
|
53
|
+
batch: 3
|
|
54
|
+
conditional: true
|
|
55
|
+
search_keywords: ["外部调用", "HTTP", "SDK", "第三方", "远程服务"]
|
|
56
|
+
size_expectations:
|
|
57
|
+
min: 500
|
|
58
|
+
warn_max: 30000
|
|
59
|
+
hard_max: 50000
|
|
60
|
+
|
|
61
|
+
observability:
|
|
62
|
+
filename: "observability.md"
|
|
63
|
+
batch: 3
|
|
64
|
+
conditional: true
|
|
65
|
+
search_keywords: ["监控", "指标", "日志", "告警", "Metrics", "健康检查"]
|
|
66
|
+
size_expectations:
|
|
67
|
+
min: 500
|
|
68
|
+
warn_max: 30000
|
|
69
|
+
hard_max: 50000
|
|
70
|
+
|
|
71
|
+
# Batch 4: 业务逻辑 + 工具类
|
|
72
|
+
business-logic:
|
|
73
|
+
filename: "business-logic.md"
|
|
74
|
+
batch: 4
|
|
75
|
+
conditional: false
|
|
76
|
+
search_keywords: ["怎么实现", "流程", "调用链", "业务逻辑", "方法实现"]
|
|
77
|
+
depends_on: ["data-models", "api-contracts"]
|
|
78
|
+
size_expectations:
|
|
79
|
+
min: 1000
|
|
80
|
+
warn_max: 60000
|
|
81
|
+
hard_max: 100000
|
|
82
|
+
split_override:
|
|
83
|
+
readwrite:
|
|
84
|
+
max_lines: 8000
|
|
85
|
+
max_files_per_shard: 60
|
|
86
|
+
|
|
87
|
+
utils:
|
|
88
|
+
filename: "utils.md"
|
|
89
|
+
batch: 4
|
|
90
|
+
conditional: true
|
|
91
|
+
search_keywords: ["工具类", "工具方法", "Util", "Helper", "Common"]
|
|
92
|
+
depends_on: ["data-models"]
|
|
93
|
+
size_expectations:
|
|
94
|
+
min: 500
|
|
95
|
+
warn_max: 30000
|
|
96
|
+
hard_max: 50000
|
|
97
|
+
|
|
98
|
+
# Batch 5: 索引(全局汇总)
|
|
99
|
+
index:
|
|
100
|
+
filename: "index.md"
|
|
101
|
+
batch: 5
|
|
102
|
+
global_view: true
|
|
103
|
+
conditional: false
|
|
104
|
+
search_keywords: ["概览", "模块介绍", "有哪些功能", "导航", "索引"]
|
|
105
|
+
depends_on: ["business-logic", "architecture", "data-models"]
|
|
106
|
+
size_expectations:
|
|
107
|
+
min: 500
|
|
108
|
+
warn_max: 20000
|
|
109
|
+
hard_max: 40000
|
|
110
|
+
|
|
111
|
+
# ============================================================
|
|
112
|
+
# Split 阈值
|
|
113
|
+
# ============================================================
|
|
114
|
+
split:
|
|
115
|
+
output-only:
|
|
116
|
+
max_bytes: 307200
|
|
117
|
+
max_lines: 8000
|
|
118
|
+
max_files_per_shard: 80
|
|
119
|
+
llm_sample_limit: 200 # [CLI only] Max files sampled for LLM-based split grouping
|
|
120
|
+
readwrite:
|
|
121
|
+
max_bytes: 512000
|
|
122
|
+
max_lines: 10000
|
|
123
|
+
max_files_per_shard: 80
|
|
124
|
+
# [Both modes] Noise words filtered when deriving shard group names from class names
|
|
125
|
+
noise_words:
|
|
126
|
+
- service
|
|
127
|
+
- impl
|
|
128
|
+
- base
|
|
129
|
+
- controller
|
|
130
|
+
- manager
|
|
131
|
+
- handler
|
|
132
|
+
- listener
|
|
133
|
+
- api
|
|
134
|
+
- abstract
|
|
135
|
+
- default
|
|
136
|
+
|
|
137
|
+
# ============================================================
|
|
138
|
+
# Limits
|
|
139
|
+
# ============================================================
|
|
140
|
+
limits:
|
|
141
|
+
min_doc_size_bytes: 500
|
|
142
|
+
max_source_inline_bytes: 300000
|
|
143
|
+
max_skeleton_inline_bytes: 50000
|
|
144
|
+
spawn_timeout_default: 600
|
|
145
|
+
max_retries: 2
|
|
146
|
+
max_consecutive_failures: 3
|
|
147
|
+
failure_rate_threshold: 0.5
|
|
148
|
+
garbage_patterns:
|
|
149
|
+
- "<web_search>"
|
|
150
|
+
- "<read_file>"
|
|
151
|
+
- "<search_results>"
|
|
152
|
+
- "Search results for"
|