seedcode-cli 6.1.5__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 (114) hide show
  1. seedcode/__init__.py +14 -0
  2. seedcode/__main__.py +12 -0
  3. seedcode/app.py +508 -0
  4. seedcode/apps/__init__.py +32 -0
  5. seedcode/apps/discovery.py +241 -0
  6. seedcode/apps/installer.py +164 -0
  7. seedcode/apps/launcher.py +156 -0
  8. seedcode/apps/verifier.py +119 -0
  9. seedcode/assets/logo.txt +15 -0
  10. seedcode/cli.py +95 -0
  11. seedcode/commands/__init__.py +81 -0
  12. seedcode/commands/about.py +34 -0
  13. seedcode/commands/agent.py +94 -0
  14. seedcode/commands/assist.py +201 -0
  15. seedcode/commands/clear.py +20 -0
  16. seedcode/commands/desktop.py +104 -0
  17. seedcode/commands/doctor.py +152 -0
  18. seedcode/commands/help.py +61 -0
  19. seedcode/commands/history.py +365 -0
  20. seedcode/commands/palette.py +100 -0
  21. seedcode/commands/provider.py +451 -0
  22. seedcode/commands/theme.py +76 -0
  23. seedcode/computer/__init__.py +98 -0
  24. seedcode/computer/browser.py +276 -0
  25. seedcode/computer/browser_cdp.py +567 -0
  26. seedcode/computer/browser_engine.py +546 -0
  27. seedcode/computer/browser_extract.py +301 -0
  28. seedcode/computer/browser_popups.py +329 -0
  29. seedcode/computer/browser_selenium.py +209 -0
  30. seedcode/computer/browser_skills.py +245 -0
  31. seedcode/computer/catalog.py +200 -0
  32. seedcode/computer/controller.py +324 -0
  33. seedcode/computer/dispatcher.py +272 -0
  34. seedcode/computer/dpi.py +185 -0
  35. seedcode/computer/engine.py +105 -0
  36. seedcode/computer/keyboard.py +101 -0
  37. seedcode/computer/logbook.py +104 -0
  38. seedcode/computer/mouse.py +48 -0
  39. seedcode/computer/ocr.py +213 -0
  40. seedcode/computer/operator_skills.py +577 -0
  41. seedcode/computer/permissions.py +203 -0
  42. seedcode/computer/recovery.py +115 -0
  43. seedcode/computer/registry.py +107 -0
  44. seedcode/computer/resolver.py +434 -0
  45. seedcode/computer/screen.py +130 -0
  46. seedcode/computer/screen_state.py +412 -0
  47. seedcode/computer/selfguard.py +197 -0
  48. seedcode/computer/semantic.py +100 -0
  49. seedcode/computer/skills.py +139 -0
  50. seedcode/computer/state.py +199 -0
  51. seedcode/computer/verifier.py +177 -0
  52. seedcode/computer/vision.py +327 -0
  53. seedcode/computer/windows.py +217 -0
  54. seedcode/config/__init__.py +8 -0
  55. seedcode/config/defaults.py +22 -0
  56. seedcode/config/manager.py +62 -0
  57. seedcode/core/__init__.py +31 -0
  58. seedcode/core/agent.py +534 -0
  59. seedcode/core/chat.py +128 -0
  60. seedcode/core/client.py +9 -0
  61. seedcode/core/errors.py +199 -0
  62. seedcode/core/identity.py +66 -0
  63. seedcode/core/identity_store.py +119 -0
  64. seedcode/core/lifecycle.py +240 -0
  65. seedcode/core/limits.py +35 -0
  66. seedcode/core/models.py +347 -0
  67. seedcode/core/project.py +96 -0
  68. seedcode/core/providers/__init__.py +58 -0
  69. seedcode/core/providers/aerolink.py +324 -0
  70. seedcode/core/providers/base.py +230 -0
  71. seedcode/core/providers/freemodel.py +931 -0
  72. seedcode/core/providers/ollama.py +262 -0
  73. seedcode/core/providers/openrouter.py +393 -0
  74. seedcode/core/streaming.py +21 -0
  75. seedcode/memory/__init__.py +8 -0
  76. seedcode/memory/manager.py +47 -0
  77. seedcode/memory/storage.py +38 -0
  78. seedcode/memory/store.py +257 -0
  79. seedcode/tools/__init__.py +35 -0
  80. seedcode/tools/base.py +179 -0
  81. seedcode/tools/desktop.py +371 -0
  82. seedcode/tools/filesystem.py +309 -0
  83. seedcode/tools/git.py +72 -0
  84. seedcode/tools/patch.py +170 -0
  85. seedcode/tools/permissions.py +288 -0
  86. seedcode/tools/search.py +137 -0
  87. seedcode/tools/terminal.py +200 -0
  88. seedcode/tools/textio.py +59 -0
  89. seedcode/ui/__init__.py +164 -0
  90. seedcode/ui/badges.py +64 -0
  91. seedcode/ui/banner.py +78 -0
  92. seedcode/ui/dashboard.py +197 -0
  93. seedcode/ui/dialog.py +62 -0
  94. seedcode/ui/fuzzy.py +128 -0
  95. seedcode/ui/layout.py +54 -0
  96. seedcode/ui/menu.py +61 -0
  97. seedcode/ui/palette.py +40 -0
  98. seedcode/ui/progress.py +41 -0
  99. seedcode/ui/prompts.py +16 -0
  100. seedcode/ui/renderer.py +36 -0
  101. seedcode/ui/searchbox.py +70 -0
  102. seedcode/ui/selector.py +514 -0
  103. seedcode/ui/statusbar.py +38 -0
  104. seedcode/ui/textbox.py +61 -0
  105. seedcode/ui/theme.py +204 -0
  106. seedcode/ui/tree.py +91 -0
  107. seedcode/utils/__init__.py +22 -0
  108. seedcode/utils/helpers.py +97 -0
  109. seedcode/utils/logger.py +65 -0
  110. seedcode_cli-6.1.5.dist-info/METADATA +368 -0
  111. seedcode_cli-6.1.5.dist-info/RECORD +114 -0
  112. seedcode_cli-6.1.5.dist-info/WHEEL +4 -0
  113. seedcode_cli-6.1.5.dist-info/entry_points.txt +2 -0
  114. seedcode_cli-6.1.5.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,213 @@
