axion-code 1.0.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 (82) hide show
  1. axion/__init__.py +3 -0
  2. axion/api/__init__.py +0 -0
  3. axion/api/anthropic.py +460 -0
  4. axion/api/client.py +259 -0
  5. axion/api/error.py +161 -0
  6. axion/api/ollama.py +597 -0
  7. axion/api/openai_compat.py +805 -0
  8. axion/api/openai_responses.py +627 -0
  9. axion/api/prompt_cache.py +31 -0
  10. axion/api/sse.py +98 -0
  11. axion/api/types.py +451 -0
  12. axion/cli/__init__.py +0 -0
  13. axion/cli/init_cmd.py +50 -0
  14. axion/cli/input.py +290 -0
  15. axion/cli/main.py +2953 -0
  16. axion/cli/render.py +489 -0
  17. axion/cli/tui.py +766 -0
  18. axion/commands/__init__.py +0 -0
  19. axion/commands/handlers/__init__.py +0 -0
  20. axion/commands/handlers/agents.py +51 -0
  21. axion/commands/handlers/builtin_commands.py +367 -0
  22. axion/commands/handlers/mcp.py +59 -0
  23. axion/commands/handlers/models.py +75 -0
  24. axion/commands/handlers/plugins.py +55 -0
  25. axion/commands/handlers/skills.py +61 -0
  26. axion/commands/parsing.py +317 -0
  27. axion/commands/registry.py +166 -0
  28. axion/compat_harness/__init__.py +0 -0
  29. axion/compat_harness/extractor.py +145 -0
  30. axion/plugins/__init__.py +0 -0
  31. axion/plugins/hooks.py +22 -0
  32. axion/plugins/manager.py +391 -0
  33. axion/plugins/manifest.py +270 -0
  34. axion/runtime/__init__.py +0 -0
  35. axion/runtime/bash.py +388 -0
  36. axion/runtime/bootstrap.py +39 -0
  37. axion/runtime/claude_subscription.py +300 -0
  38. axion/runtime/compact.py +233 -0
  39. axion/runtime/config.py +397 -0
  40. axion/runtime/conversation.py +1073 -0
  41. axion/runtime/file_ops.py +613 -0
  42. axion/runtime/git.py +213 -0
  43. axion/runtime/hooks.py +235 -0
  44. axion/runtime/image.py +212 -0
  45. axion/runtime/lanes.py +282 -0
  46. axion/runtime/lsp.py +425 -0
  47. axion/runtime/mcp/__init__.py +0 -0
  48. axion/runtime/mcp/client.py +76 -0
  49. axion/runtime/mcp/lifecycle.py +96 -0
  50. axion/runtime/mcp/stdio.py +318 -0
  51. axion/runtime/mcp/tool_bridge.py +79 -0
  52. axion/runtime/memory.py +196 -0
  53. axion/runtime/oauth.py +329 -0
  54. axion/runtime/openai_subscription.py +346 -0
  55. axion/runtime/permissions.py +247 -0
  56. axion/runtime/plan_mode.py +96 -0
  57. axion/runtime/policy_engine.py +259 -0
  58. axion/runtime/prompt.py +586 -0
  59. axion/runtime/recovery.py +261 -0
  60. axion/runtime/remote.py +28 -0
  61. axion/runtime/sandbox.py +68 -0
  62. axion/runtime/scheduler.py +231 -0
  63. axion/runtime/session.py +365 -0
  64. axion/runtime/sharing.py +159 -0
  65. axion/runtime/skills.py +124 -0
  66. axion/runtime/tasks.py +258 -0
  67. axion/runtime/usage.py +241 -0
  68. axion/runtime/workers.py +186 -0
  69. axion/telemetry/__init__.py +0 -0
  70. axion/telemetry/events.py +67 -0
  71. axion/telemetry/profile.py +49 -0
  72. axion/telemetry/sink.py +60 -0
  73. axion/telemetry/tracer.py +95 -0
  74. axion/tools/__init__.py +0 -0
  75. axion/tools/lane_completion.py +33 -0
  76. axion/tools/registry.py +853 -0
  77. axion/tools/tool_search.py +226 -0
  78. axion_code-1.0.0.dist-info/METADATA +709 -0
  79. axion_code-1.0.0.dist-info/RECORD +82 -0
  80. axion_code-1.0.0.dist-info/WHEEL +4 -0
  81. axion_code-1.0.0.dist-info/entry_points.txt +2 -0
  82. axion_code-1.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,259 @@
