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.
Files changed (45) hide show
  1. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/PKG-INFO +1 -1
  2. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/__main__.py +0 -38
  3. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/graph_main_backend.py +117 -1
  4. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/graph_main_frontend.py +757 -1
  5. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/graph_main_frontend_sdk.py +15 -6
  6. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/graph_main_merge.py +198 -0
  7. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/graph_main_trace.py +128 -44
  8. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/pyproject.toml +1 -1
  9. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/skill/skill.md +2 -2
  10. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/LICENSE +0 -0
  11. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/MANIFEST.in +0 -0
  12. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/README.md +0 -0
  13. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/ckgraphify.egg-info/SOURCES.txt +0 -0
  14. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/__init__.py +0 -0
  15. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/analyze.py +0 -0
  16. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/benchmark.py +0 -0
  17. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/bridge_mtop.py +0 -0
  18. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/build.py +0 -0
  19. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/business_map.py +0 -0
  20. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/cache.py +0 -0
  21. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/callflow_html.py +0 -0
  22. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/cluster.py +0 -0
  23. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/dedup.py +0 -0
  24. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/detect.py +0 -0
  25. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/export.py +0 -0
  26. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/extract.py +0 -0
  27. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/global_graph.py +0 -0
  28. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/google_workspace.py +0 -0
  29. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/graph_main_html.py +0 -0
  30. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/hooks.py +0 -0
  31. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/ingest.py +0 -0
  32. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/llm.py +0 -0
  33. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/manifest.py +0 -0
  34. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/repo_registry.py +0 -0
  35. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/report.py +0 -0
  36. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/security.py +0 -0
  37. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/serve.py +0 -0
  38. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/transcribe.py +0 -0
  39. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/tree_html.py +0 -0
  40. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/validate.py +0 -0
  41. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/watch.py +0 -0
  42. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/graphify/wiki.py +0 -0
  43. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/setup.cfg +0 -0
  44. {ckgraphify-0.2.1 → ckgraphify-0.2.3}/skill/__init__.py +0 -0
  45. {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.1
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: