code-atlas-forge 1.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.
Files changed (181) hide show
  1. code_atlas/__init__.py +6 -0
  2. code_atlas/__main__.py +6 -0
  3. code_atlas/api/__init__.py +5 -0
  4. code_atlas/api/handlers.py +1514 -0
  5. code_atlas/api/server.py +394 -0
  6. code_atlas/cli.py +2084 -0
  7. code_atlas/config.py +149 -0
  8. code_atlas/context/__init__.py +66 -0
  9. code_atlas/context/contracts.py +277 -0
  10. code_atlas/context/domain.py +760 -0
  11. code_atlas/context/engine.py +442 -0
  12. code_atlas/context/expand.py +133 -0
  13. code_atlas/context/renderers.py +71 -0
  14. code_atlas/context/tokenizer.py +37 -0
  15. code_atlas/contracts/__init__.py +38 -0
  16. code_atlas/contracts/enums.py +67 -0
  17. code_atlas/contracts/models.py +175 -0
  18. code_atlas/contracts/ports.py +70 -0
  19. code_atlas/discovery/__init__.py +25 -0
  20. code_atlas/discovery/gitignore.py +119 -0
  21. code_atlas/discovery/identity.py +52 -0
  22. code_atlas/discovery/models.py +204 -0
  23. code_atlas/discovery/scanner.py +495 -0
  24. code_atlas/domains/__init__.py +107 -0
  25. code_atlas/domains/api/__init__.py +28 -0
  26. code_atlas/domains/api/adapter.py +405 -0
  27. code_atlas/domains/api/common.py +308 -0
  28. code_atlas/domains/api/consumers.py +224 -0
  29. code_atlas/domains/api/emit.py +231 -0
  30. code_atlas/domains/api/openapi.py +398 -0
  31. code_atlas/domains/api/routes.py +582 -0
  32. code_atlas/domains/api/yaml_subset.py +683 -0
  33. code_atlas/domains/aws/__init__.py +28 -0
  34. code_atlas/domains/aws/adapter.py +382 -0
  35. code_atlas/domains/aws/common.py +261 -0
  36. code_atlas/domains/aws/configs.py +1164 -0
  37. code_atlas/domains/aws/emit.py +411 -0
  38. code_atlas/domains/aws/pyfiles.py +2220 -0
  39. code_atlas/domains/aws/sqlbridge.py +448 -0
  40. code_atlas/domains/cicd/__init__.py +50 -0
  41. code_atlas/domains/cicd/adapter.py +762 -0
  42. code_atlas/domains/cicd/classify.py +136 -0
  43. code_atlas/domains/cicd/workflow.py +504 -0
  44. code_atlas/domains/cicd/yamlmini.py +946 -0
  45. code_atlas/domains/cli_surface.py +739 -0
  46. code_atlas/domains/contracts.py +274 -0
  47. code_atlas/domains/crossresolve.py +1208 -0
  48. code_atlas/domains/evidence.py +57 -0
  49. code_atlas/domains/identity.py +149 -0
  50. code_atlas/domains/model.py +202 -0
  51. code_atlas/domains/registry.py +250 -0
  52. code_atlas/domains/resolution.py +65 -0
  53. code_atlas/domains/spark/__init__.py +31 -0
  54. code_atlas/domains/spark/adapter.py +146 -0
  55. code_atlas/domains/spark/emit.py +344 -0
  56. code_atlas/domains/spark/extract.py +108 -0
  57. code_atlas/domains/spark/sqllit.py +192 -0
  58. code_atlas/domains/spark/walk.py +1943 -0
  59. code_atlas/domains/sql/__init__.py +30 -0
  60. code_atlas/domains/sql/adapter.py +382 -0
  61. code_atlas/domains/sql/extract.py +1271 -0
  62. code_atlas/domains/sql/nodes.py +264 -0
  63. code_atlas/domains/sql/parser.py +1510 -0
  64. code_atlas/domains/sql/tokens.py +318 -0
  65. code_atlas/domains/summarize.py +126 -0
  66. code_atlas/domains/terraform/__init__.py +20 -0
  67. code_atlas/domains/terraform/adapter.py +127 -0
  68. code_atlas/domains/terraform/catalog.py +43 -0
  69. code_atlas/domains/terraform/extract.py +1277 -0
  70. code_atlas/domains/terraform/hcl.py +538 -0
  71. code_atlas/domains/terraform/refs.py +181 -0
  72. code_atlas/domains/terraform/tfjson.py +163 -0
  73. code_atlas/domains/terraform/tfvars.py +98 -0
  74. code_atlas/domains/validation.py +120 -0
  75. code_atlas/env_override.py +27 -0
  76. code_atlas/eval/__init__.py +26 -0
  77. code_atlas/eval/domain_eval.py +681 -0
  78. code_atlas/eval/ground_truth.py +688 -0
  79. code_atlas/eval/impact_truth.py +758 -0
  80. code_atlas/eval/metrics.py +178 -0
  81. code_atlas/eval/pack_value.py +610 -0
  82. code_atlas/federation/__init__.py +72 -0
  83. code_atlas/federation/federation.py +676 -0
  84. code_atlas/federation/model.py +355 -0
  85. code_atlas/federation/store.py +194 -0
  86. code_atlas/gitbin.py +48 -0
  87. code_atlas/graph/__init__.py +20 -0
  88. code_atlas/graph/builder.py +378 -0
  89. code_atlas/graph/identity.py +54 -0
  90. code_atlas/graph/queries.py +47 -0
  91. code_atlas/graph/validation.py +92 -0
  92. code_atlas/impact/__init__.py +37 -0
  93. code_atlas/impact/blast_radius.py +171 -0
  94. code_atlas/impact/contract_analyzer.py +104 -0
  95. code_atlas/impact/contracts.py +315 -0
  96. code_atlas/impact/diff_reader.py +142 -0
  97. code_atlas/impact/domain_traversal.py +768 -0
  98. code_atlas/impact/engine.py +392 -0
  99. code_atlas/impact/packs.py +128 -0
  100. code_atlas/impact/report.py +136 -0
  101. code_atlas/impact/revision_binding.py +220 -0
  102. code_atlas/impact/risk_classifier.py +83 -0
  103. code_atlas/impact/snapshot_resolver.py +136 -0
  104. code_atlas/impact/symbol_diff.py +210 -0
  105. code_atlas/impact/test_selector.py +166 -0
  106. code_atlas/indexing/__init__.py +5 -0
  107. code_atlas/indexing/cache.py +396 -0
  108. code_atlas/indexing/change_detector.py +278 -0
  109. code_atlas/indexing/coordinator.py +1032 -0
  110. code_atlas/indexing/dependency_planner.py +268 -0
  111. code_atlas/indexing/persist.py +436 -0
  112. code_atlas/indexing/reuse.py +85 -0
  113. code_atlas/install/__init__.py +7 -0
  114. code_atlas/install/cli.py +168 -0
  115. code_atlas/install/lifecycle.py +286 -0
  116. code_atlas/mcp.py +674 -0
  117. code_atlas/observability/__init__.py +19 -0
  118. code_atlas/observability/logging.py +199 -0
  119. code_atlas/parsers/__init__.py +43 -0
  120. code_atlas/parsers/contracts.py +209 -0
  121. code_atlas/parsers/engine.py +125 -0
  122. code_atlas/parsers/languages/__init__.py +1 -0
  123. code_atlas/parsers/languages/python.py +391 -0
  124. code_atlas/parsers/languages/tsx.py +28 -0
  125. code_atlas/parsers/languages/typescript.py +909 -0
  126. code_atlas/parsers/registry.py +51 -0
  127. code_atlas/parsers/tree_sitter_runtime.py +118 -0
  128. code_atlas/resolvers/__init__.py +33 -0
  129. code_atlas/resolvers/bootstrap.py +246 -0
  130. code_atlas/resolvers/capabilities.py +33 -0
  131. code_atlas/resolvers/contracts.py +133 -0
  132. code_atlas/resolvers/coordinator.py +96 -0
  133. code_atlas/resolvers/enrichment.py +318 -0
  134. code_atlas/resolvers/lsp/__init__.py +26 -0
  135. code_atlas/resolvers/lsp/adapter.py +256 -0
  136. code_atlas/resolvers/lsp/lifecycle.py +251 -0
  137. code_atlas/resolvers/lsp/spawn.py +92 -0
  138. code_atlas/resolvers/lsp/transport.py +240 -0
  139. code_atlas/resolvers/registry.py +33 -0
  140. code_atlas/resolvers/scip/__init__.py +49 -0
  141. code_atlas/resolvers/scip/decoder.py +216 -0
  142. code_atlas/resolvers/scip/importer.py +248 -0
  143. code_atlas/resolvers/scip/loader.py +90 -0
  144. code_atlas/resolvers/scip/mapper.py +271 -0
  145. code_atlas/resolvers/scip/provenance.py +211 -0
  146. code_atlas/resolvers/scip/resolver.py +289 -0
  147. code_atlas/resolvers/scip/validation.py +101 -0
  148. code_atlas/resolvers/syntactic/__init__.py +8 -0
  149. code_atlas/resolvers/syntactic/resolver.py +254 -0
  150. code_atlas/search/__init__.py +32 -0
  151. code_atlas/search/contracts.py +176 -0
  152. code_atlas/search/domain.py +561 -0
  153. code_atlas/search/engine.py +530 -0
  154. code_atlas/search/federated.py +276 -0
  155. code_atlas/search/graph.py +282 -0
  156. code_atlas/search/hybrid.py +151 -0
  157. code_atlas/search/intent.py +48 -0
  158. code_atlas/search/lexical.py +176 -0
  159. code_atlas/search/refs.py +359 -0
  160. code_atlas/search/structural.py +505 -0
  161. code_atlas/search/tokenizer.py +43 -0
  162. code_atlas/search/vector/__init__.py +35 -0
  163. code_atlas/search/vector/contracts.py +76 -0
  164. code_atlas/search/vector/embeddings.py +96 -0
  165. code_atlas/search/vector/index.py +169 -0
  166. code_atlas/search/vector/provider.py +50 -0
  167. code_atlas/storage/__init__.py +14 -0
  168. code_atlas/storage/db.py +47 -0
  169. code_atlas/storage/migrations.py +552 -0
  170. code_atlas/storage/store.py +1045 -0
  171. code_atlas/ui/__init__.py +29 -0
  172. code_atlas/ui/i18n.py +143 -0
  173. code_atlas/ui/kit.py +689 -0
  174. code_atlas/ui/wizard.py +317 -0
  175. code_atlas_forge-1.1.0.dist-info/METADATA +246 -0
  176. code_atlas_forge-1.1.0.dist-info/RECORD +181 -0
  177. code_atlas_forge-1.1.0.dist-info/WHEEL +5 -0
  178. code_atlas_forge-1.1.0.dist-info/entry_points.txt +2 -0
  179. code_atlas_forge-1.1.0.dist-info/licenses/LICENSE +202 -0
  180. code_atlas_forge-1.1.0.dist-info/licenses/NOTICE +17 -0
  181. code_atlas_forge-1.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,317 @@
