indent 0.1.20__py3-none-any.whl → 0.1.22__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.

exponent/__init__.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.1.20'
32
- __version_tuple__ = version_tuple = (0, 1, 20)
31
+ __version__ = version = '0.1.22'
32
+ __version_tuple__ = version_tuple = (0, 1, 22)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -23,7 +23,6 @@ from exponent.core.graphql.client import GraphQLClient
23
23
  from exponent.core.graphql.mutations import (
24
24
  CREATE_CLOUD_CHAT_FROM_REPOSITORY_MUTATION,
25
25
  ENABLE_CLOUD_REPOSITORY_MUTATION,
26
- INCREMENTAL_BUILD_CLOUD_REPOSITORY_MUTATION,
27
26
  REBUILD_CLOUD_REPOSITORY_MUTATION,
28
27
  START_CHAT_TURN_MUTATION,
29
28
  )
@@ -62,32 +61,6 @@ async def enable_cloud_repository(
62
61
  return cast(dict[str, Any], result["enableCloudRepository"])
63
62
 
64
63
 
65
- async def incremental_build_cloud_repository(
66
- api_key: str,
67
- base_api_url: str,
68
- base_ws_url: str,
69
- org_name: str,
70
- repo_name: str,
71
- ) -> dict[str, Any]:
72
- graphql_client = GraphQLClient(
73
- api_key=api_key, base_api_url=base_api_url, base_ws_url=base_ws_url
74
- )
75
-
76
- variables = {
77
- "orgName": org_name,
78
- "repoName": repo_name,
79
- }
80
-
81
- result = await graphql_client.execute(
82
- INCREMENTAL_BUILD_CLOUD_REPOSITORY_MUTATION,
83
- variables,
84
- "IncrementalBuildCloudRepository",
85
- timeout=120,
86
- )
87
-
88
- return cast(dict[str, Any], result["incrementalBuildCloudRepository"])
89
-
90
-
91
64
  async def rebuild_cloud_repository(
92
65
  api_key: str,
93
66
  base_api_url: str,
@@ -138,6 +111,7 @@ async def create_cloud_chat_from_repository(
138
111
  base_api_url: str,
139
112
  base_ws_url: str,
140
113
  repository_id: str,
114
+ provider: str | None = None,
141
115
  ) -> dict[str, Any]:
142
116
  graphql_client = GraphQLClient(
143
117
  api_key=api_key, base_api_url=base_api_url, base_ws_url=base_ws_url
@@ -145,6 +119,7 @@ async def create_cloud_chat_from_repository(
145
119
 
146
120
  variables = {
147
121
  "repositoryId": repository_id,
122
+ "provider": provider,
148
123
  }
149
124
 
150
125
  result = await graphql_client.execute(
@@ -243,63 +218,6 @@ def enable_repo(
243
218
  sys.exit(1)
244
219
 
245
220
 
246
- @cloud_cli.command(hidden=True)
247
- @click.option(
248
- "--org-name",
249
- help="GitHub organization name",
250
- required=True,
251
- )
252
- @click.option(
253
- "--repo-name",
254
- help="GitHub repository name",
255
- required=True,
256
- )
257
- @use_settings
258
- def incremental_build(
259
- settings: Settings,
260
- org_name: str,
261
- repo_name: str,
262
- ) -> None:
263
- """Test utility for incremental build of cloud repository."""
264
- check_exponent_version_and_upgrade(settings)
265
-
266
- if not settings.api_key:
267
- redirect_to_login(settings)
268
- return
269
-
270
- loop = asyncio.get_event_loop()
271
-
272
- api_key = settings.api_key
273
- base_api_url = settings.get_base_api_url()
274
- base_ws_url = settings.get_base_ws_url()
275
-
276
- try:
277
- result = loop.run_until_complete(
278
- incremental_build_cloud_repository(
279
- api_key, base_api_url, base_ws_url, org_name, repo_name
280
- )
281
- )
282
-
283
- if result["__typename"] == "ContainerImage":
284
- click.secho(
285
- f"✓ Successfully triggered incremental build for {org_name}/{repo_name}",
286
- fg="green",
287
- )
288
- click.echo(f" Build ref: {result.get('buildRef', 'N/A')}")
289
- click.echo(f" Created at: {result.get('createdAt', 'N/A')}")
290
- click.echo(f" Updated at: {result.get('updatedAt', 'N/A')}")
291
- else:
292
- click.secho(
293
- f"✗ Failed to trigger incremental build: {result.get('message', 'Unknown error')}",
294
- fg="red",
295
- )
296
- click.echo(f" Error type: {result['__typename']}")
297
-
298
- except Exception as e:
299
- click.secho(f"✗ Error triggering incremental build: {e!s}", fg="red")
300
- sys.exit(1)
301
-
302
-
303
221
  @cloud_cli.command(hidden=True)
304
222
  @click.option(
305
223
  "--org-name",
@@ -76,8 +76,8 @@ mutation CreateCloudChat($configId: String!) {
76
76
 
77
77
 
78
78
  CREATE_CLOUD_CHAT_FROM_REPOSITORY_MUTATION = """
79
- mutation CreateCloudChatFromRepository($repositoryId: String!) {
80
- createCloudChat(repositoryId: $repositoryId) {
79
+ mutation CreateCloudChatFromRepository($repositoryId: String!, $provider: String) {
80
+ createCloudChat(repositoryId: $repositoryId, provider: $provider) {
81
81
  __typename
82
82
  ...on Chat {
83
83
  chatUuid
@@ -131,35 +131,6 @@ mutation EnableCloudRepository($orgName: String!, $repoName: String!) {
131
131
  """
132
132
 
133
133
 
134
- INCREMENTAL_BUILD_CLOUD_REPOSITORY_MUTATION = """
135
- mutation IncrementalBuildCloudRepository($orgName: String!, $repoName: String!) {
136
- incrementalBuildCloudRepository(orgName: $orgName, repoName: $repoName) {
137
- __typename
138
- ...on ContainerImage {
139
- buildRef
140
- createdAt
141
- updatedAt
142
- }
143
- ...on UnauthenticatedError {
144
- message
145
- }
146
- ...on CloudConfigNotFoundError {
147
- message
148
- }
149
- ...on GithubConfigNotFoundError {
150
- message
151
- }
152
- ...on CloudSessionError {
153
- message
154
- }
155
- ...on Error {
156
- message
157
- }
158
- }
159
- }
160
- """
161
-
162
-
163
134
  REBUILD_CLOUD_REPOSITORY_MUTATION = """
164
135
  mutation RebuildCloudRepository($orgName: String!, $repoName: String!) {
165
136
  rebuildCloudRepository(orgName: $orgName, repoName: $repoName) {
@@ -66,14 +66,28 @@ class FileMetadata(msgspec.Struct):
66
66
  file_mode: str
67
67
 
68
68
 
69
+ class ReadToolArtifactResult(ToolResult, tag=READ_TOOL_ARTIFACT_NAME):
70
+ s3_uri: str
71
+ file_path: str
72
+ media_type: str
73
+
74
+ def to_text(self) -> str:
75
+ return f"[Image artifact uploaded to {self.s3_uri}]"
76
+
77
+
69
78
  class ReadToolResult(ToolResult, tag=READ_TOOL_NAME):
70
- content: str
71
- num_lines: int
72
- start_line: int
73
- total_lines: int
79
+ content: str | None = None
80
+ num_lines: int | None = None
81
+ start_line: int | None = None
82
+ total_lines: int | None = None
74
83
  metadata: FileMetadata | None = None
84
+ artifact: ReadToolArtifactResult | None = None
75
85
 
76
86
  def to_text(self) -> str:
87
+ if self.artifact:
88
+ return self.artifact.to_text()
89
+ assert self.content is not None
90
+ assert self.start_line is not None
77
91
  lines = self.content.splitlines()
78
92
  lines = [
79
93
  f"{str(i).rjust(6)}→{line}"
@@ -82,15 +96,6 @@ class ReadToolResult(ToolResult, tag=READ_TOOL_NAME):
82
96
  return "\n".join(lines)
83
97
 
84
98
 
85
- class ReadToolArtifactResult(ToolResult, tag=READ_TOOL_ARTIFACT_NAME):
86
- s3_uri: str
87
- file_path: str
88
- media_type: str
89
-
90
- def to_text(self) -> str:
91
- return f"[Image artifact uploaded to {self.s3_uri}]"
92
-
93
-
94
99
  LIST_TOOL_NAME = "ls"
95
100
 
96
101
 
@@ -273,6 +278,10 @@ class TerminateResponse(msgspec.Struct, tag="terminate"):
273
278
  pass
274
279
 
275
280
 
281
+ class TimeoutResponse(msgspec.Struct, tag="timeout"):
282
+ pass
283
+
284
+
276
285
  class BatchToolExecutionResponse(msgspec.Struct, tag="batch_tool_execution"):
277
286
  tool_results: list[ToolResultType]
278
287
 
@@ -324,6 +333,7 @@ class CliRpcResponse(msgspec.Struct):
324
333
  | GetAllFilesResponse
325
334
  | ErrorResponse
326
335
  | TerminateResponse
336
+ | TimeoutResponse
327
337
  | BatchToolExecutionResponse
328
338
  | HttpResponse
329
339
  | SwitchCLIChatResponse
@@ -413,6 +413,7 @@ class RemoteExecutionClient:
413
413
  results: asyncio.Queue[CliRpcResponse],
414
414
  ) -> REMOTE_EXECUTION_CLIENT_EXIT_INFO:
415
415
  """Process messages from the websocket connection."""
416
+ pending: set[asyncio.Task[object]] = set()
416
417
  try:
417
418
  recv = asyncio.create_task(websocket.recv())
418
419
  get_beat = asyncio.create_task(beats.get())
@@ -462,6 +463,9 @@ class RemoteExecutionClient:
462
463
  self,
463
464
  websocket: ClientConnection,
464
465
  connection_tracker: ConnectionTracker | None,
466
+ beats: asyncio.Queue[HeartbeatInfo],
467
+ requests: asyncio.Queue[CliRpcRequest],
468
+ results: asyncio.Queue[CliRpcResponse],
465
469
  ) -> REMOTE_EXECUTION_CLIENT_EXIT_INFO | None:
466
470
  """Handle a single websocket connection.
467
471
  Returns None to continue with reconnection attempts, or an exit info to terminate."""
@@ -470,12 +474,6 @@ class RemoteExecutionClient:
470
474
 
471
475
  self._websocket = websocket
472
476
 
473
- beats: asyncio.Queue[HeartbeatInfo] = asyncio.Queue()
474
- requests: asyncio.Queue[CliRpcRequest] = asyncio.Queue()
475
- results: asyncio.Queue[CliRpcResponse] = asyncio.Queue()
476
-
477
- tasks = await self._setup_tasks(beats, requests, results)
478
-
479
477
  try:
480
478
  return await self._process_websocket_messages(
481
479
  websocket, beats, requests, results
@@ -493,15 +491,13 @@ class RemoteExecutionClient:
493
491
  )
494
492
  return WSDisconnected(error_message=error_message)
495
493
  # Otherwise, allow reconnection attempt
494
+ logger.debug("Websocket connection closed by remote.")
496
495
  return None
497
496
  except TimeoutError:
498
497
  # Timeout, allow reconnection attempt
499
498
  # TODO: investgate if this is needed, possibly scope it down
500
499
  return None
501
500
  finally:
502
- for task in tasks:
503
- task.cancel()
504
- await asyncio.gather(*tasks, return_exceptions=True)
505
501
  if connection_tracker is not None:
506
502
  await connection_tracker.set_connected(False)
507
503
 
@@ -517,33 +513,51 @@ class RemoteExecutionClient:
517
513
  # Initialize last request time for timeout monitoring
518
514
  self._last_request_time = time.time()
519
515
 
520
- async for websocket in self.ws_connect(f"/api/ws/chat/{chat_uuid}"):
521
- # Always run connection and timeout monitor concurrently
522
- # If timeout_seconds is None, timeout monitor will loop indefinitely
523
- done, pending = await asyncio.wait(
524
- [
525
- asyncio.create_task(
526
- self._handle_websocket_connection(websocket, connection_tracker)
527
- ),
528
- asyncio.create_task(self._timeout_monitor(timeout_seconds)),
529
- ],
530
- return_when=asyncio.FIRST_COMPLETED,
531
- )
516
+ # Create queues ONCE - persist across reconnections
517
+ beats: asyncio.Queue[HeartbeatInfo] = asyncio.Queue()
518
+ requests: asyncio.Queue[CliRpcRequest] = asyncio.Queue()
519
+ results: asyncio.Queue[CliRpcResponse] = asyncio.Queue()
532
520
 
533
- # Cancel pending tasks
534
- for task in pending:
535
- task.cancel()
521
+ # Create tasks ONCE - persist across reconnections
522
+ executors = await self._setup_tasks(beats, requests, results)
536
523
 
537
- # Return result from completed task
538
- for task in done:
539
- result = await task
540
- # If we get None, we'll try to reconnect
541
- if result is not None:
542
- return result
524
+ try:
525
+ async for websocket in self.ws_connect(f"/api/ws/chat/{chat_uuid}"):
526
+ # Always run connection and timeout monitor concurrently
527
+ # If timeout_seconds is None, timeout monitor will loop indefinitely
528
+ done, pending = await asyncio.wait(
529
+ [
530
+ asyncio.create_task(
531
+ self._handle_websocket_connection(
532
+ websocket, connection_tracker, beats, requests, results
533
+ )
534
+ ),
535
+ asyncio.create_task(self._timeout_monitor(timeout_seconds)),
536
+ ],
537
+ return_when=asyncio.FIRST_COMPLETED,
538
+ )
543
539
 
544
- # If we exit the websocket connection loop without returning,
545
- # it means we couldn't establish a connection
546
- return WSDisconnected(error_message="Could not establish websocket connection")
540
+ # Cancel pending tasks
541
+ for task in pending:
542
+ task.cancel()
543
+
544
+ # Return result from completed task
545
+ for task in done:
546
+ result = await task
547
+ # If we get None, we'll try to reconnect
548
+ if result is not None:
549
+ return result
550
+
551
+ # If we exit the websocket connection loop without returning,
552
+ # it means we couldn't establish a connection
553
+ return WSDisconnected(
554
+ error_message="Could not establish websocket connection"
555
+ )
556
+ finally:
557
+ # Cancel all background tasks when exiting
558
+ for task in executors:
559
+ task.cancel()
560
+ await asyncio.gather(*executors, return_exceptions=True)
547
561
 
548
562
  async def create_chat(self, chat_source: ChatSource) -> CreateChatResponse:
549
563
  response = await self.api_client.post(
@@ -53,7 +53,7 @@ async def read_stream(
53
53
  data = await stream.read(4096)
54
54
  if not data:
55
55
  break
56
- chunk = data.decode(encoding=encoding)
56
+ chunk = data.decode(encoding=encoding, errors="replace")
57
57
  output.append((fd, chunk))
58
58
  yield StreamedOutputPiece(content=chunk)
59
59
  except UnicodeDecodeError:
@@ -0,0 +1,73 @@
1
+ import time
2
+
3
+ import psutil
4
+
5
+ from exponent.core.remote_execution.types import PortInfo
6
+
7
+
8
+ def get_port_usage() -> list[PortInfo] | None:
9
+ """
10
+ Get information about all listening ports on the system.
11
+
12
+ Returns:
13
+ List of PortInfo objects containing process name, port, protocol, pid, and uptime.
14
+ Returns None if there's a permission error.
15
+ Returns empty list if no listening ports are found.
16
+ """
17
+ try:
18
+ connections = psutil.net_connections(kind="tcp")
19
+ except (psutil.AccessDenied, PermissionError):
20
+ # If we don't have permission to see connections, return None
21
+ return None
22
+ except Exception:
23
+ # For any other unexpected errors, return None
24
+ return None
25
+
26
+ port_info_list: list[PortInfo] = []
27
+ current_time = time.time()
28
+
29
+ for conn in connections:
30
+ # Only include TCP ports in LISTEN state
31
+ if conn.status != "LISTEN":
32
+ continue
33
+
34
+ # Skip if no local address (shouldn't happen for LISTEN, but be safe)
35
+ if not conn.laddr:
36
+ continue
37
+
38
+ port = conn.laddr.port
39
+ pid = conn.pid
40
+
41
+ # Try to get process information
42
+ process_name = "unknown"
43
+ uptime_seconds = None
44
+
45
+ if pid:
46
+ try:
47
+ process = psutil.Process(pid)
48
+ process_name = process.name()
49
+
50
+ # Calculate uptime
51
+ create_time = process.create_time()
52
+ uptime_seconds = current_time - create_time
53
+ except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
54
+ # Process disappeared or we don't have permission
55
+ pass
56
+ except Exception:
57
+ # Any other unexpected error, just skip process info
58
+ pass
59
+
60
+ port_info = PortInfo(
61
+ process_name=process_name,
62
+ port=port,
63
+ protocol="TCP",
64
+ pid=pid,
65
+ uptime_seconds=uptime_seconds,
66
+ )
67
+ port_info_list.append(port_info)
68
+
69
+ # Limit to 50 ports to avoid bloating the heartbeat payload
70
+ if len(port_info_list) >= 50:
71
+ break
72
+
73
+ return port_info_list
@@ -4,6 +4,7 @@ import platform
4
4
 
5
5
  from exponent.core.remote_execution.git import get_git_info
6
6
  from exponent.core.remote_execution.languages import python_execution
7
+ from exponent.core.remote_execution.port_utils import get_port_usage
7
8
  from exponent.core.remote_execution.types import (
8
9
  SystemInfo,
9
10
  )
@@ -17,6 +18,7 @@ async def get_system_info(working_directory: str) -> SystemInfo:
17
18
  shell=_get_user_shell(),
18
19
  git=await get_git_info(working_directory),
19
20
  python_env=python_execution.get_python_env_info(),
21
+ port_usage=get_port_usage(),
20
22
  )
21
23
 
22
24
 
@@ -90,7 +90,7 @@ async def execute_read_file( # noqa: PLR0911, PLR0915
90
90
  tool_input: ReadToolInput,
91
91
  working_directory: str,
92
92
  upload_client: "RemoteExecutionClient | None" = None,
93
- ) -> ReadToolResult | ReadToolArtifactResult | ErrorToolResult:
93
+ ) -> ReadToolResult | ErrorToolResult:
94
94
  # Validate absolute path requirement
95
95
  if not tool_input.file_path.startswith("/"):
96
96
  return ErrorToolResult(
@@ -136,10 +136,12 @@ async def execute_read_file( # noqa: PLR0911, PLR0915
136
136
  if status != 200:
137
137
  raise RuntimeError(f"Upload failed with status {status}")
138
138
 
139
- return ReadToolArtifactResult(
140
- s3_uri=upload_response.s3_uri,
141
- file_path=tool_input.file_path,
142
- media_type=media_type,
139
+ return ReadToolResult(
140
+ artifact=ReadToolArtifactResult(
141
+ s3_uri=upload_response.s3_uri,
142
+ file_path=tool_input.file_path,
143
+ media_type=media_type,
144
+ )
143
145
  )
144
146
  except Exception as e:
145
147
  return ErrorToolResult(error_message=f"Failed to upload image to S3: {e!s}")
@@ -11,7 +11,6 @@ from exponent.core.remote_execution.cli_rpc_types import (
11
11
  GlobToolResult,
12
12
  GrepToolResult,
13
13
  ListToolResult,
14
- ReadToolArtifactResult,
15
14
  ReadToolResult,
16
15
  ToolResult,
17
16
  WriteToolResult,
@@ -273,7 +272,6 @@ class StringListTruncation(TruncationStrategy):
273
272
 
274
273
  TRUNCATION_REGISTRY: dict[type[ToolResult], TruncationStrategy] = {
275
274
  ReadToolResult: StringFieldTruncation("content"),
276
- ReadToolArtifactResult: NoOpTruncation(),
277
275
  WriteToolResult: StringFieldTruncation("message"),
278
276
  BashToolResult: TailTruncation("shell_output"),
279
277
  GrepToolResult: StringListTruncation("matches"),
@@ -50,6 +50,7 @@ class PrReviewWorkflowInput(BaseModel):
50
50
 
51
51
 
52
52
  class SlackWorkflowInput(BaseModel):
53
+ discriminator: Literal["slack_workflow"] = "slack_workflow"
53
54
  channel_id: str
54
55
  thread_ts: str
55
56
  slack_url: str | None = None
@@ -57,13 +58,34 @@ class SlackWorkflowInput(BaseModel):
57
58
  message_ts: str | None = None
58
59
 
59
60
 
61
+ class SlackPlanApprovalWorkflowInput(BaseModel):
62
+ discriminator: Literal["slack_plan_approval"] = "slack_plan_approval"
63
+ channel_id: str
64
+ thread_ts: str
65
+ slack_url: str
66
+ channel_name: str
67
+ message_ts: str
68
+
69
+
60
70
  class SentryWorkflowInput(BaseModel):
61
71
  title: str
62
72
  issue_id: str
63
73
  permalink: str
64
74
 
65
75
 
66
- WorkflowInput = PrReviewWorkflowInput | SlackWorkflowInput | SentryWorkflowInput
76
+ class GenericCloudWorkflowInput(BaseModel):
77
+ initial_prompt: str
78
+ system_prompt_override: str | None = None
79
+ reasoning_level: str = "LOW"
80
+
81
+
82
+ WorkflowInput = (
83
+ PrReviewWorkflowInput
84
+ | SlackWorkflowInput
85
+ | SentryWorkflowInput
86
+ | GenericCloudWorkflowInput
87
+ | SlackPlanApprovalWorkflowInput
88
+ )
67
89
 
68
90
 
69
91
  class WorkflowTriggerRequest(BaseModel):
@@ -98,6 +120,14 @@ class PythonEnvInfo(BaseModel):
98
120
  provider: Literal["venv", "pyenv", "pipenv", "conda"] | None = "pyenv"
99
121
 
100
122
 
123
+ class PortInfo(BaseModel):
124
+ process_name: str
125
+ port: int
126
+ protocol: str
127
+ pid: int | None
128
+ uptime_seconds: float | None
129
+
130
+
101
131
  class SystemInfo(BaseModel):
102
132
  name: str
103
133
  cwd: str
@@ -105,6 +135,7 @@ class SystemInfo(BaseModel):
105
135
  shell: str
106
136
  git: GitInfo | None
107
137
  python_env: PythonEnvInfo | None
138
+ port_usage: list[PortInfo] | None = None
108
139
 
109
140
 
110
141
  class HeartbeatInfo(BaseModel):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: indent
3
- Version: 0.1.20
3
+ Version: 0.1.22
4
4
  Summary: Indent is an AI Pair Programmer
5
5
  Author-email: Sashank Thupukari <sashank@exponent.run>
6
6
  Requires-Python: <3.13,>=3.10
@@ -22,6 +22,7 @@ Requires-Dist: msgspec>=0.19.0
22
22
  Requires-Dist: packaging~=24.1
23
23
  Requires-Dist: pip<26,>=25.0.1
24
24
  Requires-Dist: prompt-toolkit<4,>=3.0.36
25
+ Requires-Dist: psutil<7,>=5.9.0
25
26
  Requires-Dist: pydantic-ai==0.0.30
26
27
  Requires-Dist: pydantic-settings<3,>=2.2.1
27
28
  Requires-Dist: pydantic[email]<3,>=2.6.4
@@ -1,7 +1,7 @@
1
- exponent/__init__.py,sha256=P88Jfo9OvOr8LB0vHFqLUwFR7A0eE281KxEewbcCSBc,706
1
+ exponent/__init__.py,sha256=o3nZ3vj6LXerN2NKds558INvVml0G0wcb-duWVc5JMs,706
2
2
  exponent/cli.py,sha256=QnIeDTgWaQJrRs5WESCkQpVEQiJiAO4qWgB0rYlkd78,3344
3
3
  exponent/py.typed,sha256=9XZl5avs8yHp89XP_1Fjtbeg_2rjYorCC9I0k_j-h2c,334
4
- exponent/commands/cloud_commands.py,sha256=TNSbKnc7VBo7VALj44CqV5tdCACJejEGmtYvc5wjza4,19080
4
+ exponent/commands/cloud_commands.py,sha256=yd0d7l8AaFZIgrFPRYspsKlmcyFqkK_ovSQKhK-YpVU,16773
5
5
  exponent/commands/common.py,sha256=M2KI9yKjB8fecPoDBphMa123c35-iNeaE9q4DxhkaFU,12817
6
6
  exponent/commands/config_commands.py,sha256=mmQYuyRosODgawoHWsn9xnWnV37GiQaxJjMv-_xreAU,8902
7
7
  exponent/commands/run_commands.py,sha256=xn0SJX0PPrmHu8Nh-kG-lJBhGC4qFCc04aLIzdVyFho,6389
@@ -13,12 +13,12 @@ exponent/core/config.py,sha256=TNFLUgLnfSocRMVSav_7E4VcaNHXZ_3Mg5Lp1smP46U,5731
13
13
  exponent/core/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  exponent/core/graphql/client.py,sha256=SRagD3YPyoYZSO1RtfO-OXD7b5dm1NvgoL6CTbN380o,2009
15
15
  exponent/core/graphql/get_chats_query.py,sha256=9-2N1VfapXUZB3IFIKw5U_gKdmfyviJp5JSUntB_Yyk,1177
16
- exponent/core/graphql/mutations.py,sha256=cAAiSefyamBgy1zJEZ7LNk0rbjwawTPxMyj8eU6yRRI,3502
16
+ exponent/core/graphql/mutations.py,sha256=Szs8wS_5EpVuZdt09QbstIm_8i-_-EGT4Z17pou5714,2971
17
17
  exponent/core/graphql/queries.py,sha256=RYsk8bub0esspqgakilhzX07yJf2652Ey9tBZK1l_lY,3297
18
18
  exponent/core/graphql/subscriptions.py,sha256=SQngv_nYVNJjiZ_P2k0UcLIu1pzc4vi7q7lhH89NCZM,393
19
19
  exponent/core/remote_execution/checkpoints.py,sha256=3QGYMLa8vT7XmxMYTRcGrW8kNGHwRC0AkUfULribJWg,6354
20
- exponent/core/remote_execution/cli_rpc_types.py,sha256=uBqmxGkhx_SjfMsUeBBKUp1gj273wtsEze0NFmVcwms,8292
21
- exponent/core/remote_execution/client.py,sha256=9TlYzwh1lBiOeBlhGUhSo73KQGMh6nvbm1xdfxM48OY,31349
20
+ exponent/core/remote_execution/cli_rpc_types.py,sha256=1HPLLtzpeGJfkh8nXlo8d_zDajzfDIwLu83Cfm60Cnc,8642
21
+ exponent/core/remote_execution/client.py,sha256=dG2ueANYJH8CznDT5L3-UApkWZ25ANheSvv62JCMq9c,32038
22
22
  exponent/core/remote_execution/code_execution.py,sha256=jYPB_7dJzS9BTPLX9fKQpsFPatwjbXuaFFSxT9tDTfI,2388
23
23
  exponent/core/remote_execution/default_env.py,sha256=s44A1Cz9EgYuhF17WO3ESVNSLQw57EoOLyi9k6qliIo,911
24
24
  exponent/core/remote_execution/error_info.py,sha256=Rd7OA3ps06qYejPVcOaMBB9AtftP3wqQoOfiILFASnc,1378
@@ -27,15 +27,16 @@ exponent/core/remote_execution/file_write.py,sha256=8Sa70ANIDHGxIAq4_Uy2Qoo55K7-
27
27
  exponent/core/remote_execution/files.py,sha256=mIVjhStaEKETW6y3pCVeV8eJKNaPtroWGP_kBK1x8uA,8776
28
28
  exponent/core/remote_execution/git.py,sha256=dGjBpeoKJZsYgRwctSq29GmbsNIN9tbSA3VwBnRD0IQ,7810
29
29
  exponent/core/remote_execution/http_fetch.py,sha256=aFEyXd0S-MRfisSMuIFiEyc1AEAj9nUZ9Rj_P_YRows,2827
30
+ exponent/core/remote_execution/port_utils.py,sha256=kWje8ikCzBXMeS7qr6NZZOzQOMoMuacgPUDYyloYgwM,2183
30
31
  exponent/core/remote_execution/session.py,sha256=jlQIdeUj0f7uOk3BgzlJtBJ_GyTIjCchBp5ApQuF2-I,3847
31
- exponent/core/remote_execution/system_context.py,sha256=QY1zY8_fWj3sh-fmLYtewvgxh7uTX4ITIJqlUTDkj6c,648
32
- exponent/core/remote_execution/tool_execution.py,sha256=LSV4vL5eCdjEWxlQF5nL9XwC7PC4c-jPhbfHnBE1pBM,15737
32
+ exponent/core/remote_execution/system_context.py,sha256=I4RNuM60isS-529EuRrrEPPwJssNFC2TZ_7MhBTWEd0,754
33
+ exponent/core/remote_execution/tool_execution.py,sha256=DVO7jPS6JUGjY3GTevvNn5NlieKDOcx8id_nhi9x6Og,15783
33
34
  exponent/core/remote_execution/tool_type_utils.py,sha256=7qi6Qd8fvHts019ZSLPbtiy17BUqgqBg3P_gdfvFf7w,1301
34
- exponent/core/remote_execution/truncation.py,sha256=1L0qwbWgQFRwJZeCXRVKkEhKmzoS1x2usDLPUIp-jlU,9923
35
- exponent/core/remote_execution/types.py,sha256=nq-7ZppzpEt3pPj3pe18102GG-EYw2I_iLkRrTJjfg8,15078
35
+ exponent/core/remote_execution/truncation.py,sha256=crHzjcUxL3tVe8yuoWNAE5r-uQKjtL-GzZczd-ucrd0,9849
36
+ exponent/core/remote_execution/types.py,sha256=2tp73g6WLhL3x-5FyP9jhadcRHIswt4wfJJlEvNwlvk,15782
36
37
  exponent/core/remote_execution/utils.py,sha256=6PlBqYJ3OQwZ0dgXiIu3br04a-d-glDeDZpD0XGGPAE,14793
37
38
  exponent/core/remote_execution/languages/python_execution.py,sha256=nsX_LsXcUcHhiEHpSTjOTVNd7CxM146al0kw_iQX5OU,7724
38
- exponent/core/remote_execution/languages/shell_streaming.py,sha256=SUlk_dyN0FME3KerwdP-EB7eVe1_dNNn_HRdiEYnTes,7644
39
+ exponent/core/remote_execution/languages/shell_streaming.py,sha256=gBACa5uFMGuQzEFpKE61ww6niHWFe58NToI1HaIYGVU,7662
39
40
  exponent/core/remote_execution/languages/types.py,sha256=f7FjSRNRSga-ZaE3LddDhxCirUVjlSYMEdoskG6Pta4,314
40
41
  exponent/core/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
42
  exponent/core/types/command_data.py,sha256=_HqQsnamRZeVoVaTpeO3ecVUzNBdG62WXlFy6Q7rtUM,5294
@@ -46,7 +47,7 @@ exponent/migration-docs/login.md,sha256=KIeXy3m2nzSUgw-4PW1XzXfHael1D4Zu93CplLMb
46
47
  exponent/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
48
  exponent/utils/colors.py,sha256=HBkqe_ZmhJ9YiL2Fpulqek4KvLS5mwBTY4LQSM5N8SM,2762
48
49
  exponent/utils/version.py,sha256=GHZ9ET1kMyDubJZU3w2sah5Pw8XpiEakS5IOlt3wUnQ,8888
49
- indent-0.1.20.dist-info/METADATA,sha256=B9VbGtq-Ukm0jAsk18J05cPOitLswkeV7wVbYfQG2hA,1308
50
- indent-0.1.20.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
51
- indent-0.1.20.dist-info/entry_points.txt,sha256=q8q1t1sbl4NULGOR0OV5RmSG4KEjkpEQRU_RUXEGzcs,44
52
- indent-0.1.20.dist-info/RECORD,,
50
+ indent-0.1.22.dist-info/METADATA,sha256=l7eGEejpLppz_acmZgTllUehYS1EYiWqQVzdyjTq1Ik,1340
51
+ indent-0.1.22.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
52
+ indent-0.1.22.dist-info/entry_points.txt,sha256=q8q1t1sbl4NULGOR0OV5RmSG4KEjkpEQRU_RUXEGzcs,44
53
+ indent-0.1.22.dist-info/RECORD,,