1
+ """OCR provisioning: the text-recognition tier, configured for the user.
2
+
3
+ OCR used to be the weakest link in the detection ladder. ``pytesseract`` is
4
+ only a thin wrapper around the ``tesseract`` executable, and nothing shipped
5
+ that executable — so on a normal machine the OCR tier silently did nothing, and
6
+ a workflow that reached it failed with "OCR is not installed". Worse, the old
7
+ availability check asked only whether the *Python wrapper* imported, so Seed
8
+ Code would report OCR as available while every call to it failed.
9
+
10
+ This module fixes both halves:
11
+
12
+ * :func:`tesseract_path` finds the engine across every way Seed Code can be
13
+ installed — bundled next to the frozen exe, unpacked inside it, dropped in
14
+ the user's data directory, or already on PATH — and :func:`configure` points
15
+ ``pytesseract`` at whatever it found.
16
+ * :func:`available` reports the truth: the wrapper **and** a working binary.
17
+
18
+ The user is never asked to install anything: the Windows installer ships the
19
+ engine (see ``scripts/windows/setup.iss``) and :func:`configure` runs
20
+ automatically the first time the OCR tier is used.
21
+
22
+ Deterministic and offline. No AI, and no network access — Seed Code never
23
+ downloads a dependency behind the user's back.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import os
29
+ import shutil
30
+ import subprocess
31
+ import sys
32
+ from pathlib import Path
33
+
34
+ from ..utils.helpers import app_dir, bundled_path, install_dir
35
+
36
+ # Where the engine lives relative to each install shape. Ordered by
37
+ # trustworthiness: something we shipped beats whatever happens to be on PATH,
38
+ # so behaviour cannot drift with an unrelated system install.
39
+ _SUBDIR = "tesseract"
40
+ _EXE = "tesseract.exe" if os.name == "nt" else "tesseract"
41
+
42
+ # Env var lets a user or CI pin a specific engine explicitly.
43
+ _ENV_VARS = ("SEEDCODE_TESSERACT", "TESSERACT_CMD")
44
+
45
+ # Probing the binary costs a subprocess launch; the answer cannot change within
46
+ # a session, so it is computed once.
47
+ _probe_cache: "tuple[str, bool] | None" = None
48
+
49
+
50
+ def candidate_paths() -> list[Path]:
51
+ """Every location the engine may live, in resolution order."""
52
+ paths: list[Path] = []
53
+ for var in _ENV_VARS:
54
+ value = os.environ.get(var, "").strip()
55
+ if value:
56
+ paths.append(Path(value))
57
+ # Beside the installed exe (how the Windows installer ships it).
58
+ paths.append(install_dir() / _SUBDIR / _EXE)
59
+ # Unpacked from the frozen bundle, or inside the source package.
60
+ paths.append(bundled_path(_SUBDIR, _EXE))
61
+ # The user's own data directory — the sideload location.
62
+ paths.append(app_dir() / _SUBDIR / _EXE)
63
+ if os.name == "nt":
64
+ # A normal system-wide Tesseract install.
65
+ for root in (
66
+ os.environ.get("ProgramFiles", r"C:\Program Files"),
67
+ os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)"),
68
+ os.environ.get("LOCALAPPDATA", ""),
69
+ ):
70
+ if root:
71
+ paths.append(Path(root) / "Tesseract-OCR" / _EXE)
72
+ return paths
73
+
74
+
75
+ def tesseract_path() -> str | None:
76
+ """The path to a usable tesseract executable, or None if there is none."""
77
+ for path in candidate_paths():
78
+ try:
79
+ if path.is_file():
80
+ return str(path)
81
+ except OSError:
82
+ continue
83
+ found = shutil.which("tesseract")
84
+ return found or None
85
+
86
+
87
+ def tessdata_path(exe: str | None = None) -> str | None:
88
+ """The language-data directory matching ``exe``, if it ships alongside."""
89
+ if exe is None:
90
+ exe = tesseract_path()
91
+ if not exe:
92
+ return None
93
+ candidate = Path(exe).parent / "tessdata"
94
+ try:
95
+ return str(candidate) if candidate.is_dir() else None
96
+ except OSError:
97
+ return None
98
+
99
+
100
+ def configure() -> str | None:
101
+ """Point ``pytesseract`` at the resolved engine. Returns the path used.
102
+
103
+ Safe and cheap to call repeatedly — every OCR entry point calls it first so
104
+ the engine is configured on first use with no setup step from the user.
105
+ """
106
+ exe = tesseract_path()
107
+ if not exe:
108
+ return None
109
+ try:
110
+ import pytesseract
111
+ except ImportError:
112
+ return None
113
+ pytesseract.pytesseract.tesseract_cmd = exe
114
+ # Bundled builds need TESSDATA_PREFIX or the engine cannot find eng.traineddata.
115
+ data = tessdata_path(exe)
116
+ if data and not os.environ.get("TESSDATA_PREFIX"):
117
+ os.environ["TESSDATA_PREFIX"] = data
118
+ return exe
119
+
120
+
121
+ def wrapper_installed() -> bool:
122
+ """Whether the ``pytesseract`` Python package is importable."""
123
+ import importlib.util
124
+
125
+ return importlib.util.find_spec("pytesseract") is not None
126
+
127
+
128
+ def engine_works(exe: str | None = None) -> bool:
129
+ """Whether the engine actually runs (cached for the session).
130
+
131
+ A file existing is not proof it executes — a partial install, a blocked
132
+ binary, or a missing VC runtime all produce a present-but-broken exe. The
133
+ honest check is to run it.
134
+ """
135
+ global _probe_cache
136
+ if exe is None:
137
+ exe = tesseract_path()
138
+ if not exe:
139
+ return False
140
+ if _probe_cache is not None and _probe_cache[0] == exe:
141
+ return _probe_cache[1]
142
+ ok = False
143
+ try:
144
+ proc = subprocess.run(
145
+ [exe, "--version"],
146
+ capture_output=True,
147
+ text=True,
148
+ timeout=10,
149
+ creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0) if os.name == "nt" else 0,
150
+ )
151
+ ok = proc.returncode == 0 and "tesseract" in (proc.stdout + proc.stderr).lower()
152
+ except (OSError, subprocess.SubprocessError):
153
+ ok = False
154
+ _probe_cache = (exe, ok)
155
+ return ok
156
+
157
+
158
+ def available() -> bool:
159
+ """Whether OCR can genuinely run: wrapper present *and* engine working."""
160
+ if not wrapper_installed():
161
+ return False
162
+ return engine_works(configure())
163
+
164
+
165
+ def status() -> tuple[bool, str]:
166
+ """(ok, human-readable detail) for /doctor and the capability tables."""
167
+ if not wrapper_installed():
168
+ return False, (
169
+ "the pytesseract package is missing — reinstall Seed Code, or run: "
170
+ "pip install seedcode-cli[desktop]"
171
+ )
172
+ exe = configure()
173
+ if not exe:
174
+ return False, (
175
+ "the Tesseract engine was not found. It ships with the Seed Code "
176
+ "installer; reinstall, or set SEEDCODE_TESSERACT to a tesseract "
177
+ f"executable. Looked in: {_searched()}"
178
+ )
179
+ if not engine_works(exe):
180
+ return False, f"found {exe} but it did not run (damaged or blocked install)"
181
+ return True, exe
182
+
183
+
184
+ def version() -> str:
185
+ """The engine's reported version, or an empty string."""
186
+ exe = tesseract_path()
187
+ if not exe:
188
+ return ""
189
+ try:
190
+ proc = subprocess.run(
191
+ [exe, "--version"], capture_output=True, text=True, timeout=10,
192
+ creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0) if os.name == "nt" else 0,
193
+ )
194
+ except (OSError, subprocess.SubprocessError):
195
+ return ""
196
+ first = (proc.stdout or proc.stderr or "").strip().splitlines()
197
+ return first[0] if first else ""
198
+
199
+
200
+ def reset_cache() -> None:
201
+ """Forget the probe result (tests, and after an install repairs itself)."""
202
+ global _probe_cache
203
+ _probe_cache = None
204
+
205
+
206
+ def _searched() -> str:
207
+ """A short, readable list of the places the engine was looked for."""
208
+ seen: list[str] = []
209
+ for path in candidate_paths()[:4]:
210
+ text = str(path)
211
+ if text not in seen:
212
+ seen.append(text)
213
+ return "; ".join(seen)