1
+ """Guided installation wizard (Experience Program §1.2).
2
+
3
+ Drives the *real* install service — every choice maps to an actual
4
+ ``install()`` call; the review step is the real dry-run plan, and the
5
+ apply step is the governed ``--yes`` path. Nothing here writes files
6
+ itself.
7
+
8
+ Flow: env check → scope → profile → execution profile → components →
9
+ hosts → review (dry-run plan) → confirm → apply → doctor → finish.
10
+ Each optional step is skipped when its vocabulary is empty (a forge
11
+ with no gateway profiles, components or hosts simply never asks).
12
+ Any step can be cancelled (Esc/q) without side effects; nothing is
13
+ written before the explicit confirm.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import json
19
+ import shutil
20
+ import sys
21
+ from pathlib import Path
22
+ from typing import Any
23
+
24
+ from code_atlas.ui import i18n
25
+ from code_atlas.ui.kit import (
26
+ NonInteractive,
27
+ UIContext,
28
+ _c,
29
+ confirm,
30
+ dashboard,
31
+ multi_select,
32
+ select,
33
+ )
34
+
35
+ _ALL_HOSTS = ("claude", "devin", "codex", "copilot")
36
+ _SCOPES = ("project", "workspace", "user")
37
+ _SCOPE_LABELS = {
38
+ "project": "Current repository",
39
+ "workspace": "Entire workspace",
40
+ "user": "My user account",
41
+ }
42
+ _PROFILES = ("recommended", "minimal", "full") # service contract names
43
+ _PROFILE_LABELS = {
44
+ "recommended": "Balanced (Recommended)",
45
+ "minimal": "Economy",
46
+ "full": "Full",
47
+ }
48
+ _GATEWAY_PROFILES = ("economy", "balanced", "deep")
49
+ _GATEWAY_LABELS = {
50
+ "economy": "Economy (lowest context cost)",
51
+ "balanced": "Balanced (recommended)",
52
+ "deep": "Deep (maximum verification)",
53
+ }
54
+ _COMPONENTS = ("skills", "agents", "mcp", "tui", "graph-studio")
55
+ _COMPONENT_LABELS = {
56
+ "skills": "Skills",
57
+ "agents": "Agents",
58
+ "mcp": "MCP",
59
+ "tui": "TUI",
60
+ "graph-studio": "Graph Studio",
61
+ }
62
+ _COMPONENT_DETAILS = {
63
+ "skills": "host-discoverable skills and progressive capability guidance",
64
+ "agents": "specialists, subagents and declared agent instructions",
65
+ "mcp": "MCP configuration and governed server entry points",
66
+ "tui": "the terminal command center runtime",
67
+ "graph-studio": "federated graph views and local graph navigation",
68
+ }
69
+ _COMPONENT_DEFAULTS = {
70
+ "minimal": {"mcp", "tui"},
71
+ "recommended": {"skills", "agents", "mcp", "tui", "graph-studio"},
72
+ "full": {"skills", "agents", "mcp", "tui", "graph-studio"},
73
+ }
74
+
75
+
76
+ def _has_vcs_root(start: Path) -> bool:
77
+ """Return whether current directory belongs to a supported project root."""
78
+ return any(
79
+ (candidate / ".git").exists()
80
+ or ((candidate / "forge.json").is_file() and (candidate / "pyproject.toml").is_file())
81
+ for candidate in (start, *start.parents)
82
+ )
83
+
84
+
85
+ def _scope_choices(ctx: UIContext, scopes: tuple[str, ...]) -> list[str]:
86
+ """Hide repository-only choice when operator is in a fresh directory."""
87
+ choices = list(scopes)
88
+ if "project" in choices and not _has_vcs_root(Path.cwd()):
89
+ print(
90
+ _c(
91
+ ctx,
92
+ "33",
93
+ " No repository detected; choose Entire workspace to use this directory "
94
+ "or My user account.",
95
+ )
96
+ )
97
+ choices.remove("project")
98
+ return choices
99
+
100
+
101
+ def env_check_rows(hosts: tuple[str, ...] = _ALL_HOSTS) -> list[tuple[str, str]]:
102
+ """Real environment evidence: python, git, host binaries."""
103
+ v = sys.version_info
104
+ rows = [("Python", f"{v.major}.{v.minor}.{v.micro}")]
105
+ rows.append(("Git", "OK" if shutil.which("git") else "missing"))
106
+ for h in hosts:
107
+ rows.append((h.capitalize(), "Available" if shutil.which(h) else "not detected"))
108
+ return rows
109
+
110
+
111
+ def _banner(ctx: UIContext, forge_name: str) -> None:
112
+ print()
113
+ print(_c(ctx, "1", f" {forge_name.upper()}"))
114
+ print(_c(ctx, "2", " " + ("─" if ctx.unicode else "-") * max(10, len(forge_name) + 4)))
115
+ print(f" {i18n.t('env_detected', ctx.language)}:")
116
+
117
+
118
+ def run_wizard(
119
+ *,
120
+ forge_name: str,
121
+ install_fn: Any,
122
+ doctor_fn: Any | None = None,
123
+ hosts_available: tuple[str, ...] = _ALL_HOSTS,
124
+ gateway_profiles: tuple[str, ...] = _GATEWAY_PROFILES,
125
+ scopes: tuple[str, ...] = _SCOPES,
126
+ component_order: tuple[str, ...] | None = _COMPONENTS,
127
+ component_labels: dict[str, str] | None = None,
128
+ component_details: dict[str, str] | None = None,
129
+ component_defaults: dict[str, set[str]] | None = None,
130
+ env_hosts: tuple[str, ...] | None = None,
131
+ next_hint: str | None = None,
132
+ ctx: UIContext | None = None,
133
+ out_json: bool = False,
134
+ family: bool = False,
135
+ ) -> int:
136
+ """Interactive install wizard. Returns exit code.
137
+
138
+ ``install_fn(**kwargs)`` is the forge's real install service
139
+ (``host``/``scope``/``profile``/``gateway_profile``/``components``/
140
+ ``dry_run``/``yes`` kwargs). ``doctor_fn`` optionally verifies
141
+ post-install. Empty vocabularies skip their step: no hosts, no
142
+ gateway profile or no components means the question is never asked.
143
+ """
144
+ ctx = ctx or UIContext.detect()
145
+ if not ctx.interactive:
146
+ raise NonInteractive("install wizard requires a TTY")
147
+
148
+ comp_order = component_order or ()
149
+ comp_labels = component_labels or _COMPONENT_LABELS
150
+ comp_details = component_details or _COMPONENT_DETAILS
151
+ comp_defaults = component_defaults or _COMPONENT_DEFAULTS
152
+
153
+ _banner(ctx, forge_name)
154
+ env_rows = env_check_rows(hosts_available if env_hosts is None else env_hosts)
155
+ for label, val in env_rows:
156
+ print(f" {label:<14} {_c(ctx, '32' if val in ('OK', 'Available') else '2', val)}")
157
+ print()
158
+ if family:
159
+ print(_c(ctx, "36", " family mode: The Forge + registered specialist forges"))
160
+ print(_c(ctx, "2", " one real plan, one approval, each forge keeps its own installer"))
161
+ print()
162
+
163
+ # --- scope ---------------------------------------------------------------
164
+ scope_choices = _scope_choices(ctx, scopes)
165
+ idx = select(
166
+ i18n.t("install_scope_q", ctx.language),
167
+ [_SCOPE_LABELS.get(s, s) for s in scope_choices],
168
+ ctx=ctx,
169
+ )
170
+ if idx is None:
171
+ return 130
172
+ scope = scope_choices[idx]
173
+
174
+ # --- profile -------------------------------------------------------------
175
+ idx = select(
176
+ i18n.t("install_profile_q", ctx.language),
177
+ [_PROFILE_LABELS[p] for p in _PROFILES],
178
+ ctx=ctx,
179
+ )
180
+ if idx is None:
181
+ return 130
182
+ profile = _PROFILES[idx]
183
+
184
+ # --- execution profile ----------------------------------------------------
185
+ gateway_profile: str | None = None
186
+ if gateway_profiles:
187
+ idx = select(
188
+ i18n.t("install_gateway_profile_q", ctx.language),
189
+ [_GATEWAY_LABELS.get(p, p) for p in gateway_profiles],
190
+ ctx=ctx,
191
+ )
192
+ if idx is None:
193
+ return 130
194
+ gateway_profile = gateway_profiles[idx]
195
+
196
+ # --- optional components ---------------------------------------------------
197
+ components: tuple[str, ...] | None = None
198
+ if comp_order:
199
+ comp_checked = comp_defaults.get(profile, set())
200
+ print(_c(ctx, "2", " component choices (economy loads optional knowledge/evals on demand):"))
201
+ for component in comp_order:
202
+ detail = comp_details.get(component)
203
+ print(f" {component:<13} {detail}" if detail else f" {component}")
204
+ comp_chosen = multi_select(
205
+ i18n.t("install_components_q", ctx.language),
206
+ [comp_labels.get(c, c) for c in comp_order],
207
+ checked={i for i, c in enumerate(comp_order) if c in comp_checked},
208
+ ctx=ctx,
209
+ )
210
+ if comp_chosen is None:
211
+ return 130
212
+ components = tuple(sorted(comp_order[i] for i in comp_chosen))
213
+
214
+ # --- hosts ---------------------------------------------------------------
215
+ host_arg: str | None = None
216
+ if hosts_available:
217
+ detected = {
218
+ i
219
+ for i, h in enumerate(hosts_available)
220
+ if any(h in r[0].lower() and r[1] == "Available" for r in env_rows)
221
+ }
222
+ chosen = multi_select(
223
+ i18n.t("install_hosts_q", ctx.language),
224
+ list(hosts_available),
225
+ checked=detected,
226
+ ctx=ctx,
227
+ )
228
+ if chosen is None:
229
+ return 130
230
+ if not chosen:
231
+ host_arg = None
232
+ elif len(chosen) == len(hosts_available):
233
+ host_arg = "all"
234
+ else:
235
+ host_arg = ",".join(hosts_available[i] for i in sorted(chosen))
236
+
237
+ # --- review (real dry-run plan) ------------------------------------------
238
+ # Contrato explícito: install_fn aceita `components` — wrappers **kw
239
+ # encaminham sem inspeção de assinatura (GAP-002).
240
+ kwargs: dict[str, Any] = {
241
+ "scope": scope,
242
+ "profile": profile,
243
+ "gateway_profile": gateway_profile,
244
+ "components": components,
245
+ }
246
+ try:
247
+ # `none` é opt-out explícito — zero hosts escolhidos nunca vira
248
+ # "all" (GAP-003); csv de subconjunto é contrato válido (GAP-003b).
249
+ plan = install_fn(host=host_arg or "none", dry_run=True, **kwargs)
250
+ except Exception as exc:
251
+ print(_c(ctx, "31", f"plan failed: {exc}"))
252
+ return 1
253
+
254
+ planned = (
255
+ plan.get("planned")
256
+ or plan.get("planned_files")
257
+ or plan.get("writes")
258
+ or plan.get("plan")
259
+ or []
260
+ )
261
+ review_rows = [
262
+ ("scope", scope),
263
+ ("profile", profile),
264
+ ]
265
+ if gateway_profile is not None:
266
+ review_rows.append(("execution", gateway_profile))
267
+ review_rows.append(("mode", "family" if family else "this forge"))
268
+ if comp_order:
269
+ review_rows.append(("components", ", ".join(components or ()) or "none"))
270
+ if hosts_available:
271
+ review_rows.append(("hosts", host_arg or "none"))
272
+ review_rows.append(
273
+ ("managed writes", str(len(planned) if isinstance(planned, list) else planned))
274
+ )
275
+ dashboard(
276
+ f"{forge_name} — {i18n.t('review', ctx.language)}",
277
+ [("Plan", review_rows)],
278
+ ctx=ctx,
279
+ )
280
+ if isinstance(planned, list):
281
+ for entry in planned[:10]:
282
+ if isinstance(entry, dict):
283
+ path = str(entry.get("path") or entry.get("target") or "")
284
+ else:
285
+ path = str(entry)
286
+ print(f" {_c(ctx, '2', path)}")
287
+ if len(planned) > 10:
288
+ print(f" … {len(planned) - 10} more")
289
+
290
+ if not confirm(i18n.t("confirm_q", ctx.language), default=True, ctx=ctx):
291
+ return 130
292
+
293
+ # --- apply (real governed install) ---------------------------------------
294
+ receipt = install_fn(host=host_arg or "none", yes=True, dry_run=False, **kwargs)
295
+ status = receipt.get("status", "unknown")
296
+ if out_json:
297
+ print(json.dumps(receipt, indent=2, ensure_ascii=False))
298
+ color = "32" if status == "completed" else "31"
299
+ print(f"\n {i18n.t('status', ctx.language)}: {_c(ctx, color, status)}")
300
+
301
+ # --- verify --------------------------------------------------------------
302
+ if doctor_fn is not None and status == "completed":
303
+ health = doctor_fn(scope=scope)
304
+ raw_health = health.get("status") or health.get("health") or "unknown"
305
+ hstatus = raw_health
306
+ if isinstance(raw_health, dict):
307
+ hstatus = raw_health.get("status", "unknown")
308
+ color = "32" if hstatus in ("healthy", "PASS") else "33"
309
+ print(f" {i18n.t('health', ctx.language)}: {_c(ctx, color, str(hstatus))}")
310
+
311
+ if status == "completed" and next_hint:
312
+ print(f" next: {next_hint}")
313
+
314
+ return 0 if status == "completed" else 1
315
+
316
+
317
+ __all__ = ["run_wizard", "env_check_rows", "NonInteractive", "UIContext"]
@@ -0,0 +1,246 @@
1
+ Metadata-Version: 2.4
2
+ Name: code-atlas-forge
3
+ Version: 1.1.0
4
+ Summary: Plataforma local-first de inteligência estrutural de código — Cycle 4.1: retrieval, context packs, MCP e evidência canônica
5
+ Author: Edgar Socrates
6
+ License-Expression: Apache-2.0
7
+ Keywords: code-intelligence,code-graph,static-analysis,local-first
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Environment :: Console
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Topic :: Software Development
15
+ Requires-Python: >=3.12
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ License-File: NOTICE
19
+ Requires-Dist: tree-sitter==0.25.2
20
+ Requires-Dist: tree-sitter-python==0.23.6
21
+ Requires-Dist: tree-sitter-typescript==0.23.2
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=8.0; extra == "dev"
24
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
25
+ Requires-Dist: ruff>=0.6.0; extra == "dev"
26
+ Requires-Dist: mypy>=1.11.0; extra == "dev"
27
+ Requires-Dist: build>=1.2; extra == "dev"
28
+ Requires-Dist: mcp>=2.3.0; extra == "dev"
29
+ Provides-Extra: vector
30
+ Requires-Dist: sqlite-vec>=0.1.6; extra == "vector"
31
+ Dynamic: license-file
32
+
33
+ # Code Atlas Forge
34
+
35
+ <p align="center">
36
+ <img src="docs/assets/logo.png" alt="Code Atlas logo" width="420" />
37
+ </p>
38
+
39
+ Plataforma **open source, local-first e offline-first** de inteligência estrutural,
40
+ semântica e arquitetural de software — grafos tipados, proveniência verificável,
41
+ indexação incremental e contexto econômico para agentes.
42
+
43
+ > **Status atual: Cycle 8 — production quality em andamento
44
+ > (branch `cycle-8-production-quality`); Cycle 7 (inteligência de
45
+ > domínio + federação) entregue e arquivado.**
46
+ > O Code Atlas indexa repositórios com parsing real (Tree-sitter), extrai
47
+ > símbolos e constrói um grafo tipado persistido em SQLite, consultável via
48
+ > CLI, servidor MCP stdio, **API HTTP loopback `/api/v1`** e o
49
+ > **Explorer** — workbench visual Angular servido por
50
+ > `code-atlas explorer`. Análise de impacto entre revisões
51
+ > (`code-atlas impact` / `POST /impact/analyze`) está disponível com
52
+ > estados de binding honestos. O Cycle 7 adiciona **seis adapters de
53
+ > domínio opt-in** (SQL, PySpark, AWS data, API contracts, Terraform,
54
+ > CI/CD) com grafo de domínio snapshot-scoped (schema v9), **resolução
55
+ > cross-domain** por identidade qualificada, **federação multi-repo**
56
+ > read-only com pins por snapshot (schema v10), faceta de domínio e
57
+ > busca federada no SearchEngine, blast radius misto no Impact Engine,
58
+ > context packs de domínio, cinco telas novas no Explorer e layout FA2
59
+ > assíncrono em Web Worker (RAF gap máx. 83 ms, era ~2300 ms). Veja
60
+ > `docs/cycle-7-architecture.md`, `docs/cycle-7-homologation.md`,
61
+ > `docs/cycle-7-limitations.md` e `docs/roadmap.md`.
62
+
63
+ ## Princípios
64
+
65
+ - **Local-first:** nenhum serviço externo, Docker, conta SaaS ou API key é
66
+ necessário para operar. Nenhum dado sai da máquina por padrão.
67
+ - **Sem telemetria:** não existe código de telemetria no projeto — a coleta
68
+ não é apenas desligada por padrão, ela está ausente.
69
+ - **O repositório indexado é não confiável:** nada do código varrido é
70
+ executado, importado ou instalado.
71
+ - **Evidência primeiro:** toda relação carrega origem, extrator, versão,
72
+ confiança e status de resolução.
73
+ - **Determinismo:** a mesma árvore produz o mesmo grafo e os mesmos ids.
74
+
75
+ A especificação arquitetural normativa está em `docs/BLUEPRINT-v1.md`.
76
+
77
+ ## Instalação
78
+
79
+ Requer Python 3.12+. Dependências de runtime pinned: `tree-sitter` +
80
+ gramáticas (ADR-015) — instaladas automaticamente via wheels.
81
+
82
+ ```bash
83
+ git clone https://github.com/EdgarSocrates98/code-atlas-forge.git
84
+ cd code-atlas-forge
85
+ python3 -m venv .venv
86
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
87
+ pip install .
88
+ code-atlas --version
89
+ code-atlas doctor
90
+ ```
91
+
92
+ Para desenvolvimento: `pip install -e .[dev]`.
93
+ Detalhes em `docs/install.md`.
94
+
95
+ ## Uso rápido
96
+
97
+ ```bash
98
+ code-atlas init --root /caminho/do/repo # configura o workspace (XDG/APPDATA)
99
+ code-atlas doctor # verifica ambiente e config
100
+ code-atlas index /caminho/do/repo # incremental é o default; --full força rebuild
101
+ code-atlas index . --scip idx.scip # binding SCIP ad-hoc (proveniência mantida)
102
+ code-atlas index . --resolver scip # restringe resolvers ativos (erro tipado se desconhecido)
103
+ code-atlas index-plan /caminho/do/repo # dry-run do IndexPlan, sem tocar no DB
104
+ code-atlas status --json # estado do índice, git, migrações
105
+ code-atlas semantic-status . --json # resolvers: installed/enabled/used + coverage do READY
106
+
107
+ # consultas sobre o snapshot READY (envelope v2)
108
+ code-atlas search "Engine" --json # substring em qualified_name
109
+ code-atlas symbol pkg.core.Engine # detalhe + ocorrências
110
+ code-atlas references pkg.util.helper # incoming, com status/confiança
111
+ code-atlas definitions pkg.util.helper # defs + declarações do símbolo
112
+ code-atlas dependencies pkg.app.main --depth 2 # BFS outgoing, cycle-safe
113
+ code-atlas graph --json # dump de nós+arestas do snapshot
114
+
115
+ # retrieval híbrido + contexto (Cycle 4)
116
+ code-atlas search "q" --strategy lexical|structural|graph|hybrid --limit 10 --json
117
+ code-atlas context "create_order" --level focus --budget 4000 --format markdown
118
+ code-atlas context-expand --symbol pkg.orders.validate_total --snapshot 1 --delivered sym:pkg.orders
119
+ code-atlas mcp # servidor MCP stdio (JSON-RPC ndjson)
120
+ code-atlas mcp doctor --json # executável, DB, schema, sqlite_vec
121
+ code-atlas mcp manifest --host claude-code # emite config (nunca escreve)
122
+
123
+ # impacto entre revisões/snapshots (Cycle 5)
124
+ code-atlas impact report --base HEAD~1 --target HEAD --format json
125
+
126
+ # API local + Explorer visual (Cycle 6)
127
+ code-atlas api --port 8741 # só /api/v1, loopback, read-only
128
+ code-atlas explorer --open # API + UI Angular compilada
129
+
130
+ # domínios + federação (Cycle 7 — opt-in, default OFF)
131
+ code-atlas index . --domains sql,pyspark --cross-domain # extrai domínio no snapshot
132
+ code-atlas domains list # adapters registrados (listar não extrai)
133
+ code-atlas domains entities --domain sql # entidades do snapshot READY
134
+ code-atlas domains entity 'sql:mart.daily_revenue'
135
+ code-atlas domains lineage staging.orders --direction up --depth 3
136
+ code-atlas federation create minha-view # workspace multi-repo
137
+ code-atlas federation add minha-view /repo/a
138
+ code-atlas federation add minha-view /repo/b
139
+ code-atlas federation pin minha-view a 42 # pin de snapshot (latest desfaz)
140
+ code-atlas federation view minha-view --json
141
+ ```
142
+
143
+ Filtros: `--language`, `--kind`, `--path`, `--snapshot`,
144
+ `--relation-type`, `--limit`/`--offset`. Saída JSON estável com
145
+ `schema_version`. Detalhes: `docs/structural-search.md`, `docs/hybrid-search.md`,
146
+ `docs/graph-retrieval.md`, `docs/context-engineering.md`,
147
+ `docs/mcp-server.md`.
148
+
149
+ Configuração: `--root` > variáveis `CODE_ATLAS_*` > `XDG_CONFIG_HOME` /
150
+ `%APPDATA%`. Nada é escrito dentro do repositório indexado.
151
+
152
+ ## Linguagens suportadas (Cycle 2)
153
+
154
+ Python (`.py`/`.pyi`), TypeScript (`.ts` variantes), TSX (`.tsx`) —
155
+ matriz completa com versões de gramática pinned em
156
+ `docs/parser-adapters.md`. Arquivos de outras linguagens entram no
157
+ inventário como nós `file`, sem extração.
158
+
159
+ ## Limitações
160
+
161
+ Implementado hoje: parsing sintático real, símbolos/referências/
162
+ relações com proveniência por aresta, resolução syntactic **integrada**
163
+ a resolvers opt-in SCIP/LSP, indexação incremental com cache
164
+ versionado, snapshots atômicos, busca estrutural SQL, **FTS5
165
+ snapshot-scoped**, **retrieval híbrido (RRF k=60 + rerank task-aware
166
+ opt-in)**, graph retrieval multi-seed com direção por intent,
167
+ **context packs** com budget do payload serializado e expansão
168
+ progressiva, **servidor MCP stdio** (read-only, homologado com o SDK
169
+ oficial `mcp`), **impact engine** entre revisões/snapshots com binding
170
+ honesto (`partial`/`mismatch`/`unavailable` nunca viram resultado
171
+ verificado), **API HTTP loopback `/api/v1`** stdlib read-only
172
+ (ADR-0009), o **Explorer Angular** (`code-atlas explorer`) — grafo
173
+ bounded, busca, impacto, revisões, context packs e diagnósticos — e,
174
+ no Cycle 7, **adapters de domínio opt-in** (SQL/PySpark/AWS data/
175
+ API/Terraform/CI-CD, stdlib-only, zero deps novas), **grafo de
176
+ domínio** persistido com estados `resolved`/`ambiguous`/`unresolved`/
177
+ `external`, **resolução cross-domain** por identidade qualificada,
178
+ **federação multi-repo** com snapshot pinado por membro, **busca
179
+ federada** e faceta `domain`, **blast misto** símbolo+domínio,
180
+ **context packs de domínio** e **views de domínio no Explorer**
181
+ (`/lineage`, `/contracts`, `/infra`, `/pipelines`, `/federation`).
182
+
183
+ **Não implementado** (por design): type-checking real (resolver
184
+ sintático não infere receiver — `d.speak()` fica `unresolved`),
185
+ embeddings semânticos reais (provider naïve documentado, ADR-0022),
186
+ structural sharing de grafo entre snapshots (rejeitado, ADR-0020),
187
+ escrita via API/UI (read-only por contrato), telemetria (ausente por
188
+ spec), conexão com cloud real (adapters de domínio leem só artefatos
189
+ declarados no repo — zero rede, zero execução), mutação de federação
190
+ por HTTP (CLI-only), FTS de entidades de domínio (`q=` é `LIKE`).
191
+
192
+ **Homologado com ressalvas** (Cycle 6.1 — `docs/cycle-6.1-limitations.md`):
193
+ sem benchmark de 10k nós (máximo medido: 2000 renderizados; API trunca a
194
+ 2000, canvas capa a 500/2000), arestas do overview sem custo medido
195
+ (0 edges por design), Firefox/Safari/Windows interativo **NOT RUN**,
196
+ sem passeio com screen reader, ~55 vulnerabilidades `npm audit` (0
197
+ critical em produção — `docs/cycle-6.1-dependency-audit.md`).
198
+ **Verificado no 6.1:** 102 testes Playwright (flows, security, a11y,
199
+ scale, screenshots) verdes no job `explorer-e2e`; auditoria axe WCAG 2.2
200
+ AA em 24 scans com **0 violações**; rate limit 300/min + timeout 30 s +
201
+ CSP/XFO na API; drill-down via `GET /files/{id}/occurrences`;
202
+ `evidence_ids` emitidos nas arestas; canvas congelado pós-relayout
203
+ corrigido e medido; `npm ci` reproduzível.
204
+ Estados `unresolved`/`ambiguous`/`external` são preservados como
205
+ fatos — nunca preenchidos por heurística. Detalhes:
206
+ `docs/semantic-resolution.md`, `docs/cycle-3.1-evidence.md`,
207
+ `docs/semantic-accuracy-report.md`, `docs/cycle-6-homologation.md`,
208
+ `docs/cycle-6.1-evidence.md`, `docs/cycle-7-homologation.md`,
209
+ `docs/cycle-7-limitations.md`.
210
+
211
+ ## Estrutura do repositório
212
+
213
+ ```
214
+ src/code_atlas/ pacote (layout src; deps pinned = tree-sitter)
215
+ contracts/ modelos de domínio, enums, ports (hexagonal)
216
+ discovery/ scanner Git-aware + manifest de inventário
217
+ parsers/ engine + registry + adaptadores tree-sitter
218
+ graph/ builder canônico, identidades, validação
219
+ resolvers/ syntactic + SCIP/LSP opt-in, enrichment, bootstrap
220
+ storage/ SQLite: migrações v1-v10, snapshots, FTS5
221
+ indexing/ coordinator + persistência do grafo
222
+ search/ StructuralSearch (SQL parametrizado)
223
+ impact/ ImpactEngine: diff, binding, blast misto, risco, testes
224
+ domains/ adapters de domínio opt-in (sql, pyspark, aws, api,
225
+ terraform, cicd) + registry, identity, crossresolve
226
+ federation/ workspaces multi-repo, pins, views (schema v10)
227
+ eval/ suporte do runner de avaliação por goldens
228
+ api/ HTTP loopback read-only /api/v1 (stdlib, ADR-0009)
229
+ observability/ logging estruturado + redaction (sem telemetria)
230
+ explorer/ workbench Angular 18 (SPA servida por `code-atlas explorer`)
231
+ tests/ suíte pytest (unitários, golden corpus, e2e, bench)
232
+ docs/ blueprint, ADRs, roadmap, schemas, evidências
233
+ factory/ specs Loop Factory (inbox/active/archive + audit)
234
+ benchmarks/ bench_scan (cycle-1) + bench_index (cycle-2)
235
+ ```
236
+
237
+ ## Desenvolvimento
238
+
239
+ ```bash
240
+ pip install -e .[dev]
241
+ ruff check src tests && mypy src && pytest -q
242
+ ```
243
+
244
+ ## Licença
245
+
246
+ Apache-2.0 — veja `LICENSE` e `NOTICE`.