ckgraphify 0.2.1__tar.gz → 0.2.3__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.2.1 → ckgraphify-0.2.3}/PKG-INFO +1 -1
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/__main__.py +0 -38
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/graph_main_backend.py +117 -1
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/graph_main_frontend.py +757 -1
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/graph_main_frontend_sdk.py +15 -6
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/graph_main_merge.py +198 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/graph_main_trace.py +128 -44
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/pyproject.toml +1 -1
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/skill/skill.md +2 -2
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/LICENSE +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/MANIFEST.in +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/README.md +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/ckgraphify.egg-info/SOURCES.txt +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/__init__.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/analyze.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/benchmark.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/bridge_mtop.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/build.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/business_map.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/cache.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/callflow_html.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/cluster.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/dedup.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/detect.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/export.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/extract.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/global_graph.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/google_workspace.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/graph_main_html.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/hooks.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/ingest.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/llm.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/manifest.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/repo_registry.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/report.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/security.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/serve.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/transcribe.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/tree_html.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/validate.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/watch.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/wiki.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/setup.cfg +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/skill/__init__.py +0 -0
- {ckgraphify-0.2.1 → ckgraphify-0.2.3}/skill/skill-codex.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ckgraphify
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
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
|
|
@@ -22,31 +22,6 @@ def _default_graph_path() -> str:
|
|
|
22
22
|
return str(Path(_GRAPHIFY_OUT) / "graph.json")
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
def _check_skill_version(skill_dst: Path) -> None:
|
|
26
|
-
"""Warn if the installed skill is from an older ckgraphify package version."""
|
|
27
|
-
version_file = skill_dst.parent / ".ckgraphify_version"
|
|
28
|
-
if not version_file.exists():
|
|
29
|
-
return
|
|
30
|
-
if not skill_dst.exists():
|
|
31
|
-
print(" warning: skill dir exists but SKILL.md is missing. Run 'graphify install' to repair.")
|
|
32
|
-
return
|
|
33
|
-
installed = version_file.read_text(encoding="utf-8").strip()
|
|
34
|
-
if installed != __version__:
|
|
35
|
-
print(f" warning: skill is from ckgraphify {installed}, package is {__version__}. Run 'graphify install' to update.", file=sys.stderr)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _refresh_all_version_stamps() -> None:
|
|
39
|
-
"""After a successful install, update .ckgraphify_version in all other known skill dirs.
|
|
40
|
-
|
|
41
|
-
Prevents stale-version warnings from platforms that were installed previously
|
|
42
|
-
but not explicitly re-installed during this upgrade.
|
|
43
|
-
"""
|
|
44
|
-
for cfg in _PLATFORM_CONFIG.values():
|
|
45
|
-
skill_dst = Path.home() / cfg["skill_dst"]
|
|
46
|
-
vf = skill_dst.parent / ".ckgraphify_version"
|
|
47
|
-
if skill_dst.exists():
|
|
48
|
-
vf.write_text(__version__, encoding="utf-8")
|
|
49
|
-
|
|
50
25
|
_SETTINGS_HOOK = {
|
|
51
26
|
# Claude Code v2.1.117+ removed dedicated Grep/Glob tools; searches now go through Bash.
|
|
52
27
|
# We match on Bash and inspect the command string to avoid firing on every shell call.
|
|
@@ -151,10 +126,6 @@ def install(platform: str = "claude") -> None:
|
|
|
151
126
|
claude_md.parent.mkdir(parents=True, exist_ok=True)
|
|
152
127
|
claude_md.write_text(_SKILL_REGISTRATION.lstrip(), encoding="utf-8")
|
|
153
128
|
print(f" CLAUDE.md -> created at {claude_md}")
|
|
154
|
-
# Refresh version stamps in all other previously-installed skill dirs so
|
|
155
|
-
# stale-version warnings don't fire for platforms not explicitly re-installed.
|
|
156
|
-
_refresh_all_version_stamps()
|
|
157
|
-
|
|
158
129
|
print()
|
|
159
130
|
print("Done. Open your AI coding assistant and type:")
|
|
160
131
|
print()
|
|
@@ -523,15 +494,6 @@ def _clone_repo(url: str, branch: str | None = None, out_dir: Path | None = None
|
|
|
523
494
|
|
|
524
495
|
|
|
525
496
|
def main() -> None:
|
|
526
|
-
# Check all known skill install locations for a stale version stamp.
|
|
527
|
-
# Skip during install/uninstall (hook writes trigger a fresh check anyway).
|
|
528
|
-
# Skip during hook-check — it runs on every editor tool use and must be silent.
|
|
529
|
-
# Deduplicate paths so platforms sharing the same install dir don't warn twice.
|
|
530
|
-
_silent_cmds = {"install", "uninstall", "hook-check"}
|
|
531
|
-
if not any(arg in _silent_cmds for arg in sys.argv):
|
|
532
|
-
for skill_dst in {Path.home() / cfg["skill_dst"] for cfg in _PLATFORM_CONFIG.values()}:
|
|
533
|
-
_check_skill_version(skill_dst)
|
|
534
|
-
|
|
535
497
|
if len(sys.argv) >= 2 and sys.argv[1] in ("-v", "--version", "version"):
|
|
536
498
|
print(f"graphify {__version__}")
|
|
537
499
|
return
|
|
@@ -99,7 +99,7 @@ _METAQ_PRODUCER_RE = re.compile(r"(?:Metaq|MetaQ).{0,40}(?:send|publish|produce)
|
|
|
99
99
|
_TOPIC_RE = re.compile(r"""topic\s*=\s*["']([A-Za-z0-9_.-]+)["']""")
|
|
100
100
|
_STR_ASSIGN_RE = re.compile(r'(?m)\bString\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*"([A-Za-z0-9_.-]+)"\s*;')
|
|
101
101
|
_STATIC_STRING_CONST_RE = re.compile(
|
|
102
|
-
r'(?m)\b(?:public|protected|private)?\s*static\s+final\s+String\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*"([^"]+)"\s*;'
|
|
102
|
+
r'(?m)\b(?:public|protected|private)?\s*(?:static\s+final\s+)?String\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*"([^"]+)"\s*;'
|
|
103
103
|
)
|
|
104
104
|
_BINDING_HEADER_RE = re.compile(r"\bBinding\.header\s*\(([^)]*)\)")
|
|
105
105
|
_SET_LISTENER_RE = re.compile(r"\.setMessageListener\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)")
|
|
@@ -116,6 +116,10 @@ _TOPIC_TOKEN_RE = re.compile(r"\b([A-Za-z0-9_$.]*TOPIC[A-Za-z0-9_$.]*)\b")
|
|
|
116
116
|
_ANTX_CONSUMER_PROP_RE = re.compile(
|
|
117
117
|
r"(?m)^spring\.metaq\.consumers\[(\d+)\]\.([A-Za-z0-9_.-]+)\s*=\s*(.+?)\s*$"
|
|
118
118
|
)
|
|
119
|
+
_TAG_SPI_EXTENSION_RE = re.compile(r"@TagSpiExtension\s*\((?P<body>.*?)\)", re.S)
|
|
120
|
+
_COMPONENT_TAG_RE = re.compile(r"@ComponentTag\s*\((?P<body>.*?)\)", re.S)
|
|
121
|
+
_BLOCK_EXTENSION_RE = re.compile(r"@BlockExtension\s*\((?P<body>.*?)\)", re.S)
|
|
122
|
+
_ANNOTATION_ARG_RE_TEMPLATE = r"{name}\s*=\s*(?P<value>\{{.*?\}}|\"[^\"]+\"|'[^']+'|[A-Za-z0-9_$.]+)"
|
|
119
123
|
|
|
120
124
|
|
|
121
125
|
def _safe_id(s: str) -> str:
|
|
@@ -355,6 +359,33 @@ def _resolve_metaq_token(token: str, constants: dict[str, str]) -> str:
|
|
|
355
359
|
return constants.get(raw) or constants.get(raw.rsplit(".", 1)[-1]) or raw
|
|
356
360
|
|
|
357
361
|
|
|
362
|
+
def _resolve_java_string_token(token: str, constants: dict[str, str]) -> str:
|
|
363
|
+
raw = str(token or "").strip().strip()
|
|
364
|
+
if not raw:
|
|
365
|
+
return ""
|
|
366
|
+
if (raw.startswith('"') and raw.endswith('"')) or (raw.startswith("'") and raw.endswith("'")):
|
|
367
|
+
return raw[1:-1]
|
|
368
|
+
return constants.get(raw) or constants.get(raw.rsplit(".", 1)[-1]) or raw
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def _annotation_arg_values(body: str, name: str, constants: dict[str, str]) -> list[str]:
|
|
372
|
+
pattern = re.compile(_ANNOTATION_ARG_RE_TEMPLATE.format(name=re.escape(name)), re.S)
|
|
373
|
+
m = pattern.search(body or "")
|
|
374
|
+
if not m:
|
|
375
|
+
return []
|
|
376
|
+
raw_value = m.group("value").strip()
|
|
377
|
+
if raw_value.startswith("{") and raw_value.endswith("}"):
|
|
378
|
+
raw_items = [part.strip() for part in raw_value[1:-1].split(",")]
|
|
379
|
+
else:
|
|
380
|
+
raw_items = [raw_value]
|
|
381
|
+
values: list[str] = []
|
|
382
|
+
for item in raw_items:
|
|
383
|
+
resolved = _resolve_java_string_token(item, constants)
|
|
384
|
+
if resolved:
|
|
385
|
+
values.append(resolved)
|
|
386
|
+
return list(dict.fromkeys(values))
|
|
387
|
+
|
|
388
|
+
|
|
358
389
|
def _extract_metaq_producer_topics(body_text: str, constants: dict[str, str] | None = None) -> list[tuple[str, str]]:
|
|
359
390
|
constants = constants or {}
|
|
360
391
|
topics: list[tuple[str, str]] = []
|
|
@@ -1048,6 +1079,7 @@ def build_graph_main_backend(*, repo_root: Path, out_path: Path) -> GraphMainBac
|
|
|
1048
1079
|
dep_method_by_key: dict[str, str] = {}
|
|
1049
1080
|
prod_by_key: dict[str, str] = {}
|
|
1050
1081
|
cons_by_key: dict[str, str] = {}
|
|
1082
|
+
t3_ext_by_key: dict[str, str] = {}
|
|
1051
1083
|
|
|
1052
1084
|
def ensure_api(interface_fqcn: str, source_file: str, line: int) -> str:
|
|
1053
1085
|
canonical = f"hsf_api:{interface_fqcn.lower()}"
|
|
@@ -1275,6 +1307,51 @@ def build_graph_main_backend(*, repo_root: Path, out_path: Path) -> GraphMainBac
|
|
|
1275
1307
|
cons_by_key[canonical] = nid
|
|
1276
1308
|
return nid
|
|
1277
1309
|
|
|
1310
|
+
def ensure_t3_extension(
|
|
1311
|
+
*,
|
|
1312
|
+
extension_type: str,
|
|
1313
|
+
class_fqcn: str,
|
|
1314
|
+
component_code: str,
|
|
1315
|
+
source_file: str,
|
|
1316
|
+
line: int,
|
|
1317
|
+
scene_code: str = "",
|
|
1318
|
+
) -> str:
|
|
1319
|
+
component_code = component_code.strip()
|
|
1320
|
+
scene_code = scene_code.strip()
|
|
1321
|
+
if not component_code:
|
|
1322
|
+
component_code = "*"
|
|
1323
|
+
key_scene = scene_code.lower() if scene_code else "*"
|
|
1324
|
+
canonical = f"t3_extension:{extension_type}:{key_scene}:{component_code.lower()}:{class_fqcn.lower()}"
|
|
1325
|
+
if canonical in t3_ext_by_key:
|
|
1326
|
+
return t3_ext_by_key[canonical]
|
|
1327
|
+
label_prefix = f"{scene_code}:{component_code}" if scene_code else component_code
|
|
1328
|
+
label = f"{label_prefix} -> {class_fqcn.split('.')[-1]}"
|
|
1329
|
+
nid = f"t3_extension__{_safe_id(extension_type + '_' + label_prefix + '_' + class_fqcn)}"
|
|
1330
|
+
match_key = (
|
|
1331
|
+
f"t3_component:{scene_code.lower()}:{component_code.lower()}"
|
|
1332
|
+
if scene_code and component_code != "*"
|
|
1333
|
+
else f"t3_component:*:{component_code.lower()}"
|
|
1334
|
+
)
|
|
1335
|
+
add_node(
|
|
1336
|
+
{
|
|
1337
|
+
"id": nid,
|
|
1338
|
+
"label": label,
|
|
1339
|
+
"canonical_key": canonical,
|
|
1340
|
+
"match_key": match_key,
|
|
1341
|
+
"file_type": "code",
|
|
1342
|
+
"source_file": source_file,
|
|
1343
|
+
"source_location": f"L{line}",
|
|
1344
|
+
"main_kind": "t3_extension",
|
|
1345
|
+
"extension_type": extension_type,
|
|
1346
|
+
"class_fqcn": class_fqcn,
|
|
1347
|
+
"scene_code": scene_code,
|
|
1348
|
+
"component_code": component_code,
|
|
1349
|
+
"module_code": component_code,
|
|
1350
|
+
}
|
|
1351
|
+
)
|
|
1352
|
+
t3_ext_by_key[canonical] = nid
|
|
1353
|
+
return nid
|
|
1354
|
+
|
|
1278
1355
|
map_pairs: list[tuple[int, str, str, str]] = []
|
|
1279
1356
|
mtop_by_method_key: dict[str, str] = {}
|
|
1280
1357
|
code_method_keys: set[str] = set()
|
|
@@ -1299,6 +1376,45 @@ def build_graph_main_backend(*, repo_root: Path, out_path: Path) -> GraphMainBac
|
|
|
1299
1376
|
map_method_candidates.add(f"hsf_method:{method_key}")
|
|
1300
1377
|
map_pairs.append((idx + 1, api_name, iface, method))
|
|
1301
1378
|
|
|
1379
|
+
for info in parsed:
|
|
1380
|
+
class_text = _read_text(repo_root / info.rel_path)
|
|
1381
|
+
class_m = _CLASS_RE.search(class_text)
|
|
1382
|
+
class_line = _line_of(class_text, class_m.start()) if class_m else 1
|
|
1383
|
+
for m in _TAG_SPI_EXTENSION_RE.finditer(info.class_ann):
|
|
1384
|
+
scenes = _annotation_arg_values(m.group("body"), "sceneCode", string_constants)
|
|
1385
|
+
modules = _annotation_arg_values(m.group("body"), "moduleCode", string_constants) or [""]
|
|
1386
|
+
for scene in scenes or [""]:
|
|
1387
|
+
for module in modules:
|
|
1388
|
+
ensure_t3_extension(
|
|
1389
|
+
extension_type="tag_spi",
|
|
1390
|
+
class_fqcn=info.class_fqcn,
|
|
1391
|
+
scene_code=scene,
|
|
1392
|
+
component_code=module,
|
|
1393
|
+
source_file=info.rel_path,
|
|
1394
|
+
line=class_line,
|
|
1395
|
+
)
|
|
1396
|
+
for m in _COMPONENT_TAG_RE.finditer(info.class_ann):
|
|
1397
|
+
sources = _annotation_arg_values(m.group("body"), "source", string_constants)
|
|
1398
|
+
if not sources:
|
|
1399
|
+
sources = _annotation_arg_values(m.group("body"), "value", string_constants)
|
|
1400
|
+
for source in sources:
|
|
1401
|
+
ensure_t3_extension(
|
|
1402
|
+
extension_type="component_tag",
|
|
1403
|
+
class_fqcn=info.class_fqcn,
|
|
1404
|
+
component_code=source,
|
|
1405
|
+
source_file=info.rel_path,
|
|
1406
|
+
line=class_line,
|
|
1407
|
+
)
|
|
1408
|
+
for m in _BLOCK_EXTENSION_RE.finditer(info.class_ann):
|
|
1409
|
+
for code in _annotation_arg_values(m.group("body"), "blockExtensionCode", string_constants):
|
|
1410
|
+
ensure_t3_extension(
|
|
1411
|
+
extension_type="block_extension",
|
|
1412
|
+
class_fqcn=info.class_fqcn,
|
|
1413
|
+
component_code=code,
|
|
1414
|
+
source_file=info.rel_path,
|
|
1415
|
+
line=class_line,
|
|
1416
|
+
)
|
|
1417
|
+
|
|
1302
1418
|
resolved_map_method_keys: set[str] = set()
|
|
1303
1419
|
|
|
1304
1420
|
for info in parsed:
|