delphi-team 0.1.0__tar.gz

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.
@@ -0,0 +1,18 @@
1
+ node_modules/
2
+ dist/
3
+ dist-artifacts/
4
+ dist-binaries/
5
+ coverage/
6
+ *.tsbuildinfo
7
+
8
+ # Compiled binaries are staged into the wheel at build time, never committed.
9
+ python/src/delphi_team/bin/*
10
+ !python/src/delphi_team/bin/.gitkeep
11
+ python/dist/
12
+ python/build/
13
+ *.egg-info/
14
+ __pycache__/
15
+
16
+ .delphi/logs/
17
+ .delphi/tmp/
18
+ .build/tmp/
@@ -0,0 +1,31 @@
1
+ Metadata-Version: 2.5
2
+ Name: delphi-team
3
+ Version: 0.1.0
4
+ Summary: Run Claude Code as a department. Unofficial; works with Claude Code.
5
+ License-Expression: MIT
6
+ Keywords: agents,claude-code,cli,orchestration
7
+ Classifier: Environment :: Console
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Operating System :: MacOS
10
+ Classifier: Operating System :: Microsoft :: Windows
11
+ Classifier: Operating System :: POSIX :: Linux
12
+ Classifier: Programming Language :: Python :: 3
13
+ Requires-Python: >=3.9
14
+ Description-Content-Type: text/markdown
15
+
16
+ # delphi-team (Python distribution)
17
+
18
+ Run Claude Code as a department. Unofficial; works with Claude Code.
19
+
20
+ This wheel carries a compiled binary of the `delphi` CLI, so nothing here needs Node.
21
+ All logic lives in the TypeScript core — this package is a shim that hands over argv,
22
+ stdio and the exit code. See the project README for what the tool does.
23
+
24
+ ```
25
+ pipx install delphi-team
26
+ uvx delphi-team --help
27
+ pip install delphi-team
28
+ ```
29
+
30
+ Platforms without a published binary fail with an instruction to use `npm install -g delphi-team`
31
+ rather than silently downloading a Node runtime.
@@ -0,0 +1,16 @@
1
+ # delphi-team (Python distribution)
2
+
3
+ Run Claude Code as a department. Unofficial; works with Claude Code.
4
+
5
+ This wheel carries a compiled binary of the `delphi` CLI, so nothing here needs Node.
6
+ All logic lives in the TypeScript core — this package is a shim that hands over argv,
7
+ stdio and the exit code. See the project README for what the tool does.
8
+
9
+ ```
10
+ pipx install delphi-team
11
+ uvx delphi-team --help
12
+ pip install delphi-team
13
+ ```
14
+
15
+ Platforms without a published binary fail with an instruction to use `npm install -g delphi-team`
16
+ rather than silently downloading a Node runtime.
@@ -0,0 +1,20 @@
1
+ """Mark the wheel as platform-specific so it can carry a compiled binary.
2
+
3
+ The wheel holds no Python C extension, so the ABI tag stays ``none``; only the platform
4
+ tag changes. ``DELPHI_WHEEL_TAG`` is set by CI per target; building locally without it
5
+ infers the tag from the host.
6
+ """
7
+
8
+ import os
9
+
10
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
11
+
12
+
13
+ class CustomBuildHook(BuildHookInterface):
14
+ def initialize(self, version, build_data):
15
+ build_data["pure_python"] = False
16
+ tag = os.environ.get("DELPHI_WHEEL_TAG")
17
+ if tag:
18
+ build_data["tag"] = tag
19
+ else:
20
+ build_data["infer_tag"] = True
@@ -0,0 +1,32 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.32"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "delphi-team"
7
+ version = "0.1.0"
8
+ description = "Run Claude Code as a department. Unofficial; works with Claude Code."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.9"
12
+ keywords = ["claude-code", "agents", "orchestration", "cli"]
13
+ classifiers = [
14
+ "Environment :: Console",
15
+ "Intended Audience :: Developers",
16
+ "Operating System :: Microsoft :: Windows",
17
+ "Operating System :: MacOS",
18
+ "Operating System :: POSIX :: Linux",
19
+ "Programming Language :: Python :: 3",
20
+ ]
21
+
22
+ [project.scripts]
23
+ delphi-team = "delphi_team._shim:main"
24
+ delphi = "delphi_team._shim:main"
25
+
26
+ [tool.hatch.build.targets.wheel]
27
+ packages = ["src/delphi_team"]
28
+ # Without this, hatchling's VCS-aware file selection silently drops the gitignored binary.
29
+ artifacts = ["src/delphi_team/bin/*"]
30
+
31
+ [tool.hatch.build.targets.wheel.hooks.custom]
32
+ path = "hatch_build.py"
@@ -0,0 +1,7 @@
1
+ """Thin Python distribution for the delphi-team CLI.
2
+
3
+ All logic lives in the TypeScript core; this package only carries a compiled binary and
4
+ hands control to it. See docs/spec/PACKAGING_SPEC.md section 1.
5
+ """
6
+
7
+ __version__ = "0.1.0"
@@ -0,0 +1,3 @@
1
+ from delphi_team._shim import main
2
+
3
+ main()
@@ -0,0 +1,78 @@
1
+ """Hand argv, stdin, stdout, stderr and the exit code to the bundled delphi binary.
2
+
3
+ On POSIX the process is replaced outright, so streams and signals are inherited and the
4
+ exit code is the binary's own. Windows has no real ``execv``, so the binary is run as a
5
+ child and its return code is propagated.
6
+
7
+ There is deliberately no fallback to ``npx`` (ADR-0005): it would reintroduce a Node
8
+ requirement for exactly the pip and uv users these wheels exist to serve. A platform with
9
+ no binary gets a clear message instead of a silent download.
10
+ """
11
+
12
+ import os
13
+ import subprocess
14
+ import sys
15
+ from pathlib import Path
16
+
17
+ _BIN_DIR = Path(__file__).resolve().parent / "bin"
18
+
19
+
20
+ def binary_path() -> Path:
21
+ """Where the compiled CLI lives inside the installed wheel."""
22
+ return _BIN_DIR / ("delphi.exe" if os.name == "nt" else "delphi")
23
+
24
+
25
+ def _machine() -> str:
26
+ if hasattr(os, "uname"):
27
+ return os.uname().machine
28
+ return os.environ.get("PROCESSOR_ARCHITECTURE", "unknown")
29
+
30
+
31
+ def _missing_binary_message(exe: Path) -> str:
32
+ return (
33
+ f"delphi-team has no compiled binary for this platform "
34
+ f"({sys.platform}, {_machine()}).\n"
35
+ f"Expected it at: {exe}\n\n"
36
+ "Install the Node distribution instead:\n"
37
+ " npm install -g delphi-team\n\n"
38
+ "If you believe this platform should be supported, please open an issue."
39
+ )
40
+
41
+
42
+ def _unrunnable_binary_message(exe: Path, error: OSError) -> str:
43
+ return (
44
+ f"delphi-team found its binary but could not run it: {error}\n"
45
+ f" {exe}\n\n"
46
+ "The file is usually not executable, or the install is incomplete. Try reinstalling:\n"
47
+ " pipx reinstall delphi-team\n\n"
48
+ "Or use the Node distribution instead:\n"
49
+ " npm install -g delphi-team"
50
+ )
51
+
52
+
53
+ def _fail(message: str) -> "NoReturn": # noqa: F821 - quoted so Python 3.9 needs no import
54
+ sys.stderr.write(message + "\n")
55
+ raise SystemExit(1)
56
+
57
+
58
+ def main() -> None:
59
+ exe = binary_path()
60
+ if not exe.is_file():
61
+ _fail(_missing_binary_message(exe))
62
+
63
+ args = [str(exe), *sys.argv[1:]]
64
+ try:
65
+ if os.name == "nt":
66
+ # Windows has no execv that replaces the process, so run the binary as a child.
67
+ raise SystemExit(subprocess.run(args).returncode)
68
+ sys.stdout.flush()
69
+ sys.stderr.flush()
70
+ os.execv(str(exe), args)
71
+ except KeyboardInterrupt:
72
+ # On Windows the console delivers Ctrl+C to both processes; without this the child
73
+ # exits cleanly and the parent then dies with a traceback. 130 is the shell convention.
74
+ raise SystemExit(130) from None
75
+ except OSError as error:
76
+ # A present but unrunnable binary: no execute bit, wrong architecture, truncated file.
77
+ # Report it the way the missing case is reported rather than raising a traceback.
78
+ _fail(_unrunnable_binary_message(exe, error))
File without changes
@@ -0,0 +1,97 @@
1
+ """Self-check for the delphi-team shim. Run it directly: `python python/test_shim.py`.
2
+
3
+ Plain asserts, no test framework — the Python side is a shim, not a codebase, and a
4
+ dependency here would have to be installed on every runner just to check three branches.
5
+ """
6
+
7
+ import os
8
+ import subprocess
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ sys.path.insert(0, str(Path(__file__).parent / "src"))
13
+
14
+ from delphi_team import _shim # noqa: E402
15
+
16
+
17
+ def _run_main(tmp_bin: Path, monkey_argv=("delphi",)):
18
+ """Call main() with the shim pointed at tmp_bin, returning (exit_code, stderr)."""
19
+ original_binary_path = _shim.binary_path
20
+ original_argv = sys.argv
21
+ original_stderr = sys.stderr
22
+
23
+ class Capture:
24
+ def __init__(self):
25
+ self.text = ""
26
+
27
+ def write(self, s):
28
+ self.text += s
29
+
30
+ def flush(self):
31
+ pass
32
+
33
+ captured = Capture()
34
+ _shim.binary_path = lambda: tmp_bin
35
+ sys.argv = list(monkey_argv)
36
+ sys.stderr = captured
37
+ try:
38
+ _shim.main()
39
+ except SystemExit as exc:
40
+ return exc.code, captured.text
41
+ finally:
42
+ _shim.binary_path = original_binary_path
43
+ sys.argv = original_argv
44
+ sys.stderr = original_stderr
45
+ raise AssertionError("main() returned instead of exiting")
46
+
47
+
48
+ def test_missing_binary_refuses_loudly(tmp: Path):
49
+ """ADR-0005: no npx fallback. A platform with no binary gets an install hint."""
50
+ code, err = _run_main(tmp / "nope")
51
+ assert code == 1, code
52
+ assert "no compiled binary for this platform" in err, err
53
+ assert "npm install -g delphi-team" in err, err
54
+ assert "npx" not in err, "the shim must not suggest or use npx"
55
+
56
+
57
+ def test_unrunnable_binary_reports_instead_of_crashing(tmp: Path):
58
+ """A present-but-unrunnable binary must not surface as a traceback."""
59
+ if os.name == "nt":
60
+ # Windows has no execute bit; an empty .exe is rejected by CreateProcess instead.
61
+ fake = tmp / "delphi.exe"
62
+ else:
63
+ fake = tmp / "delphi"
64
+ fake.write_bytes(b"not an executable")
65
+ if os.name != "nt":
66
+ fake.chmod(0o644)
67
+
68
+ code, err = _run_main(fake)
69
+ assert code == 1, code
70
+ assert "could not run it" in err, err
71
+ assert "pipx reinstall delphi-team" in err, err
72
+
73
+
74
+ def test_real_binary_passes_through_argv_and_exit_code():
75
+ """The happy path, using this Python interpreter as a stand-in for the compiled CLI."""
76
+ script = "import sys; sys.stdout.write(' '.join(sys.argv[1:])); sys.exit(7)"
77
+ result = subprocess.run(
78
+ [sys.executable, "-c", script, "alpha", "beta"], capture_output=True, text=True
79
+ )
80
+ assert result.stdout == "alpha beta", result.stdout
81
+ assert result.returncode == 7, result.returncode
82
+
83
+
84
+ def main():
85
+ import tempfile
86
+
87
+ tmp = Path(tempfile.mkdtemp())
88
+ for name, fn in sorted(globals().items()):
89
+ if not name.startswith("test_"):
90
+ continue
91
+ fn(tmp) if fn.__code__.co_argcount else fn()
92
+ print(f"ok {name}")
93
+ print("\nall shim checks passed")
94
+
95
+
96
+ if __name__ == "__main__":
97
+ main()