graphite-code 0.3.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 (112) hide show
  1. graphite/__init__.py +41 -0
  2. graphite/__main__.py +7 -0
  3. graphite/_cleanup_worker.py +525 -0
  4. graphite/activation.py +164 -0
  5. graphite/agent_hooks.py +577 -0
  6. graphite/agent_settings.py +226 -0
  7. graphite/analyze.py +146 -0
  8. graphite/answer_contract.py +420 -0
  9. graphite/bootstrap.py +210 -0
  10. graphite/buildlock.py +99 -0
  11. graphite/cache.py +131 -0
  12. graphite/channel.py +1325 -0
  13. graphite/cli.py +3053 -0
  14. graphite/cluster.py +111 -0
  15. graphite/config.py +209 -0
  16. graphite/context.py +355 -0
  17. graphite/daemon.py +745 -0
  18. graphite/daemon_health.py +733 -0
  19. graphite/debt.py +118 -0
  20. graphite/dependency_install.py +1597 -0
  21. graphite/detach.py +33 -0
  22. graphite/doctor.py +678 -0
  23. graphite/doctor_probes.py +2100 -0
  24. graphite/engine_identity.py +238 -0
  25. graphite/export/__init__.py +6 -0
  26. graphite/export/html.py +244 -0
  27. graphite/export/json.py +39 -0
  28. graphite/export/md.py +68 -0
  29. graphite/extract/__init__.py +4 -0
  30. graphite/extract/ast.py +1964 -0
  31. graphite/freshness.py +127 -0
  32. graphite/git.py +406 -0
  33. graphite/graph.py +117 -0
  34. graphite/graph_io.py +188 -0
  35. graphite/health.py +147 -0
  36. graphite/hook_entry.py +68 -0
  37. graphite/hookinstall.py +224 -0
  38. graphite/hookshim.py +86 -0
  39. graphite/incident_ledger.py +247 -0
  40. graphite/ingest.py +279 -0
  41. graphite/init.py +791 -0
  42. graphite/io.py +32 -0
  43. graphite/listing.py +51 -0
  44. graphite/llm.py +518 -0
  45. graphite/llm_probe.py +157 -0
  46. graphite/mcp.py +7 -0
  47. graphite/mcp_server.py +450 -0
  48. graphite/natural_query.py +252 -0
  49. graphite/overlays.py +713 -0
  50. graphite/probe_process.py +879 -0
  51. graphite/probe_workspace.py +728 -0
  52. graphite/process_contracts.py +22 -0
  53. graphite/provider_observer.py +397 -0
  54. graphite/query.py +646 -0
  55. graphite/query_plan.py +97 -0
  56. graphite/replacement_audit.py +291 -0
  57. graphite/resolve.py +660 -0
  58. graphite/review.py +782 -0
  59. graphite/routing/__init__.py +5 -0
  60. graphite/routing/approval.py +362 -0
  61. graphite/routing/classifier.py +169 -0
  62. graphite/routing/claude_executor.py +419 -0
  63. graphite/routing/claude_probe.py +102 -0
  64. graphite/routing/cli_identity.py +84 -0
  65. graphite/routing/codex_executor.py +383 -0
  66. graphite/routing/codex_probe.py +93 -0
  67. graphite/routing/context_builder.py +327 -0
  68. graphite/routing/contracts.py +802 -0
  69. graphite/routing/diff_policy.py +468 -0
  70. graphite/routing/edit_apply.py +166 -0
  71. graphite/routing/effort.py +43 -0
  72. graphite/routing/lifecycle.py +771 -0
  73. graphite/routing/lifecycle_operator.py +227 -0
  74. graphite/routing/lifecycle_service.py +555 -0
  75. graphite/routing/lifecycle_storage.py +977 -0
  76. graphite/routing/ollama_executor.py +341 -0
  77. graphite/routing/ollama_probe.py +72 -0
  78. graphite/routing/openrouter_executor.py +338 -0
  79. graphite/routing/openrouter_probe.py +188 -0
  80. graphite/routing/policy.py +815 -0
  81. graphite/routing/probe_runner.py +543 -0
  82. graphite/routing/process_runner.py +523 -0
  83. graphite/routing/profiles.py +554 -0
  84. graphite/routing/prompt.py +58 -0
  85. graphite/routing/registry.py +444 -0
  86. graphite/routing/route_pool.py +629 -0
  87. graphite/routing/route_pool_execution.py +275 -0
  88. graphite/routing/schema_validation.py +169 -0
  89. graphite/routing/service.py +1263 -0
  90. graphite/routing/settings.py +99 -0
  91. graphite/routing/shadow.py +201 -0
  92. graphite/routing/storage.py +4001 -0
  93. graphite/routing/telemetry.py +346 -0
  94. graphite/routing/worktree.py +259 -0
  95. graphite/routing/zai_edit.py +113 -0
  96. graphite/routing/zai_executor.py +191 -0
  97. graphite/routing/zai_probe.py +126 -0
  98. graphite/savings.py +84 -0
  99. graphite/ts_bridge.py +142 -0
  100. graphite/ts_resolver.mjs +314 -0
  101. graphite/typescript_activation.py +1586 -0
  102. graphite/usage_ledger.py +156 -0
  103. graphite/validation.py +148 -0
  104. graphite/watch.py +167 -0
  105. graphite/windows_job.py +368 -0
  106. graphite/windows_startup.py +144 -0
  107. graphite/windows_task.py +212 -0
  108. graphite_code-0.3.0.dist-info/METADATA +743 -0
  109. graphite_code-0.3.0.dist-info/RECORD +112 -0
  110. graphite_code-0.3.0.dist-info/WHEEL +4 -0
  111. graphite_code-0.3.0.dist-info/entry_points.txt +3 -0
  112. graphite_code-0.3.0.dist-info/licenses/LICENSE +21 -0
