intuned-runtime 1.0.0__py3-none-any.whl → 1.1.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 (78) hide show
  1. intuned_cli/__init__.py +40 -0
  2. intuned_cli/commands/__init__.py +18 -0
  3. intuned_cli/commands/attempt_api_command.py +51 -0
  4. intuned_cli/commands/attempt_authsession_check_command.py +38 -0
  5. intuned_cli/commands/attempt_authsession_command.py +12 -0
  6. intuned_cli/commands/attempt_authsession_create_command.py +44 -0
  7. intuned_cli/commands/attempt_command.py +12 -0
  8. intuned_cli/commands/command.py +26 -0
  9. intuned_cli/commands/deploy_command.py +47 -0
  10. intuned_cli/commands/init_command.py +21 -0
  11. intuned_cli/commands/run_api_command.py +69 -0
  12. intuned_cli/commands/run_authsession_command.py +12 -0
  13. intuned_cli/commands/run_authsession_create_command.py +50 -0
  14. intuned_cli/commands/run_authsession_update_command.py +52 -0
  15. intuned_cli/commands/run_authsession_validate_command.py +49 -0
  16. intuned_cli/commands/run_command.py +12 -0
  17. intuned_cli/constants/__init__.py +1 -0
  18. intuned_cli/constants/readme.py +134 -0
  19. intuned_cli/controller/__test__/__init__.py +0 -0
  20. intuned_cli/controller/__test__/test_api.py +529 -0
  21. intuned_cli/controller/__test__/test_authsession.py +907 -0
  22. intuned_cli/controller/api.py +212 -0
  23. intuned_cli/controller/authsession.py +458 -0
  24. intuned_cli/controller/deploy.py +352 -0
  25. intuned_cli/controller/init.py +97 -0
  26. intuned_cli/types.py +33 -0
  27. intuned_cli/utils/api_helpers.py +32 -0
  28. intuned_cli/utils/auth_session_helpers.py +57 -0
  29. intuned_cli/utils/backend.py +5 -0
  30. intuned_cli/utils/confirmation.py +0 -0
  31. intuned_cli/utils/console.py +6 -0
  32. intuned_cli/utils/error.py +27 -0
  33. intuned_cli/utils/exclusions.py +40 -0
  34. intuned_cli/utils/get_auth_parameters.py +18 -0
  35. intuned_cli/utils/import_function.py +15 -0
  36. intuned_cli/utils/timeout.py +25 -0
  37. {cli → intuned_internal_cli}/__init__.py +1 -1
  38. {cli → intuned_internal_cli}/commands/__init__.py +2 -0
  39. {cli → intuned_internal_cli}/commands/ai_source/deploy.py +1 -1
  40. {cli → intuned_internal_cli}/commands/project/type_check.py +39 -32
  41. intuned_internal_cli/commands/root.py +15 -0
  42. {intuned_runtime-1.0.0.dist-info → intuned_runtime-1.1.0.dist-info}/METADATA +3 -1
  43. intuned_runtime-1.1.0.dist-info/RECORD +96 -0
  44. intuned_runtime-1.1.0.dist-info/entry_points.txt +4 -0
  45. runtime/__init__.py +2 -1
  46. runtime/backend_functions/_call_backend_function.py +0 -5
  47. runtime/browser/__init__.py +2 -1
  48. runtime/browser/launch_chromium.py +68 -49
  49. runtime/browser/storage_state.py +11 -12
  50. runtime/errors/run_api_errors.py +14 -10
  51. runtime/run/playwright_constructs.py +4 -2
  52. runtime/run/pydantic_encoder.py +15 -0
  53. runtime/run/run_api.py +5 -4
  54. runtime/types/run_types.py +16 -0
  55. intuned_runtime-1.0.0.dist-info/RECORD +0 -58
  56. intuned_runtime-1.0.0.dist-info/entry_points.txt +0 -3
  57. {cli → intuned_internal_cli}/commands/ai_source/__init__.py +0 -0
  58. {cli → intuned_internal_cli}/commands/ai_source/ai_source.py +0 -0
  59. {cli → intuned_internal_cli}/commands/browser/__init__.py +0 -0
  60. {cli → intuned_internal_cli}/commands/browser/save_state.py +0 -0
  61. {cli → intuned_internal_cli}/commands/init.py +0 -0
  62. {cli → intuned_internal_cli}/commands/project/__init__.py +0 -0
  63. {cli → intuned_internal_cli}/commands/project/auth_session/__init__.py +0 -0
  64. {cli → intuned_internal_cli}/commands/project/auth_session/check.py +0 -0
  65. {cli → intuned_internal_cli}/commands/project/auth_session/create.py +0 -0
  66. {cli → intuned_internal_cli}/commands/project/auth_session/load.py +0 -0
  67. {cli → intuned_internal_cli}/commands/project/project.py +0 -0
  68. {cli → intuned_internal_cli}/commands/project/run.py +0 -0
  69. {cli → intuned_internal_cli}/commands/project/run_interface.py +0 -0
  70. {cli → intuned_internal_cli}/commands/project/upgrade.py +0 -0
  71. {cli → intuned_internal_cli}/commands/publish_packages.py +0 -0
  72. {cli → intuned_internal_cli}/logger.py +0 -0
  73. {cli → intuned_internal_cli}/utils/ai_source_project.py +0 -0
  74. {cli → intuned_internal_cli}/utils/code_tree.py +0 -0
  75. {cli → intuned_internal_cli}/utils/run_apis.py +0 -0
  76. {cli → intuned_internal_cli}/utils/unix_socket.py +0 -0
  77. {intuned_runtime-1.0.0.dist-info → intuned_runtime-1.1.0.dist-info}/LICENSE +0 -0
  78. {intuned_runtime-1.0.0.dist-info → intuned_runtime-1.1.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,15 @@
1
+ from anyio import Path
2
+
3
+ from runtime.run.run_api import import_function_from_api_dir
4
+ from runtime.run.run_api import ImportFunction
5
+
6
+
7
+ async def get_cli_import_function() -> ImportFunction:
8
+ """
9
+ Import a function from the API directory for CLI usage.
10
+ """
11
+ cwd = await Path().resolve()
12
+
13
+ return lambda file_path, name=None: import_function_from_api_dir(
14
+ file_path=file_path, automation_function_name=name, base_dir=str(cwd)
15
+ )
@@ -0,0 +1,25 @@
1
+ import asyncio
2
+ from contextlib import asynccontextmanager
3
+
4
+ from runtime.context.context import IntunedContext
5
+ from runtime.errors.run_api_errors import AutomationError
6
+
7
+
8
+ @asynccontextmanager
9
+ async def extendable_timeout(timeout: float):
10
+ try:
11
+ async with asyncio.timeout(timeout) as tm:
12
+ existing_extend_timeout = IntunedContext.current().extend_timeout
13
+
14
+ async def extend_timeout():
15
+ tm.reschedule(asyncio.timeout(timeout).when())
16
+ if existing_extend_timeout:
17
+ await existing_extend_timeout()
18
+
19
+ IntunedContext.current().extend_timeout = extend_timeout
20
+ try:
21
+ yield
22
+ finally:
23
+ IntunedContext.current().extend_timeout = existing_extend_timeout
24
+ except asyncio.TimeoutError as e:
25
+ raise AutomationError(Exception("Timed out")) from e
@@ -18,7 +18,7 @@ def run():
18
18
  load_dotenv(dotenv, override=True)
19
19
  try:
20
20
  with IntunedContext():
21
- arguably.run()
21
+ arguably.run(name="intuned-internal")
22
22
  except ValueError as e:
23
23
  print(bold(red(str(e))))
24
24
  sys.exit(1)
@@ -9,6 +9,7 @@ from .project.auth_session import project__auth_session__check # type: ignore
9
9
  from .project.auth_session import project__auth_session__create # type: ignore
10
10
  from .project.auth_session import project__auth_session__load # type: ignore
11
11
  from .publish_packages import publish_packages # type: ignore
12
+ from .root import __root__ # type: ignore
12
13
 
13
14
  __all__ = [
14
15
  "project__run",
@@ -22,4 +23,5 @@ __all__ = [
22
23
  "project__auth_session__check",
23
24
  "project__type_check",
24
25
  "browser__save_state",
26
+ "__root__",
25
27
  ]
@@ -6,7 +6,7 @@ from more_termcolor import cyan # type: ignore
6
6
  from more_termcolor import green # type: ignore
7
7
  from more_termcolor import red # type: ignore
8
8
 
9
- from cli.utils.code_tree import convert_project_to_code_tree
9
+ from intuned_internal_cli.utils.code_tree import convert_project_to_code_tree
10
10
 
11
11
  from ...utils.ai_source_project import AiSourceInfo
12
12
  from ...utils.ai_source_project import deploy_ai_source
@@ -9,6 +9,7 @@ current_dir = os.path.dirname(os.path.abspath(__file__))
9
9
  PYRIGHT_CONFIG_PATH = os.path.join(current_dir, "..", "..", "pyright_type_check.json")
10
10
  PYRIGHT_CONFIG_PATH = os.path.abspath(PYRIGHT_CONFIG_PATH)
11
11
 
12
+
12
13
  @arguably.command # type: ignore
13
14
  async def project__type_check():
14
15
  """
@@ -37,44 +38,50 @@ async def project__type_check():
37
38
  project_dir = os.getcwd()
38
39
  print("📦 Checking Types...")
39
40
 
40
- try:
41
- pyright_issues = []
42
- pyright_result = subprocess.run(
43
- ["pyright", "--outputjson", project_dir, "--project", PYRIGHT_CONFIG_PATH],
44
- capture_output=True,
45
- text=True,
46
- check=False
47
- )
41
+ try:
42
+ pyright_issues = []
43
+ pyright_result = subprocess.run(
44
+ ["pyright", "--outputjson", project_dir, "--project", PYRIGHT_CONFIG_PATH],
45
+ capture_output=True,
46
+ text=True,
47
+ check=False,
48
+ )
49
+
50
+ if pyright_result.stdout:
51
+ pyright_data = json.loads(pyright_result.stdout)
52
+ for diagnostic in pyright_data.get("generalDiagnostics", []):
53
+ severity = diagnostic.get("severity", "").lower()
54
+ severity_emoji = "ℹ️" if severity == "information" else "⚠️" if severity == "warning" else "🔴"
55
+
56
+ pyright_issues.append(
57
+ {
58
+ "path": diagnostic.get("file", ""),
59
+ "line": diagnostic.get("range", {}).get("start", {}).get("line", 0) + 1,
60
+ "severity": diagnostic.get("severity", ""),
61
+ "message": diagnostic.get("message", ""),
62
+ "rule": "type-check",
63
+ }
64
+ )
48
65
 
49
- if pyright_result.stdout:
50
- pyright_data = json.loads(pyright_result.stdout)
51
- for diagnostic in pyright_data.get("generalDiagnostics", []):
52
- severity = diagnostic.get("severity", "").lower()
53
- severity_emoji = "ℹ️" if severity == "information" else "⚠️" if severity == "warning" else "🔴"
54
-
55
- pyright_issues.append(
56
- {"path": diagnostic.get("file", ""), "line": diagnostic.get("range", {}).get("start", {}).get("line", 0) + 1, "severity": diagnostic.get("severity", ""), "message": diagnostic.get("message", ""), "rule": "type-check"}
57
- )
58
-
59
- file_path = diagnostic.get("file", "")
60
- if "api/" in file_path:
61
- file_path = file_path[file_path.index("api/"):]
62
- line_num = diagnostic.get("range", {}).get("start", {}).get("line", 0) + 1
63
- message = diagnostic.get("message", "")
64
- print(f"{severity_emoji} {file_path}:{line_num} - {message}")
65
-
66
- if severity.lower() == "error":
67
- print("\n🔴 Type check failed")
68
- sys.exit(1)
66
+ file_path = diagnostic.get("file", "")
67
+ if "api/" in file_path:
68
+ file_path = file_path[file_path.index("api/") :]
69
+ line_num = diagnostic.get("range", {}).get("start", {}).get("line", 0) + 1
70
+ message = diagnostic.get("message", "")
71
+ print(f"{severity_emoji} {file_path}:{line_num} - {message}")
69
72
 
70
- if pyright_issues:
73
+ if severity.lower() == "error":
74
+ print("\n🔴 Type check failed")
75
+ sys.exit(1)
76
+
77
+ if pyright_issues:
71
78
  has_warnings = any(issue["severity"].lower() == "warning" for issue in pyright_issues)
72
79
  if has_warnings:
73
80
  print("\n⚠️ Type check passed with warnings")
74
81
  sys.exit(0)
75
-
76
- print("✨ Python type checking passed without errors.")
77
- sys.exit(0)
82
+
83
+ print("✨ Python type checking passed without errors.")
84
+ sys.exit(0)
78
85
  except json.JSONDecodeError:
79
86
  print("🔴 Failed to parse pyright output as JSON")
80
87
  sys.exit(1)
@@ -0,0 +1,15 @@
1
+ import arguably
2
+
3
+
4
+ @arguably.command # type: ignore
5
+ async def __root__():
6
+ """Internal Intuned CLI.
7
+
8
+ This command is intended for internal use by Intuned and is not intended for general users.
9
+ Breaking changes and experimental features may be present.
10
+
11
+ If you are not an Intuned developer, please use the main Intuned CLI instead.
12
+ """
13
+ if arguably.is_target():
14
+ print("-h/--help")
15
+ exit(1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: intuned-runtime
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: Runtime commands for Intuned platform Python scrapers
5
5
  License: Elastic-2.0
6
6
  Keywords: runtime,intuned
@@ -24,7 +24,9 @@ Requires-Dist: pathspec (>=0.12.1,<0.13.0)
24
24
  Requires-Dist: pydantic (>=2.10.6,<3.0.0)
25
25
  Requires-Dist: pyright (>=1.1.387,<2.0.0)
26
26
  Requires-Dist: python-dotenv (==1.0.1)
27
+ Requires-Dist: pytimeparse (>=1.1.8,<2.0.0)
27
28
  Requires-Dist: requests (>=2.32.3,<3.0.0)
29
+ Requires-Dist: rich (>=14.1.0,<15.0.0)
28
30
  Requires-Dist: ruff (>=0.7.2,<0.8.0)
29
31
  Requires-Dist: semver (>=3.0.4,<4.0.0)
30
32
  Requires-Dist: tenacity (>=8.5.0,<9.0.0)
@@ -0,0 +1,96 @@
1
+ intuned_cli/__init__.py,sha256=SNcUoVkqPTmIxjEsp05GZBKaAzgCt-rBkvkzndjpfPo,1124
2
+ intuned_cli/commands/__init__.py,sha256=qndefhU1fGHYYu7f7wxcv03F27NPMIwsxUd3K-fmOD8,1236
3
+ intuned_cli/commands/attempt_api_command.py,sha256=f4Oi8vjNzGLMgk_1XXO5KzOIAw9sq9N8A62d3QIZxso,1954
4
+ intuned_cli/commands/attempt_authsession_check_command.py,sha256=RdKRltXIp51wnXamRB1Xr45TUBUs1AQCmAzW8tMQnxo,1334
5
+ intuned_cli/commands/attempt_authsession_command.py,sha256=hir9y1XyW9VYioOWT6C1-dH43f3JcHhIlfEEijMg2Lc,277
6
+ intuned_cli/commands/attempt_authsession_create_command.py,sha256=ynAKlNoHuaVPgx4gv2AJquIt7ZVIe8Nh1IIHwNiDeNA,1708
7
+ intuned_cli/commands/attempt_command.py,sha256=7NZC2dXA8GViCH3ZS2PMziR43hv2RmS6-jgW7l9bu40,253
8
+ intuned_cli/commands/command.py,sha256=b0OlQIFhoCjCo5QIerfysccBKcU9iIsvqiU7oxshA2M,727
9
+ intuned_cli/commands/deploy_command.py,sha256=0XG8lo5fGeorZMxMtEx12EaqLFMvmFYJ7Zu9sgJCmQ8,1540
10
+ intuned_cli/commands/init_command.py,sha256=MV5WR5o4KH1J_Zai6K5S84NG41KZbsJ-I8NPGXurt2o,671
11
+ intuned_cli/commands/run_api_command.py,sha256=Y6FkSFI9wybuoW204YqOAiQ794__hIw12Eaf9px_ovE,3013
12
+ intuned_cli/commands/run_authsession_command.py,sha256=kM_TANy8M3yx8iBUsgSDO42byzccikLOd9KJfytfLmQ,269
13
+ intuned_cli/commands/run_authsession_create_command.py,sha256=SiuIZ7LTMqT3gnd8DUt-VmP3cyuA0I_i27daI3IJ2tw,2089
14
+ intuned_cli/commands/run_authsession_update_command.py,sha256=Op7epDgvEhjp17qs2dIXerTckHz7wlOsZsBDp8UJLjI,2145
15
+ intuned_cli/commands/run_authsession_validate_command.py,sha256=5eET02paijq1f1rzsheINvAqVYj1JGUA_iGD5Py3LVM,2008
16
+ intuned_cli/commands/run_command.py,sha256=JN1yCewcyb4zFquMcv0wEZ_aRmhJZIBMheY8L9yBeDE,245
17
+ intuned_cli/constants/__init__.py,sha256=AIfIQYQ55zSdGKL2p15wv4H9ANeRjYEkeUiObu6JFt8,37
18
+ intuned_cli/constants/readme.py,sha256=3OUkZNmz9kss7hA3V2j5h49dv7ADy4LON5-iJkrJUA4,5240
19
+ intuned_cli/controller/__test__/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ intuned_cli/controller/__test__/test_api.py,sha256=8Hk3V52qKhWIqjirKFwN68Tv5er70gTxemjI35HyZiU,19295
21
+ intuned_cli/controller/__test__/test_authsession.py,sha256=y7O3dkDPHZTf2W7WRLEhysYYRati0hg93-J8BvGjRUM,35110
22
+ intuned_cli/controller/api.py,sha256=1wHgatavA5zr6kYMf1BJ3lC5JR1IvlVBiab_ahOSVnY,7172
23
+ intuned_cli/controller/authsession.py,sha256=z8C97T-beEORNemLFx2x_JsHr2gXRakwKGV3Rgivnu8,14309
24
+ intuned_cli/controller/deploy.py,sha256=5cQgtpT2nDQ5XSUnIoeBR9xdyVoLWcY-2btuUxUD7Es,12343
25
+ intuned_cli/controller/init.py,sha256=TfkPkq9rbYam2-fchwrpMIt9GJIkY-TQnWpwvPomRZE,3774
26
+ intuned_cli/types.py,sha256=Lsykui4mbq5T1_1L7Gg5OZpJvCOmaz9EiQcZVfUEoLc,766
27
+ intuned_cli/utils/api_helpers.py,sha256=57gvXVYM_9hMGIkMqSEN_jzs3mYWlXzinPjYXzzqgg8,1122
28
+ intuned_cli/utils/auth_session_helpers.py,sha256=acKAPUjOfdybstLur4Lk3huaLFP2Ipl4AjPSqQPQLzY,1899
29
+ intuned_cli/utils/backend.py,sha256=NFMAqHFslxad9KYirUz3b0BsRz1aQqOGhZRUJdEiO8k,106
30
+ intuned_cli/utils/confirmation.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ intuned_cli/utils/console.py,sha256=jgin2xB-0kpANPMoiDBOnWhrc8Ey5zT4IHRxQa8f5CQ,93
32
+ intuned_cli/utils/error.py,sha256=DmNlXBb7zfpHDRya00ouEcRgUEZuGaTqIy1SIjDWVfo,842
33
+ intuned_cli/utils/exclusions.py,sha256=Qe7NkWA3lsX73dOC9WprdD0KyYc_vuiwkrUCwD105gk,796
34
+ intuned_cli/utils/get_auth_parameters.py,sha256=HmMSjBE8bPulkUdX319Ipr383Ko2Gtz3y8_WT9CK3Kw,798
35
+ intuned_cli/utils/import_function.py,sha256=UmE2yw5std1ENMFdBU-TUBuQ01qsv7Qr5ElnAhqE6Yc,453
36
+ intuned_cli/utils/timeout.py,sha256=DkoeoU9XvKKKSQ06CpwqcNvxWqLPAOVuAMw6kSr4Tuo,886
37
+ intuned_internal_cli/__init__.py,sha256=iz-mTdcPhNCknHZzdO5-9PHFSapbXiLCwg_cTaYfww4,1337
38
+ intuned_internal_cli/commands/__init__.py,sha256=gZ-r8UIXvRakeCfvmOZCNWr8CJHBcYzRzbMjyKYPXV0,1003
39
+ intuned_internal_cli/commands/ai_source/__init__.py,sha256=lg7owgcK8owNn2a4VBUP9RKxzFsLruhtnnQV0F_z6pc,149
40
+ intuned_internal_cli/commands/ai_source/ai_source.py,sha256=2woQtCmhxKvLfEz832eUoCT9gMsuSvEE6rMnHSYXC7w,138
41
+ intuned_internal_cli/commands/ai_source/deploy.py,sha256=NpomuP_2mo5SLKe7BZoY5H0Pp36aDtkYU_CyihqOvdI,2457
42
+ intuned_internal_cli/commands/browser/__init__.py,sha256=AuVbvh7aSBTFKYvewXZyPoIvfBTe2uHiPcnaAkzapas,95
43
+ intuned_internal_cli/commands/browser/save_state.py,sha256=eHKfvBfeFR_U9VQbsjOnIZjWepyDjNn9NL3naDYWP2s,841
44
+ intuned_internal_cli/commands/init.py,sha256=8rWBenWZfwNtLxOBqhEMbOATyQNEnmDUmrFJ1xBGyxI,4384
45
+ intuned_internal_cli/commands/project/__init__.py,sha256=t97wvhSenerYRdbSeCKXqHASA6EWA3lc1hnRhF9baOE,734
46
+ intuned_internal_cli/commands/project/auth_session/__init__.py,sha256=gt7mlaW6xmqAc_4-pfF_FiecsR51C6fqCaq_NFbcbwA,300
47
+ intuned_internal_cli/commands/project/auth_session/check.py,sha256=AFILp7m34nAO_RD3IfRpuJm5Zh0wnCRtBXqIrerdbwo,4565
48
+ intuned_internal_cli/commands/project/auth_session/create.py,sha256=r-eYu3uLUo2mzF836CbVgu4oBzcIIDekzzFwwekxmg0,3374
49
+ intuned_internal_cli/commands/project/auth_session/load.py,sha256=UUvg9Vyj15xiR44XlJzojLoFm5esv-o4E3qA3JqnBsE,1201
50
+ intuned_internal_cli/commands/project/project.py,sha256=_MSh6Xor2Cbh-ItifwgOPq_BP8UDuKB7S6w796FULKQ,137
51
+ intuned_internal_cli/commands/project/run.py,sha256=FDYYkU24aURYbljyYLFo8wLF-nvb86EVr9gMEjAfeE0,12274
52
+ intuned_internal_cli/commands/project/run_interface.py,sha256=4RyR8WZriIF7Va4z1wt-q6zZDQOI31n62Ho2dyimzUY,8717
53
+ intuned_internal_cli/commands/project/type_check.py,sha256=QFnXL93Y-z250EQRln5sRqwkVqjGJ-eP_p1jGrXB7NA,3522
54
+ intuned_internal_cli/commands/project/upgrade.py,sha256=XmkZLflM4O-mwvhwcswlZpazRotwi3xesLgE0Zz8fTI,3061
55
+ intuned_internal_cli/commands/publish_packages.py,sha256=sijkaG7_s0I1EWgLekGy1qm8Aqi_gYY8poXbMX0B6Yw,10505
56
+ intuned_internal_cli/commands/root.py,sha256=o75rSb5WYa5JMD8HLN3eiNu4fM0mar3y15A63-Qm4s4,426
57
+ intuned_internal_cli/logger.py,sha256=bZK3q-KUdGxk_qzDb6pn-n0LOhKJvi6a9p8oSwZtq3s,594
58
+ intuned_internal_cli/utils/ai_source_project.py,sha256=xUCM6p3i1XN4bJbuQz8LCzeI4BwqAdSvCl_vwDAEi0k,831
59
+ intuned_internal_cli/utils/code_tree.py,sha256=1wfxZoQ5kRCfqs2SEPAicbAIPTiD6P1LxSuwYu_eeaI,2790
60
+ intuned_internal_cli/utils/run_apis.py,sha256=Zee4zkgt9R8XY1XCGzj2Nc4zJ3jlRz1xnO493wotuWw,4690
61
+ intuned_internal_cli/utils/unix_socket.py,sha256=UISmkJMHrir5iBLUm6vxC3uzTGIFyOk_wa0C9LUw4Cc,1889
62
+ runtime/__init__.py,sha256=87gDXuxUv_kGzQfuB1mh6DF-dDysJN8r684c7jGnHxc,144
63
+ runtime/backend_functions/__init__.py,sha256=j2EaK4FK8bmdFtqc5FxtFwx1KhIn_7qKPChrrAhJI3s,119
64
+ runtime/backend_functions/_call_backend_function.py,sha256=zuaf4mwYHSm5RTedhMdU66jAMAzdPYPMmXJE_V1xoyk,2869
65
+ runtime/backend_functions/get_auth_session_parameters.py,sha256=pOvB7XiWpphEuBpazdKALw9EWgBU1PeY3gkzBfVLpkc,869
66
+ runtime/browser/__init__.py,sha256=CRBpMS319LBz2FLxDjjCvQdOUCgHLIrQFscr_Zi5Hm0,160
67
+ runtime/browser/launch_chromium.py,sha256=OVaE8ezjxCYA1NUSDdd3FczrfNCpG_528Vmsv4S6QGU,7916
68
+ runtime/browser/storage_state.py,sha256=fwLg8sP-H-vgt_6AJKNl03CpgyMVCQWWcN2cqswTQMs,3603
69
+ runtime/context/__init__.py,sha256=hg8ejm4bJy4tNkwmZ9lKgYJx6bU7OgOdBS684Uv5XGg,73
70
+ runtime/context/context.py,sha256=pl_0x77_d5CiAznz1qGSk6o9cW-msNvlCt-2eFoMKlA,1739
71
+ runtime/env.py,sha256=h4BJI-XVSZKgtTxjkzj2HsyN3DlY5Ml9GZqeH4CKDE8,238
72
+ runtime/errors/__init__.py,sha256=oqiBSvT_yFLQ3hG0AbCUA3WYFaxkTDVkDMSy59xvBCo,688
73
+ runtime/errors/auth_session_errors.py,sha256=6b4XTI8UCDHDPX4jEA8_HyrNUp4VZ1TrEA8DRh6Z3rM,228
74
+ runtime/errors/run_api_errors.py,sha256=LdmOEHoUk7wjWSk0HQYqslfJNNmxVgga_0bankzvX-s,3341
75
+ runtime/errors/trace_errors.py,sha256=Lzfo0sH3zGaWz1kn5DHcAXQMn3aR2y2bnauj6xP1LYE,110
76
+ runtime/helpers/__init__.py,sha256=jozYPKHgZJ7Na5U1Wjt83egzjPATMZ_OMInEI6swSbY,234
77
+ runtime/helpers/extend_payload.py,sha256=towZF08WTpTTDBL4AV1bUU3XpKAQHEB66kGUfTICDe0,246
78
+ runtime/helpers/extend_timeout.py,sha256=KjfSLEUrqoz7v00rhnPAKq2OmUzEzcv-eQ3M8c2U46s,348
79
+ runtime/helpers/get_auth_session_parameters.py,sha256=7bopGhJ7vjKAn_UxnHSAah-k2rVOPbq0zi9FQOOCFds,472
80
+ runtime/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
+ runtime/run/__init__.py,sha256=zxMYVb7hn147YTrhMLsrcX6-KTd71HLrYHstJOWeWXQ,52
82
+ runtime/run/intuned_settings.py,sha256=vy2-ktEzUfUp5Z90dp3l7jPKHNjgB-8GSMDgAY-rYaU,1074
83
+ runtime/run/playwright_constructs.py,sha256=UZvP502fk4Hk8xtI9jMlyJ7jHLJsWt2SZyZjhet7L1A,576
84
+ runtime/run/pydantic_encoder.py,sha256=wJCljwwINSICvCJ0i2izp2RLkQ15nYglUQCyyjM40Jk,332
85
+ runtime/run/run_api.py,sha256=iYekBi-mkBuBNvLIBXQ6RWvEDN7JhjSlX3i7a2td2P8,8952
86
+ runtime/run/traces.py,sha256=fKzh11LqV47ujgq_9I2tdp-dgld566wffWaHwU_4gis,1123
87
+ runtime/types/__init__.py,sha256=IJkDfqsau8F8R_j8TO6j-JwW4ElQr6aU6LNaWRehg5U,401
88
+ runtime/types/payload.py,sha256=sty8HgDEn3nJbZrwEOMCXyuG7_ICGDwlBIIWSON5ABY,124
89
+ runtime/types/run_types.py,sha256=-j-XKXfRkzlyoW-Doe0og2jbqMMQWjOTIUqRFEc8lHA,4582
90
+ runtime_helpers/__init__.py,sha256=XBrEiE9yNC8Lgn8NgIkqNXbI6e4ap237E83Zj_nlhCQ,249
91
+ runtime_helpers/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
+ intuned_runtime-1.1.0.dist-info/LICENSE,sha256=9LIjQdgyU_ptzNIfItNCR7VmEHqYnrY1f1XwOreKFI0,3714
93
+ intuned_runtime-1.1.0.dist-info/METADATA,sha256=SO-KZ2dpNlLDzqEQBZcOMC8_oie3r2wyw2D9ZSigXWQ,5217
94
+ intuned_runtime-1.1.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
95
+ intuned_runtime-1.1.0.dist-info/entry_points.txt,sha256=ToMS2cqDeRmF1FGkflwoeD-Xz6jJV5p1zIbw9G7IxMg,85
96
+ intuned_runtime-1.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ [console_scripts]
2
+ intuned=intuned_cli:run
3
+ intuned-internal=intuned_internal_cli:run
4
+
runtime/__init__.py CHANGED
@@ -1,3 +1,4 @@
1
- from .browser import launch_chromium, dangerous_launch_chromium
1
+ from .browser import dangerous_launch_chromium
2
+ from .browser import launch_chromium
2
3
 
3
4
  __all__ = ["launch_chromium", "dangerous_launch_chromium"]
@@ -32,11 +32,6 @@ async def call_backend_function[T: BaseModel](
32
32
  # todo
33
33
  raise Exception("No run context found.")
34
34
 
35
- auth_session_id = context.run_context.auth_session_id
36
- if auth_session_id is None:
37
- # todo
38
- raise Exception("No auth session ID found.")
39
-
40
35
  async with AsyncClient() as client:
41
36
  if context.functions_token:
42
37
  client.headers["Authorization"] = f"Bearer {context.functions_token}"
@@ -1,3 +1,4 @@
1
- from .launch_chromium import launch_chromium, dangerous_launch_chromium
1
+ from .launch_chromium import dangerous_launch_chromium
2
+ from .launch_chromium import launch_chromium
2
3
 
3
4
  __all__ = ["launch_chromium", "dangerous_launch_chromium"]
@@ -1,21 +1,21 @@
1
+ import asyncio
1
2
  import json
3
+ import logging
2
4
  import os
3
- import tempfile
4
5
  from contextlib import asynccontextmanager
5
- from os.path import join
6
6
  from typing import Any
7
7
  from typing import Optional
8
- from typing import Literal
9
- import logging
10
- import aiofiles
11
- from playwright.async_api import async_playwright
12
- from playwright.async_api import Browser
13
- from playwright.async_api import ProxySettings
8
+ from typing import TYPE_CHECKING
9
+
10
+ import anyio
11
+
12
+ if TYPE_CHECKING:
13
+ from playwright.async_api import ProxySettings
14
14
 
15
15
  logger = logging.getLogger(__name__)
16
16
 
17
17
 
18
- def get_proxy_env() -> Optional[ProxySettings]:
18
+ def get_proxy_env() -> Optional["ProxySettings"]:
19
19
  server = os.getenv("PROXY_SERVER")
20
20
  username = os.getenv("PROXY_USERNAME")
21
21
  password = os.getenv("PROXY_PASSWORD")
@@ -64,12 +64,12 @@ chromium_launch_args_to_ignore = [
64
64
 
65
65
  async def create_user_dir_with_preferences():
66
66
  # Create a temporary directory
67
- playwright_temp_dir = tempfile.mkdtemp(prefix="pw-")
68
- user_dir = join(playwright_temp_dir, "userdir")
69
- default_dir = join(user_dir, "Default")
67
+ playwright_temp_dir = anyio.Path(await anyio.mkdtemp(prefix="pw-"))
68
+ user_dir = playwright_temp_dir / "userdir"
69
+ default_dir = user_dir / "Default"
70
70
 
71
71
  # Create the default directory recursively
72
- os.makedirs(default_dir, exist_ok=True)
72
+ await default_dir.mkdir(parents=True, exist_ok=True)
73
73
 
74
74
  # Preferences data
75
75
  preferences = {
@@ -79,10 +79,10 @@ async def create_user_dir_with_preferences():
79
79
  }
80
80
 
81
81
  # Write preferences to file
82
- async with aiofiles.open(join(default_dir, "Preferences"), mode="w") as f:
82
+ async with await (default_dir / "Preferences").open("w") as f:
83
83
  await f.write(json.dumps(preferences))
84
84
 
85
- return os.path.abspath(user_dir)
85
+ return await user_dir.absolute(), await playwright_temp_dir.absolute()
86
86
 
87
87
 
88
88
  extra_args = [
@@ -95,7 +95,9 @@ extra_args = [
95
95
  "--disable-blink-features=AutomationControlled",
96
96
  ]
97
97
 
98
- default_user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
98
+ default_user_agent = (
99
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
100
+ )
99
101
 
100
102
 
101
103
  @asynccontextmanager
@@ -105,13 +107,17 @@ async def launch_chromium(
105
107
  cdp_address: str | None = None,
106
108
  **kwargs: Any,
107
109
  ):
110
+ from playwright.async_api import async_playwright
111
+ from playwright.async_api import Browser
112
+
108
113
  async with async_playwright() as playwright:
109
114
  if cdp_address is not None:
110
115
  browser: Browser = await playwright.chromium.connect_over_cdp(cdp_address)
111
116
  context = browser.contexts[0]
112
- dir = None
117
+ user_preferences_dir = None
118
+ dir_to_clean = None
113
119
  else:
114
- dir = await create_user_dir_with_preferences()
120
+ user_preferences_dir, dir_to_clean = await create_user_dir_with_preferences()
115
121
  if kwargs.get("proxy") is None:
116
122
  proxy_env = get_proxy_env()
117
123
  else:
@@ -126,7 +132,7 @@ async def launch_chromium(
126
132
  extra_args.append("--headless=new")
127
133
 
128
134
  context = await playwright.chromium.launch_persistent_context(
129
- dir,
135
+ os.fspath(user_preferences_dir),
130
136
  headless=headless,
131
137
  viewport=viewport,
132
138
  proxy=proxy_env,
@@ -138,9 +144,19 @@ async def launch_chromium(
138
144
  context.set_default_timeout(timeout * 1000)
139
145
 
140
146
  async def remove_dir_after_close(*_: Any, **__: Any) -> None:
141
- if not dir:
147
+ if not dir_to_clean:
148
+ return
149
+ if not await dir_to_clean.exists():
142
150
  return
143
- os.system(f"rm -rf {os.path.realpath(dir)}")
151
+
152
+ process = await asyncio.create_subprocess_exec(
153
+ "rm",
154
+ "-rf",
155
+ os.fspath(dir_to_clean), # Using subprocess to remove the directory
156
+ stdout=asyncio.subprocess.DEVNULL,
157
+ stderr=asyncio.subprocess.DEVNULL,
158
+ )
159
+ await process.wait()
144
160
 
145
161
  context.once("close", remove_dir_after_close)
146
162
  yield context, context.pages[0]
@@ -149,31 +165,25 @@ async def launch_chromium(
149
165
  async def dangerous_launch_chromium(
150
166
  headless: bool = True,
151
167
  timeout: int = 10,
152
- web_socket: str | None = None,
153
168
  cdp_url: str | None = None,
154
- connection_method: Literal["ws", "cdp"] | None = None,
169
+ port: int | None = None,
155
170
  **kwargs: Any,
156
171
  ):
172
+ from playwright.async_api import async_playwright
173
+ from playwright.async_api import Browser
174
+
157
175
  playwright = await async_playwright().start()
158
- if web_socket is not None and connection_method == "ws":
159
- logging.info(f"Connecting to ws: {web_socket}")
160
- browser: Browser = await playwright.chromium.connect(web_socket)
161
- browser.on("disconnected", lambda: logging.info("Browser Session disconnected"))
162
- await browser.new_context(
163
- viewport={"width": 1280, "height": 800}, user_agent=default_user_agent
164
- )
165
- context = browser.contexts[0]
166
- dir = None
167
- elif cdp_url is not None and connection_method == "cdp":
176
+ if cdp_url is not None:
168
177
  logging.info(f"Connecting to cdp: {cdp_url}")
169
178
  browser: Browser = await playwright.chromium.connect_over_cdp(cdp_url)
170
- browser.on("disconnected", lambda: logging.info("Browser Session disconnected"))
179
+ browser.on("disconnected", lambda _: logging.info("Browser Session disconnected"))
171
180
  context = browser.contexts[0]
172
- dir = None
173
- elif web_socket is None and cdp_url is None and connection_method is None:
181
+ user_preferences_dir = None
182
+ dir_to_clean = None
183
+ else:
174
184
  logging.info("Launching local browser")
175
- dir = await create_user_dir_with_preferences()
176
- logging.info(f"Using user data directory: {dir}")
185
+ user_preferences_dir, dir_to_clean = await create_user_dir_with_preferences()
186
+ logging.info(f"Using user data directory: {user_preferences_dir}")
177
187
  if kwargs.get("proxy") is None:
178
188
  proxy_env = get_proxy_env()
179
189
  else:
@@ -187,8 +197,11 @@ async def dangerous_launch_chromium(
187
197
  chromium_launch_args_to_ignore.append("--headless")
188
198
  extra_args.append("--headless=new")
189
199
 
200
+ if port:
201
+ extra_args.append(f"--remote-debugging-port={port}")
202
+
190
203
  context = await playwright.chromium.launch_persistent_context(
191
- dir,
204
+ os.fspath(user_preferences_dir),
192
205
  headless=headless,
193
206
  viewport=viewport,
194
207
  proxy=proxy_env,
@@ -197,16 +210,22 @@ async def dangerous_launch_chromium(
197
210
  args=extra_args,
198
211
  **kwargs,
199
212
  )
200
- else:
201
- raise ValueError(
202
- "You have to provide method if you are launching a remote browser with ws or cdp"
203
- )
204
- context.set_default_timeout(timeout * 1000)
213
+ context.set_default_timeout(timeout * 1000)
205
214
 
206
- async def remove_dir_after_close(*_: Any, **__: Any) -> None:
207
- if not dir:
208
- return
209
- os.system(f"rm -rf {os.path.realpath(dir)}")
215
+ async def remove_dir_after_close(*_: Any, **__: Any) -> None:
216
+ if not dir_to_clean:
217
+ return
218
+ if not await dir_to_clean.exists():
219
+ return
210
220
 
211
- context.once("close", remove_dir_after_close)
221
+ process = await asyncio.create_subprocess_exec(
222
+ "rm",
223
+ "-rf",
224
+ os.fspath(dir_to_clean), # Using subprocess to remove the directory
225
+ stdout=asyncio.subprocess.DEVNULL,
226
+ stderr=asyncio.subprocess.DEVNULL,
227
+ )
228
+ await process.wait()
229
+
230
+ context.once("close", remove_dir_after_close)
212
231
  return playwright, context
@@ -1,23 +1,22 @@
1
1
  from typing import Any
2
+ from typing import TYPE_CHECKING
2
3
 
3
- from playwright.async_api import BrowserContext
4
- from playwright.async_api import Error as PlaywrightError
4
+ if TYPE_CHECKING:
5
+ from playwright.async_api import BrowserContext
6
+
7
+ import logging
5
8
 
6
9
  from ..types.run_types import Cookie
7
10
  from ..types.run_types import Origin
8
11
  from ..types.run_types import SessionStorageOrigin
9
12
  from ..types.run_types import StorageState
10
13
 
11
- import logging
12
-
13
14
  logger = logging.getLogger(__name__)
14
15
 
15
16
 
16
- async def set_storage_state(context: BrowserContext, state: StorageState):
17
+ async def set_storage_state(context: "BrowserContext", state: StorageState):
17
18
  # Add cookies if they exist
18
- await context.add_cookies(
19
- [cookie.model_dump(by_alias=True) for cookie in state.cookies]
20
- ) # type: ignore
19
+ await context.add_cookies([cookie.model_dump(by_alias=True) for cookie in state.cookies]) # type: ignore
21
20
 
22
21
  # Apply localStorage for each origin
23
22
  page = await context.new_page()
@@ -67,7 +66,9 @@ async def set_storage_state(context: BrowserContext, state: StorageState):
67
66
  await page.close()
68
67
 
69
68
 
70
- async def get_storage_state(context: BrowserContext) -> StorageState:
69
+ async def get_storage_state(context: "BrowserContext") -> StorageState:
70
+ from playwright.async_api import Error as PlaywrightError
71
+
71
72
  storage_state = await context.storage_state()
72
73
  cookies = storage_state.get("cookies") or []
73
74
  origins = storage_state.get("origins") or []
@@ -92,9 +93,7 @@ async def get_storage_state(context: BrowserContext) -> StorageState:
92
93
  session_storage.append(SessionStorageOrigin(**session_data))
93
94
  except PlaywrightError as e:
94
95
  if "SecurityError" in e.message:
95
- logger.warning(
96
- f"Could not get storage state for page due '{page.url}' to security error."
97
- )
96
+ logger.warning(f"Could not get storage state for page due '{page.url}' to security error.")
98
97
  continue
99
98
  raise e
100
99
 
@@ -66,22 +66,30 @@ class AutomationNotCoroutineError(RunApiError):
66
66
 
67
67
 
68
68
  class AutomationError(RunApiError):
69
- def __init__(self, exception: BaseException):
69
+ _error: BaseException
70
+
71
+ def __init__(self, error: BaseException):
70
72
  # Get all public attributes of the exception
71
- error_props = {key: str(value) for key, value in exception.__dict__.items() if not key.startswith("_")}
73
+ error_props = {key: str(value) for key, value in error.__dict__.items() if not key.startswith("_")}
72
74
 
73
75
  super().__init__(
74
- str(exception),
76
+ str(error),
75
77
  "AutomationError",
76
78
  )
77
79
 
80
+ self._error = error
81
+
78
82
  self.details = {
79
83
  "error_props": error_props,
80
- "error_type": exception.__class__.__name__,
81
- "name": exception.__class__.__name__,
82
- "message": str(exception),
84
+ "error_type": error.__class__.__name__,
85
+ "name": error.__class__.__name__,
86
+ "message": str(error),
83
87
  }
84
88
 
89
+ @property
90
+ def error(self) -> BaseException:
91
+ return self._error
92
+
85
93
 
86
94
  class AutomationTimeoutError(RunApiError):
87
95
  def __init__(self):
@@ -111,10 +119,6 @@ class InternalInvalidInputError(RunApiError):
111
119
  def __init__(self, message: str, details: Any | None = None):
112
120
  super().__init__(
113
121
  f"Internal error: {message}. Please report this issue to the Intuned team.",
114
- RunApiResponse(
115
- status_code=500,
116
- response={"error": "Internal error", "message": f"Internal error: {message}"},
117
- ),
118
122
  "InternalInvalidInputError",
119
123
  )
120
124
  self.details = details