openshard 0.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 (112) hide show
  1. openshard/__init__.py +6 -0
  2. openshard/analysis/__init__.py +0 -0
  3. openshard/analysis/repo.py +180 -0
  4. openshard/cli/__init__.py +0 -0
  5. openshard/cli/main.py +2613 -0
  6. openshard/cli/run_output.py +2188 -0
  7. openshard/cli/ui/__init__.py +1 -0
  8. openshard/cli/ui/console.py +19 -0
  9. openshard/cli/ui/home.py +318 -0
  10. openshard/cli/ui/run_screen.py +149 -0
  11. openshard/cli/ui/theme.py +15 -0
  12. openshard/config/__init__.py +0 -0
  13. openshard/config/settings.py +76 -0
  14. openshard/cost/__init__.py +0 -0
  15. openshard/cost/baseline.py +159 -0
  16. openshard/evals/__init__.py +0 -0
  17. openshard/evals/adjustments.py +181 -0
  18. openshard/evals/registry.py +67 -0
  19. openshard/evals/runner.py +138 -0
  20. openshard/evals/stats.py +265 -0
  21. openshard/execution/__init__.py +0 -0
  22. openshard/execution/gates.py +82 -0
  23. openshard/execution/generator.py +403 -0
  24. openshard/execution/opencode_executor.py +195 -0
  25. openshard/execution/runner.py +18 -0
  26. openshard/execution/stages.py +170 -0
  27. openshard/history/__init__.py +0 -0
  28. openshard/history/adjustments.py +99 -0
  29. openshard/history/failure_memory.py +122 -0
  30. openshard/history/feedback.py +102 -0
  31. openshard/history/feedback_scoring.py +174 -0
  32. openshard/history/interactions.py +101 -0
  33. openshard/history/metrics.py +199 -0
  34. openshard/history/native_steps.py +113 -0
  35. openshard/history/run_checkpoints.py +107 -0
  36. openshard/history/sandbox_apply_receipts.py +99 -0
  37. openshard/history/session_events.py +58 -0
  38. openshard/history/session_signals.py +178 -0
  39. openshard/history/shard_contract.py +1195 -0
  40. openshard/models/__init__.py +0 -0
  41. openshard/models/advisory.py +133 -0
  42. openshard/models/feedback_advisory.py +91 -0
  43. openshard/models/mode_policy.py +53 -0
  44. openshard/models/registry.py +752 -0
  45. openshard/native/__init__.py +0 -0
  46. openshard/native/backends.py +223 -0
  47. openshard/native/context.py +3614 -0
  48. openshard/native/dispatch.py +183 -0
  49. openshard/native/executor.py +1588 -0
  50. openshard/native/loop.py +66 -0
  51. openshard/native/osn_loop_recorder.py +101 -0
  52. openshard/native/repo_context.py +121 -0
  53. openshard/native/sandbox.py +75 -0
  54. openshard/native/sandbox_apply.py +195 -0
  55. openshard/native/sandbox_diff.py +104 -0
  56. openshard/native/skills.py +120 -0
  57. openshard/native/tool_runner.py +98 -0
  58. openshard/native/tools.py +385 -0
  59. openshard/planning/__init__.py +0 -0
  60. openshard/planning/generator.py +117 -0
  61. openshard/providers/__init__.py +3 -0
  62. openshard/providers/anthropic.py +117 -0
  63. openshard/providers/base.py +73 -0
  64. openshard/providers/cache.py +43 -0
  65. openshard/providers/manager.py +105 -0
  66. openshard/providers/openai.py +119 -0
  67. openshard/providers/openrouter.py +252 -0
  68. openshard/review/__init__.py +0 -0
  69. openshard/review/checks.py +185 -0
  70. openshard/review/domain_files.py +101 -0
  71. openshard/review/terraform_checker.py +528 -0
  72. openshard/routing/__init__.py +0 -0
  73. openshard/routing/engine.py +262 -0
  74. openshard/routing/form_factor_policy.py +114 -0
  75. openshard/routing/profiles.py +111 -0
  76. openshard/routing/workflow_selector.py +88 -0
  77. openshard/run/__init__.py +0 -0
  78. openshard/run/pipeline.py +2646 -0
  79. openshard/run/timeline.py +102 -0
  80. openshard/run/validator_policy.py +51 -0
  81. openshard/scoring/__init__.py +0 -0
  82. openshard/scoring/filter.py +72 -0
  83. openshard/scoring/policy.py +82 -0
  84. openshard/scoring/requirements.py +37 -0
  85. openshard/scoring/scorer.py +136 -0
  86. openshard/scoring/shortlist.py +84 -0
  87. openshard/security/__init__.py +0 -0
  88. openshard/security/paths.py +84 -0
  89. openshard/skills/__init__.py +0 -0
  90. openshard/skills/context.py +25 -0
  91. openshard/skills/discovery.py +82 -0
  92. openshard/skills/matcher.py +57 -0
  93. openshard/tui/__init__.py +1 -0
  94. openshard/tui/action_blocks.py +135 -0
  95. openshard/tui/app.py +564 -0
  96. openshard/tui/ask_mode.py +222 -0
  97. openshard/tui/commands.py +113 -0
  98. openshard/tui/plan_mode.py +55 -0
  99. openshard/tui/state.py +104 -0
  100. openshard/tui/styles.tcss +114 -0
  101. openshard/verification/__init__.py +23 -0
  102. openshard/verification/executor.py +87 -0
  103. openshard/verification/plan.py +243 -0
  104. openshard/workflow_packs/__init__.py +0 -0
  105. openshard/workflow_packs/builtin.py +118 -0
  106. openshard/workflow_packs/packs.py +62 -0
  107. openshard-0.1.0.dist-info/METADATA +553 -0
  108. openshard-0.1.0.dist-info/RECORD +112 -0
  109. openshard-0.1.0.dist-info/WHEEL +5 -0
  110. openshard-0.1.0.dist-info/entry_points.txt +2 -0
  111. openshard-0.1.0.dist-info/licenses/LICENSE +21 -0
  112. openshard-0.1.0.dist-info/top_level.txt +1 -0
