ckgraphify 0.1.3__tar.gz → 0.2.0__tar.gz
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.
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/PKG-INFO +8 -8
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/README.md +7 -7
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/ckgraphify.egg-info/SOURCES.txt +2 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/__main__.py +42 -17
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/business_map.py +71 -8
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/graph_main_backend.py +158 -31
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/graph_main_frontend.py +718 -31
- ckgraphify-0.2.0/graphify/graph_main_frontend_sdk.py +789 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/graph_main_html.py +1 -1
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/graph_main_merge.py +90 -18
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/graph_main_trace.py +76 -7
- ckgraphify-0.2.0/graphify/repo_registry.py +252 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/pyproject.toml +1 -1
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/skill/skill-codex.md +28 -12
- ckgraphify-0.2.0/skill/skill.md +132 -0
- ckgraphify-0.1.3/skill/skill.md +0 -188
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/LICENSE +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/MANIFEST.in +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/__init__.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/analyze.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/benchmark.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/bridge_mtop.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/build.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/cache.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/callflow_html.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/cluster.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/dedup.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/detect.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/export.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/extract.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/global_graph.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/google_workspace.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/hooks.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/ingest.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/llm.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/manifest.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/report.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/security.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/serve.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/transcribe.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/tree_html.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/validate.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/watch.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/graphify/wiki.py +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/setup.cfg +0 -0
- {ckgraphify-0.1.3 → ckgraphify-0.2.0}/skill/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ckgraphify
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: AI coding assistant skill for Claude Code and Codex - graph-main boundary graphs, multi-repo call chains, business-map concepts, and business search
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/safishamsi/graphify
|
|
@@ -106,17 +106,17 @@ python3 -m pip install -e ./ckgraphify && CLAUDE_PLUGIN_ROOT=/Users/alsc/code/sh
|
|
|
106
106
|
|
|
107
107
|
## 生成并合并仓库图谱
|
|
108
108
|
|
|
109
|
-
下面命令会分别进入 `${CLAUDE_PLUGIN_ROOT}/repos/kl-health` 和 `${CLAUDE_PLUGIN_ROOT}/repos/ele-newretail-health-audit` 生成 `graphify-out/graph-main.json`,然后合并到 `${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
109
|
+
下面命令会分别进入 `${CLAUDE_PLUGIN_ROOT}/repos/kl-health` 和 `${CLAUDE_PLUGIN_ROOT}/repos/ele-newretail-health-audit` 生成 `graphify-out/graph-main.json`,然后合并到 `${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json`。
|
|
110
110
|
|
|
111
111
|
```bash
|
|
112
|
-
scripts/graph-main-repos.sh --repos-root "${CLAUDE_PLUGIN_ROOT}/repos" --out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
112
|
+
scripts/graph-main-repos.sh --repos-root "${CLAUDE_PLUGIN_ROOT}/repos" --out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json" kl-health ele-newretail-health-audit
|
|
113
113
|
```
|
|
114
114
|
|
|
115
115
|
也可以传入更多 `${CLAUDE_PLUGIN_ROOT}/repos/` 下的仓库名:
|
|
116
116
|
|
|
117
117
|
```bash
|
|
118
118
|
# 健康卡 init all repos
|
|
119
|
-
scripts/graph-main-repos.sh --repos-root "${CLAUDE_PLUGIN_ROOT}/repos" --out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
119
|
+
scripts/graph-main-repos.sh --repos-root "${CLAUDE_PLUGIN_ROOT}/repos" --out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json" ele-newretail-drug ele-newretail-health-task ele-newretail-drug-grow ele-newretail-health-audit ele-newretail-health-client ele-newretail-drug-trade kl-health health-vip-card medicine-unicore p ele-newretail-venus ele-newretail-summaryx china-alsc-sales-eleme-newretail-app
|
|
120
120
|
```
|
|
121
121
|
|
|
122
122
|
```bash
|
|
@@ -124,7 +124,7 @@ scripts/graph-main-repos.sh --repos-root "${CLAUDE_PLUGIN_ROOT}/repos" --out "${
|
|
|
124
124
|
scripts/graph-main-repos.sh \
|
|
125
125
|
--incremental \
|
|
126
126
|
--repos-root "${CLAUDE_PLUGIN_ROOT}/repos" \
|
|
127
|
-
--out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
127
|
+
--out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json" \
|
|
128
128
|
p medicine-unicore
|
|
129
129
|
```
|
|
130
130
|
|
|
@@ -136,7 +136,7 @@ scripts/graph-main-repos.sh \
|
|
|
136
136
|
关于ehealth-member实体的全部链路
|
|
137
137
|
```bash
|
|
138
138
|
graphify main-trace \
|
|
139
|
-
--graph "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
139
|
+
--graph "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json" \
|
|
140
140
|
--from ehealth-member \
|
|
141
141
|
--max-depth 8
|
|
142
142
|
```
|
|
@@ -144,7 +144,7 @@ graphify main-trace \
|
|
|
144
144
|
选择ehealth-member实体的/shopping/healthCard/createHealthCard 支线链路
|
|
145
145
|
```bash
|
|
146
146
|
graphify main-trace \
|
|
147
|
-
--graph "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
147
|
+
--graph "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json" \
|
|
148
148
|
--from ehealth-member \
|
|
149
149
|
--api /shopping/healthCard/createHealthCard \
|
|
150
150
|
--max-depth 8
|
|
@@ -154,7 +154,7 @@ graphify main-trace \
|
|
|
154
154
|
|
|
155
155
|
```bash
|
|
156
156
|
graphify main-trace \
|
|
157
|
-
--graph "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
157
|
+
--graph "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json" \
|
|
158
158
|
--from ehealth-member \
|
|
159
159
|
--max-depth 8 --sources
|
|
160
160
|
```
|
|
@@ -13,17 +13,17 @@ python3 -m pip install -e ./ckgraphify && CLAUDE_PLUGIN_ROOT=/Users/alsc/code/sh
|
|
|
13
13
|
|
|
14
14
|
## 生成并合并仓库图谱
|
|
15
15
|
|
|
16
|
-
下面命令会分别进入 `${CLAUDE_PLUGIN_ROOT}/repos/kl-health` 和 `${CLAUDE_PLUGIN_ROOT}/repos/ele-newretail-health-audit` 生成 `graphify-out/graph-main.json`,然后合并到 `${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
16
|
+
下面命令会分别进入 `${CLAUDE_PLUGIN_ROOT}/repos/kl-health` 和 `${CLAUDE_PLUGIN_ROOT}/repos/ele-newretail-health-audit` 生成 `graphify-out/graph-main.json`,然后合并到 `${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json`。
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
scripts/graph-main-repos.sh --repos-root "${CLAUDE_PLUGIN_ROOT}/repos" --out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
19
|
+
scripts/graph-main-repos.sh --repos-root "${CLAUDE_PLUGIN_ROOT}/repos" --out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json" kl-health ele-newretail-health-audit
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
也可以传入更多 `${CLAUDE_PLUGIN_ROOT}/repos/` 下的仓库名:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
25
|
# 健康卡 init all repos
|
|
26
|
-
scripts/graph-main-repos.sh --repos-root "${CLAUDE_PLUGIN_ROOT}/repos" --out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
26
|
+
scripts/graph-main-repos.sh --repos-root "${CLAUDE_PLUGIN_ROOT}/repos" --out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json" ele-newretail-drug ele-newretail-health-task ele-newretail-drug-grow ele-newretail-health-audit ele-newretail-health-client ele-newretail-drug-trade kl-health health-vip-card medicine-unicore p ele-newretail-venus ele-newretail-summaryx china-alsc-sales-eleme-newretail-app
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
```bash
|
|
@@ -31,7 +31,7 @@ scripts/graph-main-repos.sh --repos-root "${CLAUDE_PLUGIN_ROOT}/repos" --out "${
|
|
|
31
31
|
scripts/graph-main-repos.sh \
|
|
32
32
|
--incremental \
|
|
33
33
|
--repos-root "${CLAUDE_PLUGIN_ROOT}/repos" \
|
|
34
|
-
--out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
34
|
+
--out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json" \
|
|
35
35
|
p medicine-unicore
|
|
36
36
|
```
|
|
37
37
|
|
|
@@ -43,7 +43,7 @@ scripts/graph-main-repos.sh \
|
|
|
43
43
|
关于ehealth-member实体的全部链路
|
|
44
44
|
```bash
|
|
45
45
|
graphify main-trace \
|
|
46
|
-
--graph "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
46
|
+
--graph "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json" \
|
|
47
47
|
--from ehealth-member \
|
|
48
48
|
--max-depth 8
|
|
49
49
|
```
|
|
@@ -51,7 +51,7 @@ graphify main-trace \
|
|
|
51
51
|
选择ehealth-member实体的/shopping/healthCard/createHealthCard 支线链路
|
|
52
52
|
```bash
|
|
53
53
|
graphify main-trace \
|
|
54
|
-
--graph "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
54
|
+
--graph "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json" \
|
|
55
55
|
--from ehealth-member \
|
|
56
56
|
--api /shopping/healthCard/createHealthCard \
|
|
57
57
|
--max-depth 8
|
|
@@ -61,7 +61,7 @@ graphify main-trace \
|
|
|
61
61
|
|
|
62
62
|
```bash
|
|
63
63
|
graphify main-trace \
|
|
64
|
-
--graph "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph
|
|
64
|
+
--graph "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph.json" \
|
|
65
65
|
--from ehealth-member \
|
|
66
66
|
--max-depth 8 --sources
|
|
67
67
|
```
|
|
@@ -20,6 +20,7 @@ graphify/global_graph.py
|
|
|
20
20
|
graphify/google_workspace.py
|
|
21
21
|
graphify/graph_main_backend.py
|
|
22
22
|
graphify/graph_main_frontend.py
|
|
23
|
+
graphify/graph_main_frontend_sdk.py
|
|
23
24
|
graphify/graph_main_html.py
|
|
24
25
|
graphify/graph_main_merge.py
|
|
25
26
|
graphify/graph_main_trace.py
|
|
@@ -27,6 +28,7 @@ graphify/hooks.py
|
|
|
27
28
|
graphify/ingest.py
|
|
28
29
|
graphify/llm.py
|
|
29
30
|
graphify/manifest.py
|
|
31
|
+
graphify/repo_registry.py
|
|
30
32
|
graphify/report.py
|
|
31
33
|
graphify/security.py
|
|
32
34
|
graphify/serve.py
|
|
@@ -570,10 +570,11 @@ def main() -> None:
|
|
|
570
570
|
print(" merge-main-graphs <graph-main.json...> merge multiple graph-main boundary graphs")
|
|
571
571
|
print(" --out <path> output path (default: graphify-out/graph-main-merged.json)")
|
|
572
572
|
print(" --report <path> report path (default: graphify-out/graph-main-merged-report.md)")
|
|
573
|
+
print(" repo-list [path] create/update editable repo-list.json from ./repos git remotes")
|
|
573
574
|
print(" main-trace --graph <path> --from <node> [--api <api>] [--max-depth N] [--sources] [--prefer-repo R] [--exclude-repo R]")
|
|
574
575
|
print(" trace a graph-main chain from an exact entry/API")
|
|
575
|
-
print(" business-init --concept <name> [--out graphify-out/business-map.json]")
|
|
576
|
-
print(" create a business-map
|
|
576
|
+
print(" business-init --concept <name> [--out graphify-out/business-map.json] [--force]")
|
|
577
|
+
print(" create a business-map or append an unexplored concept")
|
|
577
578
|
print(" business-show [--map <path>] [--concept <name>] [--scenario <name>]")
|
|
578
579
|
print(" inspect concepts, scenarios, anchors, and trace hints")
|
|
579
580
|
print(" business-query \"question\" [--map <path>] [--graph <path>] [--trace] [--sources] [--format json|text]")
|
|
@@ -1329,9 +1330,9 @@ def main() -> None:
|
|
|
1329
1330
|
sys.exit(1)
|
|
1330
1331
|
else:
|
|
1331
1332
|
graph_paths.append(Path(a)); i += 1
|
|
1332
|
-
if len(graph_paths) <
|
|
1333
|
+
if len(graph_paths) < 1:
|
|
1333
1334
|
print(
|
|
1334
|
-
"Usage: graphify merge-main-graphs <graph-main1.json>
|
|
1335
|
+
"Usage: graphify merge-main-graphs <graph-main1.json> [graph-main2.json ...] "
|
|
1335
1336
|
"[--out graph-main-merged.json] [--report report.md]",
|
|
1336
1337
|
file=sys.stderr,
|
|
1337
1338
|
)
|
|
@@ -1357,6 +1358,7 @@ def main() -> None:
|
|
|
1357
1358
|
f"repos={stats.repo_count}, nodes={stats.nodes}, edges={stats.edges}, "
|
|
1358
1359
|
f"cross_edges={stats.cross_edges}, mtop={stats.mtop_links}, rest={stats.rest_links}, "
|
|
1359
1360
|
f"hsf_method={stats.hsf_method_links}, hsf_api={stats.hsf_api_links}, metaq={stats.metaq_links}, "
|
|
1361
|
+
f"npm_export={stats.npm_export_links}, "
|
|
1360
1362
|
f"unresolved_dependencies={stats.unresolved_dependencies}"
|
|
1361
1363
|
)
|
|
1362
1364
|
print(f"Graph: {out_path}")
|
|
@@ -1723,6 +1725,12 @@ def main() -> None:
|
|
|
1723
1725
|
args = sys.argv[2:]
|
|
1724
1726
|
from graphify.business_map import default_business_graph_path, default_business_map_path
|
|
1725
1727
|
|
|
1728
|
+
def _require_business_trace_value(option: str, index: int) -> str:
|
|
1729
|
+
if index + 1 >= len(args) or args[index + 1].startswith("--"):
|
|
1730
|
+
print(f"error: business-trace option {option} requires a value", file=sys.stderr)
|
|
1731
|
+
sys.exit(1)
|
|
1732
|
+
return args[index + 1]
|
|
1733
|
+
|
|
1726
1734
|
map_path = default_business_map_path()
|
|
1727
1735
|
graph_path: Path | None = None
|
|
1728
1736
|
concept = ""
|
|
@@ -1733,29 +1741,29 @@ def main() -> None:
|
|
|
1733
1741
|
i = 0
|
|
1734
1742
|
while i < len(args):
|
|
1735
1743
|
a = args[i]
|
|
1736
|
-
if a == "--map"
|
|
1737
|
-
map_path = Path(
|
|
1744
|
+
if a == "--map":
|
|
1745
|
+
map_path = Path(_require_business_trace_value(a, i)); i += 2
|
|
1738
1746
|
elif a.startswith("--map="):
|
|
1739
1747
|
map_path = Path(a.split("=", 1)[1]); i += 1
|
|
1740
|
-
elif a == "--graph"
|
|
1741
|
-
graph_path = Path(
|
|
1748
|
+
elif a == "--graph":
|
|
1749
|
+
graph_path = Path(_require_business_trace_value(a, i)); i += 2
|
|
1742
1750
|
elif a.startswith("--graph="):
|
|
1743
1751
|
graph_path = Path(a.split("=", 1)[1]); i += 1
|
|
1744
|
-
elif a == "--concept"
|
|
1745
|
-
concept =
|
|
1752
|
+
elif a == "--concept":
|
|
1753
|
+
concept = _require_business_trace_value(a, i); i += 2
|
|
1746
1754
|
elif a.startswith("--concept="):
|
|
1747
1755
|
concept = a.split("=", 1)[1]; i += 1
|
|
1748
|
-
elif a == "--scenario"
|
|
1749
|
-
scenario =
|
|
1756
|
+
elif a == "--scenario":
|
|
1757
|
+
scenario = _require_business_trace_value(a, i); i += 2
|
|
1750
1758
|
elif a.startswith("--scenario="):
|
|
1751
1759
|
scenario = a.split("=", 1)[1]; i += 1
|
|
1752
|
-
elif a == "--flow"
|
|
1753
|
-
flow =
|
|
1760
|
+
elif a == "--flow":
|
|
1761
|
+
flow = _require_business_trace_value(a, i); i += 2
|
|
1754
1762
|
elif a.startswith("--flow="):
|
|
1755
1763
|
flow = a.split("=", 1)[1]; i += 1
|
|
1756
|
-
elif a == "--max-depth"
|
|
1764
|
+
elif a == "--max-depth":
|
|
1757
1765
|
try:
|
|
1758
|
-
max_depth = int(
|
|
1766
|
+
max_depth = int(_require_business_trace_value(a, i))
|
|
1759
1767
|
except ValueError:
|
|
1760
1768
|
print("error: --max-depth must be an integer", file=sys.stderr)
|
|
1761
1769
|
sys.exit(1)
|
|
@@ -1921,6 +1929,22 @@ def main() -> None:
|
|
|
1921
1929
|
if thin_out is not None:
|
|
1922
1930
|
print(f"Thin graph: {thin_out}")
|
|
1923
1931
|
|
|
1932
|
+
elif cmd == "repo-list":
|
|
1933
|
+
start = Path(sys.argv[2]) if len(sys.argv) > 2 else Path(".")
|
|
1934
|
+
if len(sys.argv) > 3:
|
|
1935
|
+
print("Usage: graphify repo-list [path]", file=sys.stderr)
|
|
1936
|
+
sys.exit(1)
|
|
1937
|
+
try:
|
|
1938
|
+
from graphify.repo_registry import ensure_repo_list as _ensure_repo_list
|
|
1939
|
+
|
|
1940
|
+
list_path = _ensure_repo_list(start.resolve())
|
|
1941
|
+
data = json.loads(list_path.read_text(encoding="utf-8"))
|
|
1942
|
+
repos = data.get("repos", []) if isinstance(data, dict) else []
|
|
1943
|
+
print(f"Repo list: {list_path} ({len(repos)} repos)")
|
|
1944
|
+
except Exception as exc:
|
|
1945
|
+
print(f"error: repo-list failed: {exc}", file=sys.stderr)
|
|
1946
|
+
sys.exit(1)
|
|
1947
|
+
|
|
1924
1948
|
elif cmd == "main-graph":
|
|
1925
1949
|
args = sys.argv[2:]
|
|
1926
1950
|
root = Path(".")
|
|
@@ -2095,7 +2119,8 @@ def main() -> None:
|
|
|
2095
2119
|
print(
|
|
2096
2120
|
"Node counts: "
|
|
2097
2121
|
f"page={stats.page_nodes}, component={stats.component_nodes}, "
|
|
2098
|
-
f"mtop_api={stats.mtop_api_nodes}, rest_api={stats.rest_api_nodes}"
|
|
2122
|
+
f"mtop_api={stats.mtop_api_nodes}, rest_api={stats.rest_api_nodes}, "
|
|
2123
|
+
f"sdk_export={stats.sdk_export_nodes}, sdk_dependency={stats.sdk_dependency_nodes}"
|
|
2099
2124
|
)
|
|
2100
2125
|
print(f"HTML: {html_out}")
|
|
2101
2126
|
print(f"Report: {report_out}")
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
5
|
import re
|
|
6
|
+
import hashlib
|
|
6
7
|
from dataclasses import dataclass
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
|
|
@@ -220,6 +221,49 @@ def health_card_seed() -> dict:
|
|
|
220
221
|
}
|
|
221
222
|
|
|
222
223
|
|
|
224
|
+
def _concept_id_from_name(name: str) -> str:
|
|
225
|
+
raw = str(name or "").strip()
|
|
226
|
+
if _matches_text(raw, "健康卡", ["health_card", "healthCard", "health card"]):
|
|
227
|
+
return "health_card"
|
|
228
|
+
lowered = raw.lower()
|
|
229
|
+
if "ai" in lowered and "找药" in raw:
|
|
230
|
+
return "ai_find_drug"
|
|
231
|
+
ascii_parts = _ascii_terms(raw)
|
|
232
|
+
slug = "_".join(ascii_parts)
|
|
233
|
+
slug = re.sub(r"[^a-z0-9_]+", "_", slug).strip("_")
|
|
234
|
+
if slug and not slug[0].isdigit():
|
|
235
|
+
return slug[:48]
|
|
236
|
+
digest = hashlib.sha1(raw.encode("utf-8")).hexdigest()[:8]
|
|
237
|
+
return f"concept_{digest}"
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def concept_seed(concept: str) -> dict:
|
|
241
|
+
name = str(concept or "").strip()
|
|
242
|
+
if not name:
|
|
243
|
+
raise ValueError("concept is required")
|
|
244
|
+
aliases: list[str] = []
|
|
245
|
+
if _concept_id_from_name(name) == "ai_find_drug":
|
|
246
|
+
aliases = ["闪购AI找药", "千问找药"]
|
|
247
|
+
return {
|
|
248
|
+
"id": _concept_id_from_name(name),
|
|
249
|
+
"name": name,
|
|
250
|
+
"aliases": aliases,
|
|
251
|
+
"status": "unexplored",
|
|
252
|
+
"summary": f"待探索{name}相关业务场景、入口、API、后端承接链路和边界。",
|
|
253
|
+
"scenarios": [],
|
|
254
|
+
"gaps": ["缺少场景、入口 repo、页面/API 和后端锚点。"],
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _business_map_seed() -> dict:
|
|
259
|
+
return {
|
|
260
|
+
"version": 1,
|
|
261
|
+
"kind": "business-map",
|
|
262
|
+
"description": "Business concept map layered on top of graph-main facts.",
|
|
263
|
+
"concepts": [],
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
|
|
223
267
|
def load_business_map(path: Path) -> dict:
|
|
224
268
|
data = json.loads(path.read_text(encoding="utf-8"))
|
|
225
269
|
if not isinstance(data, dict):
|
|
@@ -301,9 +345,12 @@ def default_business_graph_path(map_path: Path, start: Path | None = None) -> Pa
|
|
|
301
345
|
plugin_root = os.environ.get("CLAUDE_PLUGIN_ROOT", "").strip()
|
|
302
346
|
if plugin_root:
|
|
303
347
|
graphify_out = Path(plugin_root).expanduser().resolve() / "graphify-out"
|
|
304
|
-
|
|
305
|
-
if
|
|
306
|
-
return
|
|
348
|
+
graph = graphify_out / "graph.json"
|
|
349
|
+
if graph.exists():
|
|
350
|
+
return graph
|
|
351
|
+
legacy_graph = graphify_out / "graph-hc.json"
|
|
352
|
+
if legacy_graph.exists():
|
|
353
|
+
return legacy_graph
|
|
307
354
|
candidates = sorted(
|
|
308
355
|
p for p in graphify_out.glob("graph*.json")
|
|
309
356
|
if p.name != "business-map.json"
|
|
@@ -331,11 +378,27 @@ def default_business_graph_path(map_path: Path, start: Path | None = None) -> Pa
|
|
|
331
378
|
|
|
332
379
|
|
|
333
380
|
def init_business_map(concept: str, out_path: Path, *, force: bool = False) -> dict:
|
|
334
|
-
if out_path.exists()
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
381
|
+
if force or not out_path.exists():
|
|
382
|
+
if _matches_text(concept, "健康卡", ["health_card", "healthCard", "health card"]):
|
|
383
|
+
data = health_card_seed()
|
|
384
|
+
else:
|
|
385
|
+
data = _business_map_seed()
|
|
386
|
+
data["concepts"].append(concept_seed(concept))
|
|
387
|
+
write_business_map(data, out_path)
|
|
388
|
+
return data
|
|
389
|
+
|
|
390
|
+
data = load_business_map(out_path)
|
|
391
|
+
concepts = data.setdefault("concepts", [])
|
|
392
|
+
if not isinstance(concepts, list):
|
|
393
|
+
raise ValueError("business map concepts must be a list")
|
|
394
|
+
|
|
395
|
+
candidate = (
|
|
396
|
+
health_card_seed()["concepts"][0]
|
|
397
|
+
if _matches_text(concept, "健康卡", ["health_card", "healthCard", "health card"])
|
|
398
|
+
else concept_seed(concept)
|
|
399
|
+
)
|
|
400
|
+
if not any(isinstance(item, dict) and _concept_matches(item, concept) for item in concepts):
|
|
401
|
+
concepts.append(candidate)
|
|
339
402
|
write_business_map(data, out_path)
|
|
340
403
|
return data
|
|
341
404
|
|