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.
- openshard/__init__.py +6 -0
- openshard/analysis/__init__.py +0 -0
- openshard/analysis/repo.py +180 -0
- openshard/cli/__init__.py +0 -0
- openshard/cli/main.py +2613 -0
- openshard/cli/run_output.py +2188 -0
- openshard/cli/ui/__init__.py +1 -0
- openshard/cli/ui/console.py +19 -0
- openshard/cli/ui/home.py +318 -0
- openshard/cli/ui/run_screen.py +149 -0
- openshard/cli/ui/theme.py +15 -0
- openshard/config/__init__.py +0 -0
- openshard/config/settings.py +76 -0
- openshard/cost/__init__.py +0 -0
- openshard/cost/baseline.py +159 -0
- openshard/evals/__init__.py +0 -0
- openshard/evals/adjustments.py +181 -0
- openshard/evals/registry.py +67 -0
- openshard/evals/runner.py +138 -0
- openshard/evals/stats.py +265 -0
- openshard/execution/__init__.py +0 -0
- openshard/execution/gates.py +82 -0
- openshard/execution/generator.py +403 -0
- openshard/execution/opencode_executor.py +195 -0
- openshard/execution/runner.py +18 -0
- openshard/execution/stages.py +170 -0
- openshard/history/__init__.py +0 -0
- openshard/history/adjustments.py +99 -0
- openshard/history/failure_memory.py +122 -0
- openshard/history/feedback.py +102 -0
- openshard/history/feedback_scoring.py +174 -0
- openshard/history/interactions.py +101 -0
- openshard/history/metrics.py +199 -0
- openshard/history/native_steps.py +113 -0
- openshard/history/run_checkpoints.py +107 -0
- openshard/history/sandbox_apply_receipts.py +99 -0
- openshard/history/session_events.py +58 -0
- openshard/history/session_signals.py +178 -0
- openshard/history/shard_contract.py +1195 -0
- openshard/models/__init__.py +0 -0
- openshard/models/advisory.py +133 -0
- openshard/models/feedback_advisory.py +91 -0
- openshard/models/mode_policy.py +53 -0
- openshard/models/registry.py +752 -0
- openshard/native/__init__.py +0 -0
- openshard/native/backends.py +223 -0
- openshard/native/context.py +3614 -0
- openshard/native/dispatch.py +183 -0
- openshard/native/executor.py +1588 -0
- openshard/native/loop.py +66 -0
- openshard/native/osn_loop_recorder.py +101 -0
- openshard/native/repo_context.py +121 -0
- openshard/native/sandbox.py +75 -0
- openshard/native/sandbox_apply.py +195 -0
- openshard/native/sandbox_diff.py +104 -0
- openshard/native/skills.py +120 -0
- openshard/native/tool_runner.py +98 -0
- openshard/native/tools.py +385 -0
- openshard/planning/__init__.py +0 -0
- openshard/planning/generator.py +117 -0
- openshard/providers/__init__.py +3 -0
- openshard/providers/anthropic.py +117 -0
- openshard/providers/base.py +73 -0
- openshard/providers/cache.py +43 -0
- openshard/providers/manager.py +105 -0
- openshard/providers/openai.py +119 -0
- openshard/providers/openrouter.py +252 -0
- openshard/review/__init__.py +0 -0
- openshard/review/checks.py +185 -0
- openshard/review/domain_files.py +101 -0
- openshard/review/terraform_checker.py +528 -0
- openshard/routing/__init__.py +0 -0
- openshard/routing/engine.py +262 -0
- openshard/routing/form_factor_policy.py +114 -0
- openshard/routing/profiles.py +111 -0
- openshard/routing/workflow_selector.py +88 -0
- openshard/run/__init__.py +0 -0
- openshard/run/pipeline.py +2646 -0
- openshard/run/timeline.py +102 -0
- openshard/run/validator_policy.py +51 -0
- openshard/scoring/__init__.py +0 -0
- openshard/scoring/filter.py +72 -0
- openshard/scoring/policy.py +82 -0
- openshard/scoring/requirements.py +37 -0
- openshard/scoring/scorer.py +136 -0
- openshard/scoring/shortlist.py +84 -0
- openshard/security/__init__.py +0 -0
- openshard/security/paths.py +84 -0
- openshard/skills/__init__.py +0 -0
- openshard/skills/context.py +25 -0
- openshard/skills/discovery.py +82 -0
- openshard/skills/matcher.py +57 -0
- openshard/tui/__init__.py +1 -0
- openshard/tui/action_blocks.py +135 -0
- openshard/tui/app.py +564 -0
- openshard/tui/ask_mode.py +222 -0
- openshard/tui/commands.py +113 -0
- openshard/tui/plan_mode.py +55 -0
- openshard/tui/state.py +104 -0
- openshard/tui/styles.tcss +114 -0
- openshard/verification/__init__.py +23 -0
- openshard/verification/executor.py +87 -0
- openshard/verification/plan.py +243 -0
- openshard/workflow_packs/__init__.py +0 -0
- openshard/workflow_packs/builtin.py +118 -0
- openshard/workflow_packs/packs.py +62 -0
- openshard-0.1.0.dist-info/METADATA +553 -0
- openshard-0.1.0.dist-info/RECORD +112 -0
- openshard-0.1.0.dist-info/WHEEL +5 -0
- openshard-0.1.0.dist-info/entry_points.txt +2 -0
- openshard-0.1.0.dist-info/licenses/LICENSE +21 -0
- openshard-0.1.0.dist-info/top_level.txt +1 -0
openshard/__init__.py
ADDED
|
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
|