indent 0.0.8__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.

Potentially problematic release.


This version of indent might be problematic. Click here for more details.

Files changed (56) hide show
  1. exponent/__init__.py +1 -0
  2. exponent/cli.py +112 -0
  3. exponent/commands/cloud_commands.py +85 -0
  4. exponent/commands/common.py +434 -0
  5. exponent/commands/config_commands.py +581 -0
  6. exponent/commands/github_app_commands.py +211 -0
  7. exponent/commands/listen_commands.py +96 -0
  8. exponent/commands/run_commands.py +208 -0
  9. exponent/commands/settings.py +56 -0
  10. exponent/commands/shell_commands.py +2840 -0
  11. exponent/commands/theme.py +246 -0
  12. exponent/commands/types.py +111 -0
  13. exponent/commands/upgrade.py +29 -0
  14. exponent/commands/utils.py +236 -0
  15. exponent/core/config.py +180 -0
  16. exponent/core/graphql/__init__.py +0 -0
  17. exponent/core/graphql/client.py +59 -0
  18. exponent/core/graphql/cloud_config_queries.py +77 -0
  19. exponent/core/graphql/get_chats_query.py +47 -0
  20. exponent/core/graphql/github_config_queries.py +56 -0
  21. exponent/core/graphql/mutations.py +75 -0
  22. exponent/core/graphql/queries.py +110 -0
  23. exponent/core/graphql/subscriptions.py +452 -0
  24. exponent/core/remote_execution/checkpoints.py +212 -0
  25. exponent/core/remote_execution/cli_rpc_types.py +214 -0
  26. exponent/core/remote_execution/client.py +545 -0
  27. exponent/core/remote_execution/code_execution.py +58 -0
  28. exponent/core/remote_execution/command_execution.py +105 -0
  29. exponent/core/remote_execution/error_info.py +45 -0
  30. exponent/core/remote_execution/exceptions.py +10 -0
  31. exponent/core/remote_execution/file_write.py +410 -0
  32. exponent/core/remote_execution/files.py +415 -0
  33. exponent/core/remote_execution/git.py +268 -0
  34. exponent/core/remote_execution/languages/python_execution.py +239 -0
  35. exponent/core/remote_execution/languages/shell_streaming.py +221 -0
  36. exponent/core/remote_execution/languages/types.py +20 -0
  37. exponent/core/remote_execution/session.py +128 -0
  38. exponent/core/remote_execution/system_context.py +54 -0
  39. exponent/core/remote_execution/tool_execution.py +289 -0
  40. exponent/core/remote_execution/truncation.py +284 -0
  41. exponent/core/remote_execution/types.py +670 -0
  42. exponent/core/remote_execution/utils.py +600 -0
  43. exponent/core/types/__init__.py +0 -0
  44. exponent/core/types/command_data.py +206 -0
  45. exponent/core/types/event_types.py +89 -0
  46. exponent/core/types/generated/__init__.py +0 -0
  47. exponent/core/types/generated/strategy_info.py +225 -0
  48. exponent/migration-docs/login.md +112 -0
  49. exponent/py.typed +4 -0
  50. exponent/utils/__init__.py +0 -0
  51. exponent/utils/colors.py +92 -0
  52. exponent/utils/version.py +289 -0
  53. indent-0.0.8.dist-info/METADATA +36 -0
  54. indent-0.0.8.dist-info/RECORD +56 -0
  55. indent-0.0.8.dist-info/WHEEL +4 -0
  56. indent-0.0.8.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,452 @@