openshard/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ from importlib.metadata import version, PackageNotFoundError
2
+
3
+ try:
4
+ __version__ = version("openshard")
5
+ except PackageNotFoundError:
6
+ __version__ = "0.1.0-dev"
File without changes
@@ -0,0 +1,180 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import subprocess
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+
8
+
9
+ @dataclass
10
+ class RepoFacts:
11
+ languages: list[str]
12
+ package_files: list[str]
13
+ framework: str | None
14
+ test_command: str | None
15
+ risky_paths: list[str]
16
+ changed_files: list[str]
17
+
18
+
19
+ _EXT_TO_LANG: dict[str, str] = {
20
+ ".py": "python",
21
+ ".js": "javascript",
22
+ ".jsx": "javascript",
23
+ ".ts": "typescript",
24
+ ".tsx": "typescript",
25
+ ".rs": "rust",
26
+ ".go": "go",
27
+ ".java": "java",
28
+ ".rb": "ruby",
29
+ ".php": "php",
30
+ ".cs": "csharp",
31
+ ".cpp": "cpp",
32
+ ".c": "c",
33
+ ".swift": "swift",
34
+ ".kt": "kotlin",
35
+ }
36
+
37
+ _KNOWN_PACKAGE_FILES: frozenset[str] = frozenset({
38
+ "package.json",
39
+ "requirements.txt",
40
+ "pyproject.toml",
41
+ "Cargo.toml",
42
+ "go.mod",
43
+ "pom.xml",
44
+ "build.gradle",
45
+ "Gemfile",
46
+ "composer.json",
47
+ "setup.py",
48
+ "setup.cfg",
49
+ })
50
+
51
+ _RISKY_KEYWORDS: tuple[str, ...] = (
52
+ "auth", "payment", "config", "env", "security", "migration",
53
+ )
54
+
55
+ _SKIP_DIRS: frozenset[str] = frozenset({
56
+ ".git", "node_modules", "__pycache__", ".venv", "venv",
57
+ ".mypy_cache", ".pytest_cache", ".tox", "dist", "build",
58
+ ".next", ".nuxt", ".openshard",
59
+ })
60
+
61
+
62
+ def _walk_repo(path: Path):
63
+ for p in path.rglob("*"):
64
+ rel_parts = p.relative_to(path).parts
65
+ if any(part in _SKIP_DIRS for part in rel_parts):
66
+ continue
67
+ yield p
68
+
69
+
70
+ def _detect_languages(path: Path) -> list[str]:
71
+ seen: set[str] = set()
72
+ for p in _walk_repo(path):
73
+ if p.is_file():
74
+ lang = _EXT_TO_LANG.get(p.suffix.lower())
75
+ if lang:
76
+ seen.add(lang)
77
+ return sorted(seen)
78
+
79
+
80
+ def _detect_package_files(path: Path) -> list[str]:
81
+ return sorted(name for name in _KNOWN_PACKAGE_FILES if (path / name).is_file())
82
+
83
+
84
+ def _detect_framework(path: Path, package_files: list[str]) -> str | None:
85
+ if "package.json" in package_files:
86
+ try:
87
+ pkg = json.loads((path / "package.json").read_text(encoding="utf-8"))
88
+ deps = {**pkg.get("dependencies", {}), **pkg.get("devDependencies", {})}
89
+ for fw in ("next", "react", "vue", "angular", "express", "fastify", "svelte"):
90
+ if fw in deps:
91
+ return fw
92
+ except Exception:
93
+ pass
94
+
95
+ for fname in ("requirements.txt", "pyproject.toml", "setup.cfg"):
96
+ if fname not in package_files:
97
+ continue
98
+ try:
99
+ content = (path / fname).read_text(encoding="utf-8").lower()
100
+ for fw in ("django", "fastapi", "flask", "starlette", "tornado"):
101
+ if fw in content:
102
+ return fw
103
+ except Exception:
104
+ pass
105
+
106
+ return None
107
+
108
+
109
+ def _detect_test_command(path: Path, package_files: list[str]) -> str | None:
110
+ if "package.json" in package_files:
111
+ try:
112
+ pkg = json.loads((path / "package.json").read_text(encoding="utf-8"))
113
+ if "test" in pkg.get("scripts", {}):
114
+ return "npm test"
115
+ except Exception:
116
+ pass
117
+
118
+ if any(f in package_files for f in ("pyproject.toml", "setup.cfg", "requirements.txt")):
119
+ for fname in ("pyproject.toml", "setup.cfg", "requirements.txt"):
120
+ if fname not in package_files:
121
+ continue
122
+ try:
123
+ if "pytest" in (path / fname).read_text(encoding="utf-8").lower():
124
+ return "python -m pytest"
125
+ except Exception:
126
+ pass
127
+ if any(path.rglob("test_*.py")):
128
+ return "python -m pytest"
129
+
130
+ if "Cargo.toml" in package_files:
131
+ return "cargo test"
132
+
133
+ if "go.mod" in package_files:
134
+ return "go test ./..."
135
+
136
+ if "Gemfile" in package_files:
137
+ return "bundle exec rspec"
138
+
139
+ if "pom.xml" in package_files:
140
+ return "mvn test"
141
+
142
+ return None
143
+
144
+
145
+ def _detect_risky_paths(path: Path) -> list[str]:
146
+ risky: list[str] = []
147
+ for p in _walk_repo(path):
148
+ name = p.name.lower()
149
+ if any(kw in name for kw in _RISKY_KEYWORDS):
150
+ risky.append(str(p.relative_to(path)).replace("\\", "/"))
151
+ return sorted(risky)
152
+
153
+
154
+ def _detect_changed_files(path: Path) -> list[str]:
155
+ try:
156
+ result = subprocess.run(
157
+ ["git", "diff", "--name-only", "HEAD"],
158
+ cwd=str(path),
159
+ capture_output=True,
160
+ text=True,
161
+ timeout=5,
162
+ )
163
+ if result.returncode == 0:
164
+ return [f for f in result.stdout.splitlines() if f and not f.startswith(".openshard/")]
165
+ except Exception:
166
+ pass
167
+ return []
168
+
169
+
170
+ def analyze_repo(path: str | Path) -> RepoFacts:
171
+ p = Path(path)
172
+ package_files = _detect_package_files(p)
173
+ return RepoFacts(
174
+ languages=_detect_languages(p),
175
+ package_files=package_files,
176
+ framework=_detect_framework(p, package_files),
177
+ test_command=_detect_test_command(p, package_files),
178
+ risky_paths=_detect_risky_paths(p),
179
+ changed_files=_detect_changed_files(p),
180
+ )
File without changes