indent 0.1.18__tar.gz → 0.1.20__tar.gz

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 (52) hide show
  1. {indent-0.1.18 → indent-0.1.20}/.gitignore +3 -0
  2. {indent-0.1.18 → indent-0.1.20}/PKG-INFO +1 -1
  3. {indent-0.1.18 → indent-0.1.20}/exponent/__init__.py +2 -2
  4. {indent-0.1.18 → indent-0.1.20}/exponent/commands/config_commands.py +0 -87
  5. {indent-0.1.18 → indent-0.1.20}/exponent/commands/run_commands.py +1 -1
  6. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/cli_rpc_types.py +1 -0
  7. indent-0.1.20/exponent/core/remote_execution/default_env.py +31 -0
  8. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/languages/shell_streaming.py +4 -0
  9. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/tool_execution.py +17 -11
  10. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/types.py +8 -1
  11. indent-0.1.18/exponent/core/graphql/github_config_queries.py +0 -56
  12. {indent-0.1.18 → indent-0.1.20}/exponent/cli.py +0 -0
  13. {indent-0.1.18 → indent-0.1.20}/exponent/commands/cloud_commands.py +0 -0
  14. {indent-0.1.18 → indent-0.1.20}/exponent/commands/common.py +0 -0
  15. {indent-0.1.18 → indent-0.1.20}/exponent/commands/settings.py +0 -0
  16. {indent-0.1.18 → indent-0.1.20}/exponent/commands/types.py +0 -0
  17. {indent-0.1.18 → indent-0.1.20}/exponent/commands/upgrade.py +0 -0
  18. {indent-0.1.18 → indent-0.1.20}/exponent/commands/utils.py +0 -0
  19. {indent-0.1.18 → indent-0.1.20}/exponent/core/config.py +0 -0
  20. {indent-0.1.18 → indent-0.1.20}/exponent/core/graphql/__init__.py +0 -0
  21. {indent-0.1.18 → indent-0.1.20}/exponent/core/graphql/client.py +0 -0
  22. {indent-0.1.18 → indent-0.1.20}/exponent/core/graphql/get_chats_query.py +0 -0
  23. {indent-0.1.18 → indent-0.1.20}/exponent/core/graphql/mutations.py +0 -0
  24. {indent-0.1.18 → indent-0.1.20}/exponent/core/graphql/queries.py +0 -0
  25. {indent-0.1.18 → indent-0.1.20}/exponent/core/graphql/subscriptions.py +0 -0
  26. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/checkpoints.py +0 -0
  27. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/client.py +0 -0
  28. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/code_execution.py +0 -0
  29. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/error_info.py +0 -0
  30. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/exceptions.py +0 -0
  31. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/file_write.py +0 -0
  32. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/files.py +0 -0
  33. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/git.py +0 -0
  34. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/http_fetch.py +0 -0
  35. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/languages/python_execution.py +0 -0
  36. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/languages/types.py +0 -0
  37. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/session.py +0 -0
  38. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/system_context.py +0 -0
  39. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/tool_type_utils.py +0 -0
  40. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/truncation.py +0 -0
  41. {indent-0.1.18 → indent-0.1.20}/exponent/core/remote_execution/utils.py +0 -0
  42. {indent-0.1.18 → indent-0.1.20}/exponent/core/types/__init__.py +0 -0
  43. {indent-0.1.18 → indent-0.1.20}/exponent/core/types/command_data.py +0 -0
  44. {indent-0.1.18 → indent-0.1.20}/exponent/core/types/event_types.py +0 -0
  45. {indent-0.1.18 → indent-0.1.20}/exponent/core/types/generated/__init__.py +0 -0
  46. {indent-0.1.18 → indent-0.1.20}/exponent/core/types/generated/strategy_info.py +0 -0
  47. {indent-0.1.18 → indent-0.1.20}/exponent/migration-docs/login.md +0 -0
  48. {indent-0.1.18 → indent-0.1.20}/exponent/py.typed +0 -0
  49. {indent-0.1.18 → indent-0.1.20}/exponent/utils/__init__.py +0 -0
  50. {indent-0.1.18 → indent-0.1.20}/exponent/utils/colors.py +0 -0
  51. {indent-0.1.18 → indent-0.1.20}/exponent/utils/version.py +0 -0
  52. {indent-0.1.18 → indent-0.1.20}/pyproject.toml +0 -0