1
+ AUTHENTICATED_USER_SUBSCRIPTION = """
2
+ subscription {
3
+ testAuthenticatedUser {
4
+ __typename
5
+ ... on UnauthenticatedError {
6
+ message
7
+ }
8
+ ...on Error {
9
+ message
10
+ }
11
+ ... on User {
12
+ userUuid
13
+ }
14
+ }
15
+ }
16
+ """
17
+
18
+ INDENT_EVENTS_SUBSCRIPTION = """
19
+ subscription ChatEvents(
20
+ $prompt: Prompt
21
+ $chatUuid: String!
22
+ $parentUuid: String
23
+ $model: ModelName!
24
+ $strategyNameOverride: StrategyName
25
+ $depthLimit: Int!
26
+ $requireConfirmation: Boolean
27
+ $readOnly: Boolean
28
+ $enableThinking: Boolean
29
+ ) {
30
+ indentChat(
31
+ chatInput: {
32
+ prompt: $prompt
33
+ }
34
+ parentUuid: $parentUuid
35
+ chatConfig: {
36
+ chatUuid: $chatUuid
37
+ model: $model
38
+ requireConfirmation: $requireConfirmation
39
+ readOnly: $readOnly
40
+ strategyNameOverride: $strategyNameOverride
41
+ depthLimit: $depthLimit
42
+ enableThinking: $enableThinking
43
+ }
44
+ ) {
45
+ __typename
46
+ ...on Error {
47
+ message
48
+ }
49
+ ...on UnauthenticatedError {
50
+ message
51
+ }
52
+ ...on UserEvent {
53
+ uuid
54
+ parentUuid
55
+ chatId
56
+ isSidechain
57
+ version
58
+ createdAt
59
+ sidechainRootUuid
60
+ synthetic
61
+ messageData: message {
62
+ __typename
63
+ ... on TextMessage {
64
+ text
65
+ }
66
+ ... on ToolResultMessage {
67
+ messageId
68
+ toolUseId
69
+ text
70
+ resultData {
71
+ ... on BashToolResult {
72
+ shellOutput
73
+ exitCode
74
+ }
75
+ ... on ReadToolResult {
76
+ content
77
+ }
78
+ }
79
+ }
80
+ ... on PartialToolResultMessage {
81
+ messageId
82
+ toolUseId
83
+ text
84
+ resultData {
85
+ ... on PartialToolResult {
86
+ __typename
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ ...on AssistantEvent {
93
+ uuid
94
+ parentUuid
95
+ chatId
96
+ isSidechain
97
+ version
98
+ createdAt
99
+ sidechainRootUuid
100
+ synthetic
101
+ messageData: message {
102
+ __typename
103
+ ... on TextMessage {
104
+ text
105
+ }
106
+ ... on ToolCallMessage {
107
+ messageId
108
+ toolUseId
109
+ toolName
110
+ toolInput {
111
+ ... on BashToolInput {
112
+ command
113
+ }
114
+ ... on ReadToolInput {
115
+ filePath
116
+ }
117
+ }
118
+ }
119
+ }
120
+ }
121
+ ...on SystemEvent {
122
+ uuid
123
+ parentUuid
124
+ chatId
125
+ isSidechain
126
+ version
127
+ createdAt
128
+ sidechainRootUuid
129
+ messageData: message {
130
+ __typename
131
+ ... on ToolCallMessage {
132
+ messageId
133
+ toolUseId
134
+ toolName
135
+ toolInput {
136
+ ... on BashToolInput {
137
+ command
138
+ }
139
+ ... on ReadToolInput {
140
+ filePath
141
+ }
142
+ }
143
+ }
144
+ ... on ToolResultMessage {
145
+ messageId
146
+ toolUseId
147
+ text
148
+ resultData {
149
+ ... on BashToolResult {
150
+ shellOutput
151
+ exitCode
152
+ }
153
+ ... on ReadToolResult {
154
+ content
155
+ }
156
+ }
157
+ }
158
+ ... on ToolExecutionStatusMessage {
159
+ executionStatus: status
160
+ }
161
+ ... on ToolPermissionStatusMessage {
162
+ permissionStatus: status
163
+ }
164
+ }
165
+ }
166
+ }
167
+ }
168
+ """
169
+
170
+
171
+ CONFIRM_AND_CONTINUE_SUBSCRIPTION = """
172
+ subscription ChatEvents(
173
+ $requestUuid: String!
174
+ $chatUuid: String!
175
+ $model: ModelName!
176
+ $strategyNameOverride: StrategyName
177
+ $depthLimit: Int!
178
+ $requireConfirmation: Boolean
179
+ $readOnly: Boolean
180
+ $enableThinking: Boolean
181
+ ) {
182
+ confirmAndContinue(
183
+ requestEventUuid: $requestUuid
184
+ chatConfig: {
185
+ chatUuid: $chatUuid
186
+ model: $model
187
+ requireConfirmation: $requireConfirmation
188
+ readOnly: $readOnly
189
+ strategyNameOverride: $strategyNameOverride
190
+ depthLimit: $depthLimit
191
+ enableThinking: $enableThinking
192
+ }
193
+ ) {
194
+ __typename
195
+ ...on Error {
196
+ message
197
+ }
198
+ ...on UnauthenticatedError {
199
+ message
200
+ }
201
+ ...on UserEvent {
202
+ uuid
203
+ parentUuid
204
+ chatId
205
+ isSidechain
206
+ version
207
+ createdAt
208
+ sidechainRootUuid
209
+ synthetic
210
+ messageData: message {
211
+ __typename
212
+ ... on TextMessage {
213
+ text
214
+ }
215
+ ... on ToolResultMessage {
216
+ messageId
217
+ toolUseId
218
+ text
219
+ resultData {
220
+ ... on BashToolResult {
221
+ shellOutput
222
+ exitCode
223
+ }
224
+ ... on ReadToolResult {
225
+ content
226
+ }
227
+ }
228
+ }
229
+ ... on PartialToolResultMessage {
230
+ messageId
231
+ toolUseId
232
+ text
233
+ resultData {
234
+ ... on PartialToolResult {
235
+ __typename
236
+ }
237
+ }
238
+ }
239
+ }
240
+ }
241
+ ...on AssistantEvent {
242
+ uuid
243
+ parentUuid
244
+ chatId
245
+ isSidechain
246
+ version
247
+ createdAt
248
+ sidechainRootUuid
249
+ synthetic
250
+ messageData: message {
251
+ __typename
252
+ ... on TextMessage {
253
+ text
254
+ }
255
+ ... on ToolCallMessage {
256
+ messageId
257
+ toolUseId
258
+ toolName
259
+ toolInput {
260
+ ... on BashToolInput {
261
+ command
262
+ }
263
+ ... on ReadToolInput {
264
+ filePath
265
+ }
266
+ }
267
+ }
268
+ }
269
+ }
270
+ ...on SystemEvent {
271
+ uuid
272
+ parentUuid
273
+ chatId
274
+ isSidechain
275
+ version
276
+ createdAt
277
+ sidechainRootUuid
278
+ messageData: message {
279
+ __typename
280
+ ... on ToolCallMessage {
281
+ messageId
282
+ toolUseId
283
+ toolName
284
+ toolInput {
285
+ ... on BashToolInput {
286
+ command
287
+ }
288
+ ... on ReadToolInput {
289
+ filePath
290
+ }
291
+ }
292
+ }
293
+ ... on ToolResultMessage {
294
+ messageId
295
+ toolUseId
296
+ text
297
+ resultData {
298
+ ... on BashToolResult {
299
+ shellOutput
300
+ exitCode
301
+ }
302
+ ... on ReadToolResult {
303
+ content
304
+ }
305
+ }
306
+ }
307
+ ... on ToolExecutionStatusMessage {
308
+ executionStatus: status
309
+ }
310
+ ... on ToolPermissionStatusMessage {
311
+ permissionStatus: status
312
+ }
313
+ }
314
+ }
315
+ }
316
+ }
317
+ """
318
+
319
+
320
+ INDENT_CHAT_EVENT_STREAM_SUBSCRIPTION = """
321
+ subscription IndentChatEventStream(
322
+ $chatUuid: String!
323
+ $lastKnownFullEventUuid: String
324
+ ) {
325
+ indentChatEventStream(
326
+ chatUuid: $chatUuid
327
+ lastKnownFullEventUuid: $lastKnownFullEventUuid
328
+ ) {
329
+ __typename
330
+ ...on Error {
331
+ message
332
+ }
333
+ ...on UnauthenticatedError {
334
+ message
335
+ }
336
+ ...on UserEvent {
337
+ uuid
338
+ parentUuid
339
+ chatId
340
+ isSidechain
341
+ version
342
+ createdAt
343
+ sidechainRootUuid
344
+ synthetic
345
+ messageData: message {
346
+ __typename
347
+ ... on TextMessage {
348
+ text
349
+ }
350
+ ... on ToolResultMessage {
351
+ messageId
352
+ toolUseId
353
+ text
354
+ resultData {
355
+ ... on BashToolResult {
356
+ shellOutput
357
+ exitCode
358
+ }
359
+ ... on ReadToolResult {
360
+ content
361
+ }
362
+ }
363
+ }
364
+ ... on PartialToolResultMessage {
365
+ messageId
366
+ toolUseId
367
+ text
368
+ resultData {
369
+ ... on PartialToolResult {
370
+ __typename
371
+ }
372
+ }
373
+ }
374
+ }
375
+ }
376
+ ...on AssistantEvent {
377
+ uuid
378
+ parentUuid
379
+ chatId
380
+ isSidechain
381
+ version
382
+ createdAt
383
+ sidechainRootUuid
384
+ synthetic
385
+ messageData: message {
386
+ __typename
387
+ ... on TextMessage {
388
+ text
389
+ }
390
+ ... on ToolCallMessage {
391
+ messageId
392
+ toolUseId
393
+ toolName
394
+ toolInput {
395
+ ... on BashToolInput {
396
+ command
397
+ }
398
+ ... on ReadToolInput {
399
+ filePath
400
+ }
401
+ }
402
+ }
403
+ }
404
+ }
405
+ ...on SystemEvent {
406
+ uuid
407
+ parentUuid
408
+ chatId
409
+ isSidechain
410
+ version
411
+ createdAt
412
+ sidechainRootUuid
413
+ messageData: message {
414
+ __typename
415
+ ... on ToolCallMessage {
416
+ messageId
417
+ toolUseId
418
+ toolName
419
+ toolInput {
420
+ ... on BashToolInput {
421
+ command
422
+ }
423
+ ... on ReadToolInput {
424
+ filePath
425
+ }
426
+ }
427
+ }
428
+ ... on ToolResultMessage {
429
+ messageId
430
+ toolUseId
431
+ text
432
+ resultData {
433
+ ... on BashToolResult {
434
+ shellOutput
435
+ exitCode
436
+ }
437
+ ... on ReadToolResult {
438
+ content
439
+ }
440
+ }
441
+ }
442
+ ... on ToolExecutionStatusMessage {
443
+ executionStatus: status
444
+ }
445
+ ... on ToolPermissionStatusMessage {
446
+ permissionStatus: status
447
+ }
448
+ }
449
+ }
450
+ }
451
+ }
452
+ """
@@ -0,0 +1,212 @@
1
+ import os
2
+ import subprocess
3
+ import tempfile
4
+
5
+ from pygit2.repository import Repository
6
+
7
+ from exponent.core.remote_execution.types import (
8
+ CreateCheckpointRequest,
9
+ CreateCheckpointResponse,
10
+ GitCommitMetadata,
11
+ GitDiff,
12
+ GitFileChange,
13
+ RollbackToCheckpointResponse,
14
+ )
15
+
16
+
17
+ async def create_checkpoint(
18
+ request: CreateCheckpointRequest,
19
+ ) -> CreateCheckpointResponse:
20
+ repo = Repository(".")
21
+ head_commit = str(repo.head.target)
22
+ uncommitted_changes_commit = None
23
+ diff_versus_last_checkpoint = None
24
+
25
+ # Get metadata for head commit - fetch each field separately
26
+ author_name = (
27
+ subprocess.run(
28
+ ["git", "log", "--format=%aN", "-1", head_commit],
29
+ capture_output=True,
30
+ text=True,
31
+ check=True,
32
+ ).stdout.strip()
33
+ or "unknown"
34
+ )
35
+
36
+ author_email = (
37
+ subprocess.run(
38
+ ["git", "log", "--format=%aE", "-1", head_commit],
39
+ capture_output=True,
40
+ text=True,
41
+ check=True,
42
+ ).stdout.strip()
43
+ or "unknown@unknown"
44
+ )
45
+
46
+ author_date = subprocess.run(
47
+ ["git", "log", "--format=%ai", "-1", head_commit],
48
+ capture_output=True,
49
+ text=True,
50
+ check=True,
51
+ ).stdout.strip()
52
+
53
+ commit_date = subprocess.run(
54
+ ["git", "log", "--format=%ci", "-1", head_commit],
55
+ capture_output=True,
56
+ text=True,
57
+ check=True,
58
+ ).stdout.strip()
59
+
60
+ commit_message = subprocess.run(
61
+ ["git", "log", "--format=%B", "-1", head_commit],
62
+ capture_output=True,
63
+ text=True,
64
+ check=True,
65
+ ).stdout.strip()
66
+
67
+ # Get current branch
68
+ branch_result = subprocess.run(
69
+ ["git", "rev-parse", "--abbrev-ref", "HEAD"],
70
+ capture_output=True,
71
+ text=True,
72
+ check=True,
73
+ )
74
+ branch = branch_result.stdout.strip()
75
+
76
+ head_metadata = GitCommitMetadata(
77
+ author_name=author_name,
78
+ author_email=author_email,
79
+ author_date=author_date,
80
+ commit_date=commit_date,
81
+ branch=branch,
82
+ commit_message=commit_message,
83
+ )
84
+
85
+ if repo.status(): # working dir is dirty
86
+ with tempfile.NamedTemporaryFile(prefix="git_index_") as tmp:
87
+ tmp_index_path = tmp.name
88
+
89
+ # Set up environment with temporary index
90
+ env = os.environ.copy()
91
+ env["GIT_INDEX_FILE"] = tmp_index_path
92
+
93
+ # Initialize temporary index from HEAD
94
+ subprocess.run(["git", "read-tree", head_commit], env=env, check=True)
95
+
96
+ # Add all files (including untracked) to temporary index
97
+ subprocess.run(["git", "add", "-A"], env=env, check=True)
98
+
99
+ # Write tree object from our temporary index
100
+ result = subprocess.run(
101
+ ["git", "write-tree"],
102
+ env=env,
103
+ capture_output=True,
104
+ text=True,
105
+ check=True,
106
+ )
107
+ tree_hash = result.stdout.strip()
108
+
109
+ if not tree_hash:
110
+ raise ValueError("Failed to create tree object")
111
+
112
+ # Create commit object from the tree with HEAD as parent
113
+ result = subprocess.run(
114
+ [
115
+ "git",
116
+ "commit-tree",
117
+ tree_hash,
118
+ "-p",
119
+ str(head_commit),
120
+ "-m",
121
+ "Checkpoint commit",
122
+ ],
123
+ capture_output=True,
124
+ text=True,
125
+ check=True,
126
+ )
127
+ uncommitted_changes_commit = result.stdout.strip()
128
+
129
+ if not uncommitted_changes_commit:
130
+ raise ValueError("Failed to create checkpoint commit")
131
+
132
+ if request.last_checkpoint_head_commit:
133
+ last_checkpoint_commit = (
134
+ request.last_checkpoint_uncommitted_changes_commit
135
+ or request.last_checkpoint_head_commit
136
+ )
137
+ current_commit = uncommitted_changes_commit or head_commit
138
+
139
+ diff_versus_last_checkpoint = _parse_git_diff_tree(
140
+ last_checkpoint_commit,
141
+ current_commit,
142
+ )
143
+
144
+ return CreateCheckpointResponse(
145
+ correlation_id=request.correlation_id,
146
+ head_commit_hash=head_commit,
147
+ head_commit_metadata=head_metadata,
148
+ uncommitted_changes_commit_hash=uncommitted_changes_commit,
149
+ diff_versus_last_checkpoint=diff_versus_last_checkpoint,
150
+ )
151
+
152
+
153
+ async def rollback_to_checkpoint(
154
+ correlation_id: str,
155
+ head_commit: str,
156
+ checkpoint_commit: str | None,
157
+ ) -> RollbackToCheckpointResponse:
158
+ # Clean working directory (including untracked files) before any operations
159
+ subprocess.run(
160
+ ["git", "clean", "-fd"], check=True
161
+ ) # Remove untracked files and directories
162
+ subprocess.run(
163
+ ["git", "reset", "--hard"], check=True
164
+ ) # Remove staged/unstaged changes
165
+
166
+ # Now reset HEAD to the original commit state
167
+ subprocess.run(["git", "reset", "--hard", head_commit], check=True)
168
+
169
+ if checkpoint_commit:
170
+ # Cherry-pick the checkpoint commit to restore all changes
171
+ subprocess.run(
172
+ ["git", "cherry-pick", "--no-commit", checkpoint_commit], check=True
173
+ )
174
+ subprocess.run(["git", "reset"], check=True)
175
+
176
+ return RollbackToCheckpointResponse(
177
+ correlation_id=correlation_id,
178
+ )
179
+
180
+
181
+ def _parse_git_diff_tree(
182
+ from_commit: str, to_commit: str, max_files: int = 50
183
+ ) -> GitDiff:
184
+ """Parse git diff-tree output into a GitDiff object.
185
+
186
+ Args:
187
+ from_commit: Starting commit hash
188
+ to_commit: Ending commit hash
189
+ max_files: Maximum number of files to include in the diff
190
+ """
191
+ result = subprocess.run(
192
+ ["git", "diff-tree", "--numstat", from_commit, to_commit],
193
+ capture_output=True,
194
+ text=True,
195
+ check=True,
196
+ )
197
+
198
+ files = []
199
+ for line in result.stdout.splitlines():
200
+ if not line.strip():
201
+ continue
202
+ added, deleted, path = line.split("\t")
203
+ files.append(
204
+ GitFileChange(path=path, lines_added=int(added), lines_deleted=int(deleted))
205
+ )
206
+
207
+ total_files = len(files)
208
+ truncated = total_files > max_files
209
+ if truncated:
210
+ files = files[:max_files]
211
+
212
+ return GitDiff(files=files, truncated=truncated, total_files=total_files)