feat: add Chinese UI, Responses models, and mirrored Windows setup
Localize the web console and persist custom model and capability settings. Use OpenAI Responses exclusively and move runtime limits into environment configuration. Bootstrap uv and the virtual environment on Windows, support optional China mirrors, and package source distributions without environments, build output, or credentials. Update regression tests and repository quality checks for the new behavior.
This commit is contained in:
1 parent
371aa6df56
commit
2ddec53954
183 files changed
+3427
-11857
No files matched your search
@@ -0,0 +1,154 @@
|
||||
"""Create a portable source ZIP without environments, builds, or local credentials."""
|
||||
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
import hashlib
|
||||
import os
|
||||
from pathlib import Path
|
||||
import zipfile
|
||||
|
||||
|
||||
EXCLUDED_DIRS = {
|
||||
".git",
|
||||
".venv",
|
||||
"venv",
|
||||
"env",
|
||||
"node_modules",
|
||||
"__pycache__",
|
||||
"__pypackages__",
|
||||
".angular",
|
||||
".gradle",
|
||||
".pytest_cache",
|
||||
".ruff_cache",
|
||||
".mypy_cache",
|
||||
".cache",
|
||||
".tox",
|
||||
".nox",
|
||||
".hypothesis",
|
||||
".eggs",
|
||||
".idea",
|
||||
".vscode",
|
||||
".vs",
|
||||
".codex",
|
||||
".claude",
|
||||
".gemini",
|
||||
".cursor",
|
||||
".ipynb_checkpoints",
|
||||
"build",
|
||||
"dist",
|
||||
"out",
|
||||
"coverage",
|
||||
"htmlcov",
|
||||
"artifacts",
|
||||
"traces",
|
||||
"scratch",
|
||||
"outputs",
|
||||
"trace_output",
|
||||
}
|
||||
EXCLUDED_SUFFIXES = {
|
||||
".pyc",
|
||||
".pyo",
|
||||
".pyd",
|
||||
".so",
|
||||
".dll",
|
||||
".exe",
|
||||
".o",
|
||||
".obj",
|
||||
".a",
|
||||
".lib",
|
||||
".class",
|
||||
".jar",
|
||||
".apk",
|
||||
".aab",
|
||||
".wasm",
|
||||
".map",
|
||||
".tsbuildinfo",
|
||||
".egg",
|
||||
".whl",
|
||||
".zip",
|
||||
".7z",
|
||||
".tar",
|
||||
".gz",
|
||||
".log",
|
||||
".db",
|
||||
".sqlite",
|
||||
".sqlite3",
|
||||
".pem",
|
||||
".key",
|
||||
".keystore",
|
||||
".p12",
|
||||
".pfx",
|
||||
".swp",
|
||||
".swo",
|
||||
}
|
||||
|
||||
|
||||
def excluded(path: Path) -> bool:
|
||||
parts = tuple(part.lower() for part in path.parts)
|
||||
name = parts[-1]
|
||||
if any(part in EXCLUDED_DIRS or part.endswith(".egg-info") for part in parts):
|
||||
return True
|
||||
# This tracked directory also contains generated Angular bundles.
|
||||
if parts[:3] == ("artemis", "resources", "showcase_ui"):
|
||||
return True
|
||||
if (name == ".env" or name.startswith(".env.")) and name != ".env.example":
|
||||
return True
|
||||
if name.startswith((".artemis_", ".jetski_", ".coverage")):
|
||||
return True
|
||||
if name in {".ds_store", "thumbs.db", ".ipc_port", ".ls_address", ".npmrc", ".pypirc"}:
|
||||
return True
|
||||
return path.suffix.lower() in EXCLUDED_SUFFIXES or name.endswith((".db-wal", ".db-shm", "~"))
|
||||
|
||||
|
||||
def source_files(root: Path):
|
||||
for directory, dirs, files in os.walk(root, followlinks=False):
|
||||
current = Path(directory)
|
||||
dirs[:] = sorted(
|
||||
name
|
||||
for name in dirs
|
||||
if not (current / name).is_symlink()
|
||||
and not excluded((current / name).relative_to(root))
|
||||
)
|
||||
for name in sorted(files):
|
||||
path = current / name
|
||||
if not path.is_symlink() and not excluded(path.relative_to(root)):
|
||||
yield path
|
||||
|
||||
|
||||
def package_source(root: Path, output: Path) -> tuple[int, str]:
|
||||
root = root.resolve()
|
||||
output = output.resolve()
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
temporary = output.with_suffix(".zip.tmp")
|
||||
files = [p for p in source_files(root) if p.resolve() not in {output, temporary}]
|
||||
try:
|
||||
with zipfile.ZipFile(temporary, "w", zipfile.ZIP_DEFLATED, compresslevel=6) as archive:
|
||||
for path in files:
|
||||
archive.write(path, Path("artemis") / path.relative_to(root))
|
||||
with zipfile.ZipFile(temporary) as archive:
|
||||
bad_file = archive.testzip()
|
||||
if bad_file:
|
||||
raise RuntimeError(f"ZIP integrity check failed: {bad_file}")
|
||||
if any(excluded(Path(name).relative_to("artemis")) for name in archive.namelist()):
|
||||
raise RuntimeError("An excluded file was found in the source archive")
|
||||
temporary.replace(output)
|
||||
finally:
|
||||
temporary.unlink(missing_ok=True)
|
||||
with output.open("rb") as stream:
|
||||
digest = hashlib.file_digest(stream, "sha256").hexdigest()
|
||||
return len(files), digest
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--root", type=Path, default=Path(__file__).resolve().parents[1])
|
||||
parser.add_argument("--output", type=Path)
|
||||
args = parser.parse_args()
|
||||
output = (
|
||||
args.output
|
||||
or args.root / "artifacts" / f"artemis-source-{datetime.now():%Y%m%d-%H%M%S}.zip"
|
||||
)
|
||||
count, digest = package_source(args.root, output)
|
||||
print(f"Archive: {output.resolve()}")
|
||||
print(f"Files: {count}; size: {output.stat().st_size / (1024 * 1024):.2f} MiB")
|
||||
print(f"SHA256: {digest}")
|
||||
Reference in new issue
Block a user