1
+ """Git lane policy engine with condition combinators and chained actions.
2
+
3
+ Maps to: rust/crates/runtime/src/policy_engine.rs
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import enum
9
+ from dataclasses import dataclass, field
10
+
11
+ GreenLevel = int # 0-255
12
+
13
+
14
+ # ---------------------------------------------------------------------------
15
+ # Lane context
16
+ # ---------------------------------------------------------------------------
17
+
18
+ class ReviewStatus(enum.Enum):
19
+ PENDING = "pending"
20
+ APPROVED = "approved"
21
+ REJECTED = "rejected"
22
+
23
+
24
+ class DiffScope(enum.Enum):
25
+ FULL = "full"
26
+ SCOPED = "scoped"
27
+
28
+
29
+ class LaneBlocker(enum.Enum):
30
+ NONE = "none"
31
+ STARTUP = "startup"
32
+ EXTERNAL = "external"
33
+
34
+
35
+ @dataclass
36
+ class LaneContext:
37
+ """Context for policy evaluation."""
38
+
39
+ lane_id: str
40
+ green_level: GreenLevel = 0
41
+ branch_freshness_ms: int = 0
42
+ blocker: LaneBlocker = LaneBlocker.NONE
43
+ review_status: ReviewStatus = ReviewStatus.PENDING
44
+ diff_scope: DiffScope = DiffScope.FULL
45
+ completed: bool = False
46
+ reconciled: bool = False
47
+ timed_out: bool = False
48
+ stale_branch: bool = False
49
+
50
+
51
+ # ---------------------------------------------------------------------------
52
+ # Conditions (combinators matching Rust enum)
53
+ # ---------------------------------------------------------------------------
54
+
55
+ class PolicyCondition:
56
+ """Base class for policy conditions."""
57
+
58
+ def evaluate(self, ctx: LaneContext) -> bool:
59
+ raise NotImplementedError
60
+
61
+
62
+ class ConditionAnd(PolicyCondition):
63
+ def __init__(self, conditions: list[PolicyCondition]) -> None:
64
+ self.conditions = conditions
65
+
66
+ def evaluate(self, ctx: LaneContext) -> bool:
67
+ return all(c.evaluate(ctx) for c in self.conditions)
68
+
69
+
70
+ class ConditionOr(PolicyCondition):
71
+ def __init__(self, conditions: list[PolicyCondition]) -> None:
72
+ self.conditions = conditions
73
+
74
+ def evaluate(self, ctx: LaneContext) -> bool:
75
+ return any(c.evaluate(ctx) for c in self.conditions)
76
+
77
+
78
+ class ConditionGreenAt(PolicyCondition):
79
+ def __init__(self, level: GreenLevel) -> None:
80
+ self.level = level
81
+
82
+ def evaluate(self, ctx: LaneContext) -> bool:
83
+ return ctx.green_level >= self.level
84
+
85
+
86
+ class ConditionStaleBranch(PolicyCondition):
87
+ def evaluate(self, ctx: LaneContext) -> bool:
88
+ return ctx.stale_branch
89
+
90
+
91
+ class ConditionStartupBlocked(PolicyCondition):
92
+ def evaluate(self, ctx: LaneContext) -> bool:
93
+ return ctx.blocker == LaneBlocker.STARTUP
94
+
95
+
96
+ class ConditionLaneCompleted(PolicyCondition):
97
+ def evaluate(self, ctx: LaneContext) -> bool:
98
+ return ctx.completed
99
+
100
+
101
+ class ConditionLaneReconciled(PolicyCondition):
102
+ def evaluate(self, ctx: LaneContext) -> bool:
103
+ return ctx.reconciled
104
+
105
+
106
+ class ConditionReviewPassed(PolicyCondition):
107
+ def evaluate(self, ctx: LaneContext) -> bool:
108
+ return ctx.review_status == ReviewStatus.APPROVED
109
+
110
+
111
+ class ConditionScopedDiff(PolicyCondition):
112
+ def evaluate(self, ctx: LaneContext) -> bool:
113
+ return ctx.diff_scope == DiffScope.SCOPED
114
+
115
+
116
+ class ConditionTimedOut(PolicyCondition):
117
+ def __init__(self, duration_ms: int = 0) -> None:
118
+ self.duration_ms = duration_ms
119
+
120
+ def evaluate(self, ctx: LaneContext) -> bool:
121
+ return ctx.timed_out
122
+
123
+
124
+ class ConditionAlways(PolicyCondition):
125
+ def evaluate(self, ctx: LaneContext) -> bool:
126
+ return True
127
+
128
+
129
+ # ---------------------------------------------------------------------------
130
+ # Actions
131
+ # ---------------------------------------------------------------------------
132
+
133
+ class PolicyAction(enum.Enum):
134
+ MERGE_TO_DEV = "merge_to_dev"
135
+ MERGE_FORWARD = "merge_forward"
136
+ RECOVER_ONCE = "recover_once"
137
+ ESCALATE = "escalate"
138
+ CLOSEOUT_LANE = "closeout_lane"
139
+ CLEANUP_SESSION = "cleanup_session"
140
+ RECONCILE = "reconcile"
141
+ NOTIFY = "notify"
142
+ BLOCK = "block"
143
+
144
+
145
+ @dataclass
146
+ class PolicyActionSpec:
147
+ """An action with optional parameters."""
148
+
149
+ action: PolicyAction
150
+ reason: str = ""
151
+ channel: str = "" # For NOTIFY
152
+
153
+
154
+ @dataclass
155
+ class ChainedAction:
156
+ """Multiple actions executed in sequence."""
157
+
158
+ actions: list[PolicyActionSpec] = field(default_factory=list)
159
+
160
+
161
+ # ---------------------------------------------------------------------------
162
+ # Rules
163
+ # ---------------------------------------------------------------------------
164
+
165
+ @dataclass
166
+ class PolicyRule:
167
+ """A condition → action mapping with priority."""
168
+
169
+ name: str
170
+ condition: PolicyCondition
171
+ action: PolicyActionSpec | ChainedAction
172
+ priority: int = 0
173
+ description: str = ""
174
+
175
+
176
+ # ---------------------------------------------------------------------------
177
+ # Policy engine
178
+ # ---------------------------------------------------------------------------
179
+
180
+ class PolicyEngine:
181
+ """Evaluates policy rules against lane context.
182
+
183
+ Maps to: rust/crates/runtime/src/policy_engine.rs::PolicyEngine
184
+ Supports condition combinators (And/Or), chained actions, and priority ordering.
185
+ """
186
+
187
+ def __init__(self, rules: list[PolicyRule] | None = None) -> None:
188
+ self._rules = sorted(rules or [], key=lambda r: r.priority, reverse=True)
189
+
190
+ def add_rule(self, rule: PolicyRule) -> None:
191
+ self._rules.append(rule)
192
+ self._rules.sort(key=lambda r: r.priority, reverse=True)
193
+
194
+ def evaluate(self, context: LaneContext) -> list[PolicyActionSpec]:
195
+ """Evaluate all rules and return applicable actions."""
196
+ actions: list[PolicyActionSpec] = []
197
+
198
+ for rule in self._rules:
199
+ if rule.condition.evaluate(context):
200
+ if isinstance(rule.action, ChainedAction):
201
+ actions.extend(rule.action.actions)
202
+ else:
203
+ actions.append(rule.action)
204
+
205
+ return actions
206
+
207
+ def evaluate_first(self, context: LaneContext) -> PolicyActionSpec | None:
208
+ """Return the first matching action (highest priority)."""
209
+ for rule in self._rules:
210
+ if rule.condition.evaluate(context):
211
+ if isinstance(rule.action, ChainedAction):
212
+ return rule.action.actions[0] if rule.action.actions else None
213
+ return rule.action
214
+ return None
215
+
216
+ @classmethod
217
+ def default_rules(cls) -> PolicyEngine:
218
+ """Create engine with default git lane policies."""
219
+ return cls(rules=[
220
+ PolicyRule(
221
+ name="merge_approved",
222
+ condition=ConditionAnd([ConditionLaneCompleted(), ConditionReviewPassed()]),
223
+ action=PolicyActionSpec(action=PolicyAction.MERGE_TO_DEV),
224
+ priority=100,
225
+ description="Merge completed & approved lanes to dev",
226
+ ),
227
+ PolicyRule(
228
+ name="block_startup",
229
+ condition=ConditionStartupBlocked(),
230
+ action=PolicyActionSpec(action=PolicyAction.BLOCK, reason="Startup blocker active"),
231
+ priority=90,
232
+ ),
233
+ PolicyRule(
234
+ name="escalate_external",
235
+ condition=ConditionAnd([
236
+ ConditionOr([ConditionStaleBranch(), ConditionTimedOut()]),
237
+ ]),
238
+ action=PolicyActionSpec(
239
+ action=PolicyAction.ESCALATE,
240
+ reason="Branch stale or timed out",
241
+ ),
242
+ priority=80,
243
+ ),
244
+ PolicyRule(
245
+ name="closeout_reconciled",
246
+ condition=ConditionAnd([ConditionLaneCompleted(), ConditionLaneReconciled()]),
247
+ action=ChainedAction(actions=[
248
+ PolicyActionSpec(action=PolicyAction.CLOSEOUT_LANE),
249
+ PolicyActionSpec(action=PolicyAction.CLEANUP_SESSION),
250
+ ]),
251
+ priority=70,
252
+ ),
253
+ PolicyRule(
254
+ name="recover_stale",
255
+ condition=ConditionStaleBranch(),
256
+ action=PolicyActionSpec(action=PolicyAction.RECOVER_ONCE, reason="Branch is stale"),
257
+ priority=50,
258
+ ),
259
+ ])