graphite/debt.py ADDED
@@ -0,0 +1,118 @@
1
+ """Declared debt, with the interval that makes it actionable.
2
+
3
+ The target for this project was never "zero known issues". That bar punishes the
4
+ sessions that find real defects, and it is satisfiable by not looking. What
5
+ matters is the LATENCY: how long a blind spot stays known-but-undeclared, and
6
+ then how long a declared one stays open.
7
+
8
+ `CAVEAT_REGISTRY` already records both endpoints -- `since` is the day a
9
+ blindspot class was confirmed, `retired_by` the day it stopped being emitted,
10
+ and its process rule requires the entry on the day of confirmation, decoupled
11
+ from the fix. So the series existed and nothing read it.
12
+
13
+ Deliberately offline and deterministic, like every other canonical surface here:
14
+ `as_of` is a parameter rather than a call to `date.today()`, so the output can
15
+ be asserted on and compared across runs. GitHub issues are NOT consulted --
16
+ that would put a network call and a non-reproducible answer inside a diagnostic
17
+ whose whole value is being comparable.
18
+ """
19
+ from __future__ import annotations
20
+
21
+ from datetime import date
22
+ from typing import Any
23
+
24
+ from .answer_contract import CAVEAT_REGISTRY
25
+
26
+ DEBT_SCHEMA = 1
27
+
28
+
29
+ def _parse(stamp: str) -> date:
30
+ return date.fromisoformat(stamp)
31
+
32
+
33
+ def debt_report(*, as_of: date) -> dict[str, Any]:
34
+ """Declared blind spots, open and retired, as of a given day."""
35
+ open_items: list[dict[str, Any]] = []
36
+ retired_items: list[dict[str, Any]] = []
37
+
38
+ for entry in CAVEAT_REGISTRY:
39
+ since = _parse(entry["since"])
40
+ retired_by = entry.get("retired_by")
41
+ if retired_by:
42
+ retired_items.append(
43
+ {
44
+ "code": entry["code"],
45
+ "summary": entry["summary"],
46
+ "since": entry["since"],
47
+ "retired_by": retired_by,
48
+ # Declaration -> fix. Zero is a real and good value: the
49
+ # process rule allows an entry and its fix on the same day.
50
+ "latency_days": (_parse(retired_by) - since).days,
51
+ }
52
+ )
53
+ continue
54
+ open_items.append(
55
+ {
56
+ "code": entry["code"],
57
+ "summary": entry["summary"],
58
+ "since": entry["since"],
59
+ # Clamped at zero: `as_of` is operator input and can precede a
60
+ # declaration. A negative age would read as a fresh item and
61
+ # sort itself to the bottom of the list, which is the one place
62
+ # nobody looks.
63
+ "age_days": max(0, (as_of - since).days),
64
+ }
65
+ )
66
+
67
+ # Oldest first: the list is read top-down, and the top is where attention
68
+ # goes. Ties break on code so the ordering is total and the report is
69
+ # comparable across runs.
70
+ open_items.sort(key=lambda item: (-item["age_days"], item["code"]))
71
+ retired_items.sort(key=lambda item: (item["retired_by"], item["code"]))
72
+
73
+ latencies = sorted(item["latency_days"] for item in retired_items)
74
+ summary = {
75
+ "open_count": len(open_items),
76
+ "retired_count": len(retired_items),
77
+ "oldest_open_days": open_items[0]["age_days"] if open_items else 0,
78
+ "oldest_open_code": open_items[0]["code"] if open_items else None,
79
+ "median_retire_latency_days": (
80
+ latencies[len(latencies) // 2] if latencies else None
81
+ ),
82
+ }
83
+
84
+ return {
85
+ "schema_version": DEBT_SCHEMA,
86
+ "as_of": as_of.isoformat(),
87
+ "open": open_items,
88
+ "retired": retired_items,
89
+ "summary": summary,
90
+ }
91
+
92
+
93
+ def render_debt(report: dict[str, Any]) -> str:
94
+ """Human rendering. The ages are the point, so they lead each line."""
95
+ lines = [f"[graphite] declared debt as of {report['as_of']}"]
96
+ summary = report["summary"]
97
+
98
+ if not report["open"]:
99
+ lines.append(" no open blind spots declared")
100
+ else:
101
+ lines.append(f" OPEN ({summary['open_count']}):")
102
+ for item in report["open"]:
103
+ lines.append(f" {item['age_days']:>5}d {item['code']}")
104
+ lines.append(f" {item['summary']}")
105
+
106
+ if report["retired"]:
107
+ lines.append(f" RETIRED ({summary['retired_count']}), declaration -> fix:")
108
+ for item in report["retired"]:
109
+ lines.append(f" {item['latency_days']:>5}d {item['code']}")
110
+
111
+ median = summary["median_retire_latency_days"]
112
+ if median is not None:
113
+ lines.append(f" median time to retire: {median}d")
114
+ lines.append(
115
+ " note: counts are not the target -- an unfixed blind spot that is "
116
+ "DECLARED is working as designed; an undeclared one is the failure."
117
+ )
118
+ return "\n".join(lines)