codetalker-mcp 0.3.1__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.
- codetalker/__init__.py +5 -0
- codetalker/adapter_base.py +432 -0
- codetalker/adapters/__init__.py +76 -0
- codetalker/adapters/aider.py +228 -0
- codetalker/adapters/antigravity.py +491 -0
- codetalker/adapters/chatgpt.py +934 -0
- codetalker/adapters/claude.py +320 -0
- codetalker/adapters/copilot.py +338 -0
- codetalker/adapters/cursor.py +464 -0
- codetalker/adapters/freebuff.py +275 -0
- codetalker/adapters/opencode.py +520 -0
- codetalker/adapters/opencode_sidecar.py +362 -0
- codetalker/adapters/windsurf.py +528 -0
- codetalker/agent_guidance.py +213 -0
- codetalker/audit.py +181 -0
- codetalker/continuity.py +269 -0
- codetalker/install_harnesses.py +251 -0
- codetalker/registry.py +69 -0
- codetalker/schema.py +269 -0
- codetalker/search.py +391 -0
- codetalker/server.py +1334 -0
- codetalker/utils/__init__.py +3 -0
- codetalker/utils/display.py +15 -0
- codetalker/utils/paths.py +48 -0
- codetalker/utils/sanitize.py +13 -0
- codetalker/utils/timestamps.py +101 -0
- codetalker/utils/tool_errors.py +45 -0
- codetalker_mcp-0.3.1.dist-info/METADATA +310 -0
- codetalker_mcp-0.3.1.dist-info/RECORD +32 -0
- codetalker_mcp-0.3.1.dist-info/WHEEL +4 -0
- codetalker_mcp-0.3.1.dist-info/entry_points.txt +4 -0
- codetalker_mcp-0.3.1.dist-info/licenses/LICENSE +21 -0
codetalker/__init__.py
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import Sequence
|
|
5
|
+
|
|
6
|
+
from codetalker.schema import (
|
|
7
|
+
ActorRole,
|
|
8
|
+
BlockType,
|
|
9
|
+
BranchDiff,
|
|
10
|
+
BranchSummary,
|
|
11
|
+
ConversationBranchTree,
|
|
12
|
+
ForkPoint,
|
|
13
|
+
NormalizedSession,
|
|
14
|
+
NormalizedStep,
|
|
15
|
+
StepPagination,
|
|
16
|
+
TextBlock,
|
|
17
|
+
ThinkingBlock,
|
|
18
|
+
ToolResultBlock,
|
|
19
|
+
)
|
|
20
|
+
from codetalker.utils.timestamps import timestamp_gte, timestamp_lte
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class BaseAdapter(ABC):
|
|
24
|
+
"""Abstract base class for all harness adapters."""
|
|
25
|
+
|
|
26
|
+
harness_name: str
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def discover_sessions(
|
|
30
|
+
self,
|
|
31
|
+
root_path: str | None = None,
|
|
32
|
+
) -> list[NormalizedSession]:
|
|
33
|
+
"""Discover and return session shells (metadata only, without full steps)."""
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def load_steps(
|
|
38
|
+
self,
|
|
39
|
+
session: NormalizedSession,
|
|
40
|
+
since: str | None = None,
|
|
41
|
+
until: str | None = None,
|
|
42
|
+
since_last_user_input: bool = False,
|
|
43
|
+
include_step_types: list[BlockType] | None = None,
|
|
44
|
+
include_actor_roles: list[ActorRole] | None = None,
|
|
45
|
+
exclude_actor_roles: list[ActorRole] | None = None,
|
|
46
|
+
include_thinking: bool = True,
|
|
47
|
+
include_raw_data: bool = False,
|
|
48
|
+
max_step_chars: int | None = None,
|
|
49
|
+
offset: int = 0,
|
|
50
|
+
from_end: bool = False,
|
|
51
|
+
limit: int | None = None,
|
|
52
|
+
) -> list[NormalizedStep]:
|
|
53
|
+
"""Load and normalize steps for a given session with filtering applied."""
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
def count_steps(self, session: NormalizedSession) -> int:
|
|
57
|
+
"""Return total step count for a session (may use a cheap peek when available)."""
|
|
58
|
+
return len(
|
|
59
|
+
self.load_steps(
|
|
60
|
+
session=session,
|
|
61
|
+
include_raw_data=False,
|
|
62
|
+
include_thinking=True,
|
|
63
|
+
)
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
def load_steps_paginated(
|
|
67
|
+
self,
|
|
68
|
+
session: NormalizedSession,
|
|
69
|
+
since: str | None = None,
|
|
70
|
+
until: str | None = None,
|
|
71
|
+
since_last_user_input: bool = False,
|
|
72
|
+
include_step_types: list[BlockType] | None = None,
|
|
73
|
+
include_actor_roles: list[ActorRole] | None = None,
|
|
74
|
+
exclude_actor_roles: list[ActorRole] | None = None,
|
|
75
|
+
include_thinking: bool = True,
|
|
76
|
+
include_raw_data: bool = False,
|
|
77
|
+
max_step_chars: int | None = None,
|
|
78
|
+
offset: int = 0,
|
|
79
|
+
from_end: bool = False,
|
|
80
|
+
limit: int | None = None,
|
|
81
|
+
) -> tuple[list[NormalizedStep], StepPagination]:
|
|
82
|
+
"""Load steps and return pagination metadata for the applied slice."""
|
|
83
|
+
all_steps = self.load_steps(
|
|
84
|
+
session=session,
|
|
85
|
+
since=since,
|
|
86
|
+
until=until,
|
|
87
|
+
since_last_user_input=since_last_user_input,
|
|
88
|
+
include_step_types=include_step_types,
|
|
89
|
+
include_actor_roles=include_actor_roles,
|
|
90
|
+
exclude_actor_roles=exclude_actor_roles,
|
|
91
|
+
include_thinking=include_thinking,
|
|
92
|
+
include_raw_data=include_raw_data,
|
|
93
|
+
max_step_chars=max_step_chars,
|
|
94
|
+
offset=0,
|
|
95
|
+
from_end=False,
|
|
96
|
+
limit=None,
|
|
97
|
+
)
|
|
98
|
+
return self.paginate_steps(
|
|
99
|
+
all_steps, offset=offset, from_end=from_end, limit=limit
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def paginate_steps(
|
|
104
|
+
steps: Sequence[NormalizedStep],
|
|
105
|
+
offset: int = 0,
|
|
106
|
+
from_end: bool = False,
|
|
107
|
+
limit: int | None = None,
|
|
108
|
+
) -> tuple[list[NormalizedStep], StepPagination]:
|
|
109
|
+
total = len(steps)
|
|
110
|
+
offset = max(0, offset)
|
|
111
|
+
if total == 0:
|
|
112
|
+
return [], StepPagination(
|
|
113
|
+
offset=offset,
|
|
114
|
+
limit=limit,
|
|
115
|
+
from_end=from_end,
|
|
116
|
+
returned_step_count=0,
|
|
117
|
+
total_steps_available=0,
|
|
118
|
+
has_more_before=False,
|
|
119
|
+
has_more_after=False,
|
|
120
|
+
next_offset=None,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
if from_end:
|
|
124
|
+
end_exclusive = max(0, total - offset)
|
|
125
|
+
if limit is not None and limit > 0:
|
|
126
|
+
start = max(0, end_exclusive - limit)
|
|
127
|
+
else:
|
|
128
|
+
start = 0
|
|
129
|
+
sliced = list(steps[start:end_exclusive])
|
|
130
|
+
has_more_before = start > 0
|
|
131
|
+
has_more_after = offset > 0
|
|
132
|
+
next_offset = offset + len(sliced) if has_more_before and sliced else None
|
|
133
|
+
start_idx = sliced[0].step_index if sliced else None
|
|
134
|
+
end_idx = sliced[-1].step_index if sliced else None
|
|
135
|
+
else:
|
|
136
|
+
start = min(offset, total)
|
|
137
|
+
if limit is not None and limit > 0:
|
|
138
|
+
sliced = list(steps[start : start + limit])
|
|
139
|
+
else:
|
|
140
|
+
sliced = list(steps[start:])
|
|
141
|
+
end_exclusive = start + len(sliced)
|
|
142
|
+
has_more_before = start > 0
|
|
143
|
+
has_more_after = end_exclusive < total
|
|
144
|
+
next_offset = end_exclusive if has_more_after else None
|
|
145
|
+
start_idx = sliced[0].step_index if sliced else None
|
|
146
|
+
end_idx = sliced[-1].step_index if sliced else None
|
|
147
|
+
|
|
148
|
+
return sliced, StepPagination(
|
|
149
|
+
offset=offset,
|
|
150
|
+
limit=limit,
|
|
151
|
+
from_end=from_end,
|
|
152
|
+
returned_step_count=len(sliced),
|
|
153
|
+
total_steps_available=total,
|
|
154
|
+
has_more_before=has_more_before,
|
|
155
|
+
has_more_after=has_more_after,
|
|
156
|
+
next_offset=next_offset,
|
|
157
|
+
start_step_index=start_idx,
|
|
158
|
+
end_step_index=end_idx,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
def get_branch_tree(
|
|
162
|
+
self,
|
|
163
|
+
conversation_id: str,
|
|
164
|
+
root_path: str | None = None,
|
|
165
|
+
) -> ConversationBranchTree | None:
|
|
166
|
+
"""Construct the branch/DAG tree for a given conversation ID."""
|
|
167
|
+
sessions = self.discover_sessions(root_path=root_path)
|
|
168
|
+
matching_branches = [
|
|
169
|
+
s
|
|
170
|
+
for s in sessions
|
|
171
|
+
if s.conversation_id == conversation_id or s.session_id == conversation_id
|
|
172
|
+
]
|
|
173
|
+
if not matching_branches:
|
|
174
|
+
return None
|
|
175
|
+
|
|
176
|
+
active_branch = next(
|
|
177
|
+
(s for s in matching_branches if s.branch_root_step_id is None),
|
|
178
|
+
matching_branches[0],
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
display_name = active_branch.display_name or f"{self.harness_name} {conversation_id[:8]}"
|
|
182
|
+
branches_summary: list[BranchSummary] = []
|
|
183
|
+
fork_map: dict[str, list[str]] = {}
|
|
184
|
+
child_subagents: list[str] = []
|
|
185
|
+
|
|
186
|
+
for s in matching_branches:
|
|
187
|
+
is_active = s.session_id == active_branch.session_id
|
|
188
|
+
branches_summary.append(
|
|
189
|
+
BranchSummary(
|
|
190
|
+
branch_id=s.session_id,
|
|
191
|
+
branch_label=s.branch_label or ("Main Thread" if is_active else "Branch"),
|
|
192
|
+
divergence_step_id=s.branch_root_step_id,
|
|
193
|
+
leaf_step_id=s.active_node_id or s.session_id,
|
|
194
|
+
step_count=s.step_count,
|
|
195
|
+
user_turn_count=s.user_turn_count,
|
|
196
|
+
assistant_turn_count=s.assistant_turn_count,
|
|
197
|
+
model=s.model,
|
|
198
|
+
is_active_path=is_active,
|
|
199
|
+
started_at=s.started_at,
|
|
200
|
+
last_activity=s.last_activity,
|
|
201
|
+
)
|
|
202
|
+
)
|
|
203
|
+
if s.branch_root_step_id:
|
|
204
|
+
fork_map.setdefault(s.branch_root_step_id, []).append(s.session_id)
|
|
205
|
+
if s.child_session_ids:
|
|
206
|
+
child_subagents.extend(s.child_session_ids)
|
|
207
|
+
|
|
208
|
+
fork_points: list[ForkPoint] = []
|
|
209
|
+
for step_id, b_ids in fork_map.items():
|
|
210
|
+
fork_points.append(
|
|
211
|
+
ForkPoint(
|
|
212
|
+
step_id=step_id,
|
|
213
|
+
variant_count=len(b_ids) + 1,
|
|
214
|
+
branch_ids=b_ids,
|
|
215
|
+
)
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
return ConversationBranchTree(
|
|
219
|
+
conversation_id=conversation_id,
|
|
220
|
+
harness=self.harness_name,
|
|
221
|
+
display_name=display_name,
|
|
222
|
+
active_branch_id=active_branch.session_id,
|
|
223
|
+
branch_count=len(matching_branches),
|
|
224
|
+
branches=branches_summary,
|
|
225
|
+
fork_points=fork_points,
|
|
226
|
+
child_subagent_sessions=list(set(child_subagents)),
|
|
227
|
+
has_dag=len(matching_branches) > 1 or any(s.has_dag for s in matching_branches),
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
def diff_branches(
|
|
231
|
+
self,
|
|
232
|
+
conversation_id: str,
|
|
233
|
+
branch_a: str,
|
|
234
|
+
branch_b: str,
|
|
235
|
+
root_path: str | None = None,
|
|
236
|
+
summary_only: bool = True,
|
|
237
|
+
include_raw_data: bool = False,
|
|
238
|
+
limit_per_branch: int = 20,
|
|
239
|
+
from_end: bool = True,
|
|
240
|
+
) -> BranchDiff | None:
|
|
241
|
+
"""Compute step divergence between two branches of a conversation."""
|
|
242
|
+
sessions = self.discover_sessions(root_path=root_path)
|
|
243
|
+
matching_map = {
|
|
244
|
+
s.session_id: s
|
|
245
|
+
for s in sessions
|
|
246
|
+
if s.conversation_id == conversation_id or s.session_id == conversation_id
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
sess_a = matching_map.get(branch_a)
|
|
250
|
+
sess_b = matching_map.get(branch_b)
|
|
251
|
+
|
|
252
|
+
if not sess_a:
|
|
253
|
+
sess_a = next((s for s in sessions if s.session_id == branch_a), None)
|
|
254
|
+
if not sess_b:
|
|
255
|
+
sess_b = next((s for s in sessions if s.session_id == branch_b), None)
|
|
256
|
+
|
|
257
|
+
if not sess_a or not sess_b:
|
|
258
|
+
return None
|
|
259
|
+
|
|
260
|
+
steps_a = self.load_steps(sess_a, include_raw_data=include_raw_data)
|
|
261
|
+
steps_b = self.load_steps(sess_b, include_raw_data=include_raw_data)
|
|
262
|
+
|
|
263
|
+
common_len = 0
|
|
264
|
+
min_len = min(len(steps_a), len(steps_b))
|
|
265
|
+
|
|
266
|
+
for i in range(min_len):
|
|
267
|
+
sa = steps_a[i]
|
|
268
|
+
sb = steps_b[i]
|
|
269
|
+
if sa.branch and sb.branch and sa.branch.step_id == sb.branch.step_id:
|
|
270
|
+
common_len += 1
|
|
271
|
+
elif (
|
|
272
|
+
sa.actor.role == sb.actor.role
|
|
273
|
+
and len(sa.blocks) == len(sb.blocks)
|
|
274
|
+
and sa.model_dump(exclude={"timestamp", "branch", "raw_data"})
|
|
275
|
+
== sb.model_dump(exclude={"timestamp", "branch", "raw_data"})
|
|
276
|
+
):
|
|
277
|
+
common_len += 1
|
|
278
|
+
else:
|
|
279
|
+
break
|
|
280
|
+
|
|
281
|
+
common_steps = steps_a[:common_len]
|
|
282
|
+
distinct_a = steps_a[common_len:]
|
|
283
|
+
distinct_b = steps_b[common_len:]
|
|
284
|
+
|
|
285
|
+
last_common = common_steps[-1] if common_steps else None
|
|
286
|
+
divergence_step_id = last_common.branch.step_id if last_common and last_common.branch else None
|
|
287
|
+
divergence_index = common_len - 1 if common_len > 0 else None
|
|
288
|
+
|
|
289
|
+
if summary_only:
|
|
290
|
+
common_steps = []
|
|
291
|
+
if from_end and limit_per_branch > 0:
|
|
292
|
+
distinct_a = distinct_a[-limit_per_branch:]
|
|
293
|
+
distinct_b = distinct_b[-limit_per_branch:]
|
|
294
|
+
elif limit_per_branch > 0:
|
|
295
|
+
distinct_a = distinct_a[:limit_per_branch]
|
|
296
|
+
distinct_b = distinct_b[:limit_per_branch]
|
|
297
|
+
else:
|
|
298
|
+
if from_end and limit_per_branch > 0:
|
|
299
|
+
distinct_a = distinct_a[-limit_per_branch:]
|
|
300
|
+
distinct_b = distinct_b[-limit_per_branch:]
|
|
301
|
+
elif limit_per_branch > 0:
|
|
302
|
+
distinct_a = distinct_a[:limit_per_branch]
|
|
303
|
+
distinct_b = distinct_b[:limit_per_branch]
|
|
304
|
+
|
|
305
|
+
return BranchDiff(
|
|
306
|
+
conversation_id=conversation_id,
|
|
307
|
+
harness=self.harness_name,
|
|
308
|
+
branch_a_id=branch_a,
|
|
309
|
+
branch_b_id=branch_b,
|
|
310
|
+
divergence_step_id=divergence_step_id,
|
|
311
|
+
divergence_step_index=divergence_index,
|
|
312
|
+
common_step_count=common_len,
|
|
313
|
+
branch_a_distinct_step_count=len(steps_a) - common_len,
|
|
314
|
+
branch_b_distinct_step_count=len(steps_b) - common_len,
|
|
315
|
+
common_steps=common_steps,
|
|
316
|
+
branch_a_distinct_steps=distinct_a,
|
|
317
|
+
branch_b_distinct_steps=distinct_b,
|
|
318
|
+
summary_only=summary_only,
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
@staticmethod
|
|
322
|
+
def _truncate_block_text(text: str, max_chars: int) -> tuple[str, bool]:
|
|
323
|
+
if len(text) <= max_chars:
|
|
324
|
+
return text, False
|
|
325
|
+
if max_chars <= 1:
|
|
326
|
+
return "…", True
|
|
327
|
+
return text[: max_chars - 1] + "…", True
|
|
328
|
+
|
|
329
|
+
@staticmethod
|
|
330
|
+
def filter_normalized_steps(
|
|
331
|
+
steps: Sequence[NormalizedStep],
|
|
332
|
+
since: str | None = None,
|
|
333
|
+
until: str | None = None,
|
|
334
|
+
since_last_user_input: bool = False,
|
|
335
|
+
include_step_types: list[BlockType] | None = None,
|
|
336
|
+
include_actor_roles: list[ActorRole] | None = None,
|
|
337
|
+
exclude_actor_roles: list[ActorRole] | None = None,
|
|
338
|
+
include_thinking: bool = True,
|
|
339
|
+
include_raw_data: bool = False,
|
|
340
|
+
max_step_chars: int | None = None,
|
|
341
|
+
offset: int = 0,
|
|
342
|
+
from_end: bool = False,
|
|
343
|
+
limit: int | None = None,
|
|
344
|
+
) -> list[NormalizedStep]:
|
|
345
|
+
"""Standard filter implementation for a list of normalized steps."""
|
|
346
|
+
filtered: list[NormalizedStep] = list(steps)
|
|
347
|
+
|
|
348
|
+
if since_last_user_input:
|
|
349
|
+
last_user_idx = -1
|
|
350
|
+
for idx, step in enumerate(filtered):
|
|
351
|
+
if step.actor.role == ActorRole.USER:
|
|
352
|
+
last_user_idx = idx
|
|
353
|
+
if last_user_idx != -1:
|
|
354
|
+
filtered = filtered[last_user_idx:]
|
|
355
|
+
|
|
356
|
+
if since is not None:
|
|
357
|
+
filtered = [
|
|
358
|
+
s for s in filtered if s.timestamp is None or timestamp_gte(s.timestamp, since)
|
|
359
|
+
]
|
|
360
|
+
if until is not None:
|
|
361
|
+
filtered = [
|
|
362
|
+
s for s in filtered if s.timestamp is None or timestamp_lte(s.timestamp, until)
|
|
363
|
+
]
|
|
364
|
+
|
|
365
|
+
if include_actor_roles is not None:
|
|
366
|
+
role_set = set(include_actor_roles)
|
|
367
|
+
filtered = [s for s in filtered if s.actor.role in role_set]
|
|
368
|
+
|
|
369
|
+
if exclude_actor_roles is not None:
|
|
370
|
+
excluded = set(exclude_actor_roles)
|
|
371
|
+
filtered = [s for s in filtered if s.actor.role not in excluded]
|
|
372
|
+
|
|
373
|
+
result: list[NormalizedStep] = []
|
|
374
|
+
for step in filtered:
|
|
375
|
+
step_blocks = list(step.blocks)
|
|
376
|
+
|
|
377
|
+
if not include_thinking:
|
|
378
|
+
step_blocks = [b for b in step_blocks if b.type != BlockType.THINKING]
|
|
379
|
+
|
|
380
|
+
if include_step_types is not None:
|
|
381
|
+
type_set = set(include_step_types)
|
|
382
|
+
step_blocks = [b for b in step_blocks if b.type in type_set]
|
|
383
|
+
|
|
384
|
+
if max_step_chars is not None and max_step_chars > 0:
|
|
385
|
+
clipped_blocks = []
|
|
386
|
+
for block in step_blocks:
|
|
387
|
+
if isinstance(block, (TextBlock, ThinkingBlock)):
|
|
388
|
+
new_text, truncated = BaseAdapter._truncate_block_text(
|
|
389
|
+
block.text, max_step_chars
|
|
390
|
+
)
|
|
391
|
+
clipped_blocks.append(
|
|
392
|
+
block.model_copy(
|
|
393
|
+
update={"text": new_text, "is_truncated": truncated or block.is_truncated}
|
|
394
|
+
)
|
|
395
|
+
)
|
|
396
|
+
elif isinstance(block, ToolResultBlock):
|
|
397
|
+
new_content, truncated = BaseAdapter._truncate_block_text(
|
|
398
|
+
block.content, max_step_chars
|
|
399
|
+
)
|
|
400
|
+
clipped_blocks.append(
|
|
401
|
+
block.model_copy(
|
|
402
|
+
update={
|
|
403
|
+
"content": new_content,
|
|
404
|
+
"is_truncated": truncated or block.is_truncated,
|
|
405
|
+
}
|
|
406
|
+
)
|
|
407
|
+
)
|
|
408
|
+
else:
|
|
409
|
+
clipped_blocks.append(block)
|
|
410
|
+
step_blocks = clipped_blocks
|
|
411
|
+
|
|
412
|
+
if step.blocks and not step_blocks:
|
|
413
|
+
continue
|
|
414
|
+
|
|
415
|
+
has_sig = any(
|
|
416
|
+
isinstance(b, ThinkingBlock) and b.has_signature for b in step_blocks
|
|
417
|
+
)
|
|
418
|
+
raw = step.raw_data if (include_raw_data or has_sig) else {}
|
|
419
|
+
|
|
420
|
+
result.append(
|
|
421
|
+
step.model_copy(
|
|
422
|
+
update={
|
|
423
|
+
"blocks": step_blocks,
|
|
424
|
+
"raw_data": raw,
|
|
425
|
+
}
|
|
426
|
+
)
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
sliced, _ = BaseAdapter.paginate_steps(
|
|
430
|
+
result, offset=offset, from_end=from_end, limit=limit
|
|
431
|
+
)
|
|
432
|
+
return sliced
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from codetalker.adapters.aider import AiderAdapter
|
|
2
|
+
from codetalker.adapters.antigravity import AntigravityAdapter
|
|
3
|
+
from codetalker.adapters.chatgpt import ChatGPTAdapter
|
|
4
|
+
from codetalker.adapters.claude import ClaudeCodeAdapter
|
|
5
|
+
from codetalker.adapters.copilot import GitHubCopilotAdapter
|
|
6
|
+
from codetalker.adapters.cursor import CursorAdapter
|
|
7
|
+
from codetalker.adapters.freebuff import FreebuffAdapter
|
|
8
|
+
from codetalker.adapters.opencode import OpenCodeAdapter
|
|
9
|
+
from codetalker.adapters.windsurf import WindsurfAdapter
|
|
10
|
+
from codetalker.registry import registry
|
|
11
|
+
|
|
12
|
+
# 1. ChatGPT / Codex adapter
|
|
13
|
+
registry.register(
|
|
14
|
+
ChatGPTAdapter(),
|
|
15
|
+
aliases=["codex", "chatgpt_desktop", "chatgpt.exe", "openai", "openai_codex", "codex_cli", "chat_gpt"],
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# 2. Devin / Windsurf adapter
|
|
19
|
+
registry.register(
|
|
20
|
+
WindsurfAdapter(),
|
|
21
|
+
aliases=["devin", "codeium", "windsurf_ide", "windsurf-ide", "windsurf"],
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# 3. Antigravity adapter
|
|
25
|
+
registry.register(
|
|
26
|
+
AntigravityAdapter(),
|
|
27
|
+
aliases=["agy", "gemini", "google_antigravity", "antigravity_ide", "antigravity-ide", "google-antigravity", "google_antigravity_ide"],
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# 4. Cursor adapter
|
|
31
|
+
registry.register(
|
|
32
|
+
CursorAdapter(),
|
|
33
|
+
aliases=["cursor_ide", "cursor-ide", "anysphere"],
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# 5. Claude Code adapter
|
|
37
|
+
registry.register(
|
|
38
|
+
ClaudeCodeAdapter(),
|
|
39
|
+
aliases=["claudecode", "claude_code", "claude-code", "anthropic", "claude"],
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# 6. Aider adapter
|
|
43
|
+
registry.register(
|
|
44
|
+
AiderAdapter(),
|
|
45
|
+
aliases=["aider_chat", "aider-chat"],
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# 7. GitHub Copilot adapter
|
|
49
|
+
registry.register(
|
|
50
|
+
GitHubCopilotAdapter(),
|
|
51
|
+
aliases=["github_copilot", "copilot_chat", "vscode_copilot", "github-copilot"],
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# 8. Freebuff / Codebuff adapter
|
|
55
|
+
registry.register(
|
|
56
|
+
FreebuffAdapter(),
|
|
57
|
+
aliases=["codebuff", "freebuff_desktop", "freebuff-desktop", "free_buff"],
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# 9. OpenCode adapter
|
|
61
|
+
registry.register(
|
|
62
|
+
OpenCodeAdapter(),
|
|
63
|
+
aliases=["open_code", "opencode_desktop", "opencode-ai", "open-code"],
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
__all__ = [
|
|
67
|
+
"ChatGPTAdapter",
|
|
68
|
+
"WindsurfAdapter",
|
|
69
|
+
"AntigravityAdapter",
|
|
70
|
+
"CursorAdapter",
|
|
71
|
+
"ClaudeCodeAdapter",
|
|
72
|
+
"AiderAdapter",
|
|
73
|
+
"GitHubCopilotAdapter",
|
|
74
|
+
"FreebuffAdapter",
|
|
75
|
+
"OpenCodeAdapter",
|
|
76
|
+
]
|