@@ -167,6 +167,9 @@ dmypy.json
167
167
  # Debug logs
168
168
  debug/
169
169
 
170
+ # Local test scripts
171
+ local_test_scripts/
172
+
170
173
  # Benchmarks
171
174
  .benchy.*
172
175
  node_modules
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: indent
3
- Version: 0.1.18
3
+ Version: 0.1.20
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
@@ -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.18'
32
- __version_tuple__ = version_tuple = (0, 1, 18)
31
+ __version__ = version = '0.1.20'
32
+ __version_tuple__ = version_tuple = (0, 1, 20)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -14,11 +14,6 @@ from exponent.commands.types import exponent_cli_group
14
14
  from exponent.core.config import Settings
15
15
  from exponent.core.graphql.client import GraphQLClient
16
16
  from exponent.core.graphql.get_chats_query import GET_CHATS_QUERY
17
- from exponent.core.graphql.github_config_queries import (
18
- CHECK_GITHUB_CONFIG_VALIDITY_QUERY,
19
- CREATE_GITHUB_CONFIG_MUTATION,
20
- REPOS_FOR_GITHUB_CONFIG_QUERY,
21
- )
22
17
  from exponent.core.graphql.subscriptions import AUTHENTICATED_USER_SUBSCRIPTION
23
18
  from exponent.utils.version import (
24
19
  get_installed_metadata,
@@ -56,74 +51,6 @@ def debug(
56
51
  click.echo(get_installed_metadata())
57
52
 
58
53
 
59
- @config_cli.command(hidden=True)
60
- @use_settings
61
- def check_github_config_validity(
62
- settings: Settings,
63
- ) -> None:
64
- if not settings.api_key:
65
- redirect_to_login(settings)
66
- return
67
-
68
- run_until_complete(
69
- check_github_config_validity_task(
70
- api_key=settings.api_key,
71
- base_api_url=settings.get_base_api_url(),
72
- base_ws_url=settings.get_base_ws_url(),
73
- )
74
- )
75
-
76
-
77
- async def check_github_config_validity_task(
78
- api_key: str,
79
- base_api_url: str,
80
- base_ws_url: str,
81
- ) -> None:
82
- graphql_client = GraphQLClient(api_key, base_api_url, base_ws_url)
83
- result = await graphql_client.execute(CHECK_GITHUB_CONFIG_VALIDITY_QUERY)
84
- click.echo(result)
85
-
86
-
87
- @config_cli.command(hidden=True)
88
- @use_settings
89
- def repos_for_github_config(
90
- settings: Settings,
91
- ) -> None:
92
- if not settings.api_key:
93
- redirect_to_login(settings)
94
- return
95
-
96
- run_until_complete(
97
- repos_for_github_config_task(
98
- api_key=settings.api_key,
99
- base_api_url=settings.get_base_api_url(),
100
- base_ws_url=settings.get_base_ws_url(),
101
- )
102
- )
103
-
104
-
105
- async def repos_for_github_config_task(
106
- api_key: str,
107
- base_api_url: str,
108
- base_ws_url: str,
109
- ) -> None:
110
- graphql_client = GraphQLClient(api_key, base_api_url, base_ws_url)
111
- try:
112
- click.echo("Sending request to fetch repos...")
113
- result = await graphql_client.execute(
114
- REPOS_FOR_GITHUB_CONFIG_QUERY, timeout=120
115
- ) # 120 seconds timeout
116
- click.echo("Request completed. Result:")
117
- click.echo(result)
118
- except Exception as e:
119
- click.echo(f"An error occurred while fetching repos: {e!s}")
120
- click.echo(f"Error type: {type(e).__name__}")
121
- # Add more detailed error information if available
122
- if hasattr(e, "response"):
123
- click.echo(f"Response status: {e.response.status_code}")
124
- click.echo(f"Response content: {e.response.text}")
125
-
126
-
127
54
  @config_cli.command(hidden=True)
128
55
  @click.option(
129
56
  "--set-git-warning-disabled",
@@ -389,20 +316,6 @@ async def get_authenticated_user_task(
389
316
  click.echo(it)
390
317
 
391
318
 
392
- async def create_github_config_task(
393
- api_key: str,
394
- base_api_url: str,
395
- base_ws_url: str,
396
- github_pat: str,
397
- ) -> None:
398
- graphql_client = GraphQLClient(api_key, base_api_url, base_ws_url)
399
- variables = {
400
- "githubPat": github_pat,
401
- }
402
- result = await graphql_client.execute(CREATE_GITHUB_CONFIG_MUTATION, variables)
403
- click.echo(result)
404
-
405
-
406
319
  @config_cli.command(hidden=True)
407
320
  @use_settings
408
321
  def refresh_key(settings: Settings) -> None:
@@ -97,7 +97,7 @@ def run(
97
97
  create_chat(api_key, base_api_url, base_ws_url, ChatSource.CLI_RUN)
98
98
  )
99
99
 
100
- if timeout_seconds is not None and timeout_seconds <= 0:
100
+ if isinstance(timeout_seconds, int) and timeout_seconds <= 0:
101
101
  click.secho("Error: --timeout-seconds must be a positive integer", fg="red")
102
102
  sys.exit(1)
103
103
 
@@ -48,6 +48,7 @@ class ToolResult(msgspec.Struct, tag_field="tool_name", omit_defaults=True):
48
48
 
49
49
  class ErrorToolResult(ToolResult, tag="error"):
50
50
  error_message: str
51
+ is_assistant_error: bool = False
51
52
 
52
53
 
53
54
  READ_TOOL_NAME = "read"
@@ -0,0 +1,31 @@
1
+ import os
2
+
3
+
4
+ def get_default_env() -> dict[str, str]:
5
+ """
6
+ Returns default environment variables for CLI-spawned processes.
7
+ These are merged with the parent process environment.
8
+ """
9
+ return {
10
+ "GIT_EDITOR": "true",
11
+ }
12
+
13
+
14
+ def get_process_env(env_overrides: dict[str, str] | None = None) -> dict[str, str]:
15
+ """
16
+ Returns the complete environment for spawned processes.
17
+ Merges parent environment with default variables, then applies overrides.
18
+
19
+ Priority order (lowest to highest):
20
+ 1. Parent process environment (os.environ)
21
+ 2. Default environment variables (get_default_env())
22
+ 3. Explicit overrides (env_overrides parameter)
23
+
24
+ Args:
25
+ env_overrides: Optional dict of environment variables that override defaults
26
+ """
27
+ env = os.environ.copy()
28
+ env.update(get_default_env())
29
+ if env_overrides:
30
+ env.update(env_overrides)
31
+ return env
@@ -6,6 +6,7 @@ import signal
6
6
  from collections.abc import AsyncGenerator, Callable
7
7
  from typing import Any
8
8
 
9
+ from exponent.core.remote_execution.default_env import get_process_env
9
10
  from exponent.core.remote_execution.languages.types import (
10
11
  ShellExecutionResult,
11
12
  StreamedOutputPiece,
@@ -80,6 +81,7 @@ async def execute_shell_streaming( # noqa: PLR0915
80
81
  working_directory: str,
81
82
  timeout: int,
82
83
  should_halt: Callable[[], bool] | None = None,
84
+ env: dict[str, str] | None = None,
83
85
  ) -> AsyncGenerator[StreamedOutputPiece | ShellExecutionResult, None]:
84
86
  timeout_seconds = min(timeout, MAX_TIMEOUT)
85
87
 
@@ -91,6 +93,7 @@ async def execute_shell_streaming( # noqa: PLR0915
91
93
  stdout=asyncio.subprocess.PIPE,
92
94
  stderr=asyncio.subprocess.PIPE,
93
95
  cwd=working_directory,
96
+ env=get_process_env(env),
94
97
  )
95
98
  else:
96
99
  # Add rc file sourcing to the command
@@ -105,6 +108,7 @@ async def execute_shell_streaming( # noqa: PLR0915
105
108
  stdout=asyncio.subprocess.PIPE,
106
109
  stderr=asyncio.subprocess.PIPE,
107
110
  cwd=working_directory,
111
+ env=get_process_env(env),
108
112
  start_new_session=True if platform.system() != "Windows" else False,
109
113
  )
110
114
 
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import logging
2
3
  import uuid
3
4
  from collections.abc import Callable
@@ -109,26 +110,31 @@ async def execute_read_file( # noqa: PLR0911, PLR0915
109
110
  is_image, media_type = is_image_file(tool_input.file_path)
110
111
  if is_image and media_type and upload_client is not None:
111
112
  try:
112
- import aiohttp
113
+ import urllib.request
113
114
 
114
115
  file_name = Path(tool_input.file_path).name
115
116
  s3_key = f"images/{uuid.uuid4()}/{file_name}"
116
117
 
117
118
  upload_response = await upload_client.request_upload_url(s3_key, media_type)
118
119
 
119
- async with aiohttp.ClientSession() as session:
120
- f = await file.open("rb")
121
- async with f:
122
- file_data = await f.read()
123
- async with session.put(
120
+ f = await file.open("rb")
121
+ async with f:
122
+ file_data = await f.read()
123
+
124
+ def _upload() -> int:
125
+ req = urllib.request.Request(
124
126
  upload_response.upload_url,
125
127
  data=file_data,
126
128
  headers={"Content-Type": media_type},
127
- ) as resp:
128
- if resp.status != 200:
129
- raise RuntimeError(
130
- f"Upload failed with status {resp.status}"
131
- )
129
+ method="PUT",
130
+ )
131
+ with urllib.request.urlopen(req) as resp:
132
+ status: int = resp.status
133
+ return status
134
+
135
+ status = await asyncio.to_thread(_upload)
136
+ if status != 200:
137
+ raise RuntimeError(f"Upload failed with status {status}")
132
138
 
133
139
  return ReadToolArtifactResult(
134
140
  s3_uri=upload_response.s3_uri,
@@ -57,7 +57,13 @@ class SlackWorkflowInput(BaseModel):
57
57
  message_ts: str | None = None
58
58
 
59
59
 
60
- WorkflowInput = PrReviewWorkflowInput | SlackWorkflowInput
60
+ class SentryWorkflowInput(BaseModel):
61
+ title: str
62
+ issue_id: str
63
+ permalink: str
64
+
65
+
66
+ WorkflowInput = PrReviewWorkflowInput | SlackWorkflowInput | SentryWorkflowInput
61
67
 
62
68
 
63
69
  class WorkflowTriggerRequest(BaseModel):
@@ -542,6 +548,7 @@ class ChatSource(str, Enum):
542
548
  DESKTOP_APP = "DESKTOP_APP"
543
549
  VSCODE_EXTENSION = "VSCODE_EXTENSION"
544
550
  SLACK_APP = "SLACK_APP"
551
+ SENTRY_APP = "SENTRY_APP"
545
552
 
546
553
 
547
554
  class CLIConnectedState(BaseModel):
@@ -1,56 +0,0 @@
1
- CREATE_GITHUB_CONFIG_MUTATION: str = """
2
- mutation CreateGithubConfig(
3
- $githubPat: String!,
4
- ) {
5
- createGithubConfig(
6
- githubPat: $githubPat
7
- ) {
8
- __typename
9
- ... on GithubConfig {
10
- githubConfigUuid
11
- githubPat
12
- }
13
- }
14
- }
15
- """
16
-
17
- CHECK_GITHUB_CONFIG_VALIDITY_QUERY: str = """
18
- query CheckGithubConfigValidity {
19
- checkGithubConfigValidity {
20
- __typename
21
- ... on GithubConfigValidityResult {
22
- isValid
23
- message
24
- }
25
- ... on Error {
26
- message
27
- }
28
- }
29
- }
30
- """
31
-
32
- REPOS_FOR_GITHUB_CONFIG_QUERY: str = """
33
- query ReposForGithubConfig {
34
- reposForGithubConfig {
35
- __typename
36
- ... on GithubConfigRepos {
37
- repos {
38
- id
39
- name
40
- fullName
41
- private
42
- owner
43
- description
44
- }
45
- orgs {
46
- login
47
- id
48
- url
49
- }
50
- }
51
- ... on Error {
52
- message
53
- }
54
- }
55
- }
56
- """
File without changes
File without changes
File without changes
File without changes