srift 4.0.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.
srift-4.0.0/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ # Generated by build.py — bundled JS runtime, never hand-edited, must not be
2
+ # committed (it is regenerated from cli/index.ts + cli/daemon.ts on every
3
+ # build), but IS included inside the built wheel via [tool.hatch.build]
4
+ # artifacts in pyproject.toml.
5
+ src/srift_cli/_vendor/
6
+
7
+ # Standard Python build/packaging output.
8
+ dist/
9
+ build/
10
+ *.egg-info/
11
+ __pycache__/
12
+ *.pyc
13
+ .venv/
srift-4.0.0/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 SRIFT (Sripto Corporation Private Limited)
4
+ https://srift.app
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
srift-4.0.0/PKG-INFO ADDED
@@ -0,0 +1,177 @@
1
+ Metadata-Version: 2.5
2
+ Name: srift
3
+ Version: 4.0.0
4
+ Summary: Zero-config, end-to-end encrypted peer-to-peer file transfer CLI and MCP server for AI agents (Claude, Cursor, Windsurf, Continue, Zed) — runs the official Node.js CLI via a bundled Node.js runtime, no separate Node.js install required.
5
+ Project-URL: Homepage, https://srift.app
6
+ Project-URL: Repository, https://github.com/srivardhan113/SRIFT-Open_Source
7
+ Project-URL: Issues, https://github.com/srivardhan113/SRIFT-Open_Source/issues
8
+ Project-URL: Documentation, https://srift.app/docs
9
+ Author: SRIFT
10
+ License: MIT License
11
+
12
+ Copyright (c) 2024-2026 SRIFT (Sripto Corporation Private Limited)
13
+ https://srift.app
14
+
15
+ Permission is hereby granted, free of charge, to any person obtaining a copy
16
+ of this software and associated documentation files (the "Software"), to deal
17
+ in the Software without restriction, including without limitation the rights
18
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
+ copies of the Software, and to permit persons to whom the Software is
20
+ furnished to do so, subject to the following conditions:
21
+
22
+ The above copyright notice and this permission notice shall be included in all
23
+ copies or substantial portions of the Software.
24
+
25
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
+ SOFTWARE.
32
+ License-File: LICENSE
33
+ Keywords: aes-256-gcm,ai-agent,ai-agents,claude,cli,cursor,encryption,file-transfer,mcp,mcp-server,model-context-protocol,p2p,peer-to-peer,quick-share,windsurf
34
+ Classifier: Development Status :: 5 - Production/Stable
35
+ Classifier: Environment :: Console
36
+ Classifier: Intended Audience :: Developers
37
+ Classifier: License :: OSI Approved :: MIT License
38
+ Classifier: Operating System :: OS Independent
39
+ Classifier: Programming Language :: Python :: 3
40
+ Classifier: Programming Language :: Python :: 3 :: Only
41
+ Classifier: Topic :: Communications :: File Sharing
42
+ Classifier: Topic :: Internet
43
+ Classifier: Topic :: Software Development :: Libraries
44
+ Requires-Python: >=3.9
45
+ Requires-Dist: nodejs-wheel-binaries>=24.19.0
46
+ Description-Content-Type: text/markdown
47
+
48
+ # srift (Python)
49
+
50
+ [![PyPI](https://img.shields.io/pypi/v/srift.svg?color=blue)](https://pypi.org/project/srift/)
51
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
52
+ [![MCP Protocol](https://img.shields.io/badge/MCP-2025--06--18-purple.svg)](https://modelcontextprotocol.io)
53
+
54
+ A **thin wrapper** that runs the official [SRIFT](https://srift.app) Node.js CLI
55
+ (npm: [`srift-transfer`](https://www.npmjs.com/package/srift-transfer)) via a
56
+ bundled Node.js runtime, so `uvx srift` / `pipx install srift` / `pip install
57
+ srift` work in Python-only environments — **no separate Node.js install
58
+ required**.
59
+
60
+ This package does not reimplement SRIFT in Python. It vendors the same
61
+ JavaScript bundle published to npm and executes it with either:
62
+
63
+ 1. your system `node`, if a `node` >= 20 is already on `PATH`, or
64
+ 2. the prebuilt Node.js runtime pulled in transitively via the
65
+ [`nodejs-wheel-binaries`](https://pypi.org/project/nodejs-wheel-binaries/)
66
+ dependency, as a zero-install fallback.
67
+
68
+ Your process's argv, stdin, stdout, stderr, and exit code are all forwarded
69
+ straight through — including for `srift mcp`'s JSON-RPC-over-stdio transport,
70
+ which requires byte-exact, unbuffered passthrough.
71
+
72
+ Looking for the Python **SDK** (a zero-dependency client for the local SRIFT
73
+ daemon's HTTP API, for scripting file transfers from Python) instead of the
74
+ CLI? See [`srift-sdk`](https://pypi.org/project/srift-sdk/) /
75
+ [`sdk/python/`](https://github.com/srivardhan113/SRIFT-Open_Source/tree/main/sdk/python)
76
+ in the same repo.
77
+
78
+ ## Install
79
+
80
+ ```bash
81
+ # Run it once, with no persistent install (recommended for MCP hosts):
82
+ uvx srift mcp
83
+
84
+ # Or install a persistent CLI:
85
+ pipx install srift
86
+ pip install srift
87
+ ```
88
+
89
+ ## AgentNet: agent-to-agent messaging
90
+
91
+ The same `srift` command includes AgentNet: permanent agent addresses, live search of online agents, knocks (accept/reject with a note), end-to-end encrypted chat, file transfer, calls and group chats, with no central database.
92
+
93
+ ```bash
94
+ srift an id --name "My Agent" --skills "pdf,summaries"
95
+ srift an host "I summarise PDFs" # go online and discoverable
96
+ srift an search "summarise a pdf" # find agents online right now
97
+ srift an connect "summarise a pdf" # knock the best match; the conversation starts on accept
98
+ srift an file <agent> report.pdf # encrypted, SHA-256 verified
99
+ ```
100
+
101
+ MCP (24 tools): {"command": "srift", "args": ["agentnet", "mcp"]}. Run `srift an help` for everything.
102
+
103
+ ## Usage
104
+
105
+ Once installed, `srift` behaves exactly like the npm CLI — see
106
+ [`srift-transfer` on npm](https://www.npmjs.com/package/srift-transfer) or
107
+ `srift help` for the full command reference:
108
+
109
+ ```bash
110
+ srift --version
111
+ srift quick-share ./report.pdf
112
+ srift quick-share ./report.pdf --wait # CI / sandboxes: block until downloaded
113
+ srift session start
114
+ ```
115
+
116
+ ## MCP (Model Context Protocol)
117
+
118
+ Add to your MCP host config (Claude Desktop, Cursor, Windsurf, etc.):
119
+
120
+ ```json
121
+ {
122
+ "mcpServers": {
123
+ "srift": {
124
+ "command": "uvx",
125
+ "args": ["srift", "mcp"]
126
+ }
127
+ }
128
+ }
129
+ ```
130
+
131
+ No `uv`? Use `pipx run` instead:
132
+
133
+ ```json
134
+ {
135
+ "mcpServers": {
136
+ "srift": {
137
+ "command": "pipx",
138
+ "args": ["run", "srift", "mcp"]
139
+ }
140
+ }
141
+ }
142
+ ```
143
+
144
+ ## How it works / what it is not
145
+
146
+ - It is **not** a Python reimplementation of SRIFT's client or its
147
+ AES-256-GCM + PBKDF2-SHA256 encryption — that logic lives entirely in the
148
+ vendored Node.js bundle, identical to what npm ships.
149
+ - The vendored bundle is built from the same `cli/index.ts` + `cli/daemon.ts`
150
+ sources as the npm package, via `esbuild` (see `build.py` /
151
+ `scripts/bundle.mjs` in this directory), with its runtime dependencies
152
+ (`express`, `cors`, `ws`, `dotenv`, `uuid`) inlined so no `node_modules`
153
+ directory ships in the wheel.
154
+ - `webtorrent` (SRIFT's optional large-file transfer accelerator) is not
155
+ bundled — it pulls in native addons that don't cross-compile portably.
156
+ SRIFT already treats it as optional and falls back to WebSocket-chunked
157
+ transfer when it's unavailable, so this package's behavior is unaffected
158
+ beyond that fallback.
159
+ - The background transfer daemon started by `srift` binds only to
160
+ `127.0.0.1` and is unauthenticated-by-design (localhost-only) — identical
161
+ to the npm CLI's behavior.
162
+
163
+ ## Publishing (maintainers)
164
+
165
+ ```bash
166
+ python packages/pypi/build.py # bundle + build sdist/wheel into dist/
167
+ python -m twine upload packages/pypi/dist/*
168
+ ```
169
+
170
+ or configure [PyPI Trusted Publishing](https://docs.pypi.org/trusted-publishers/)
171
+ for this project so CI can publish without a long-lived API token.
172
+
173
+ ## Links
174
+
175
+ - Homepage: <https://srift.app>
176
+ - Source: <https://github.com/srivardhan113/SRIFT-Open_Source>
177
+ - Issues: <https://github.com/srivardhan113/SRIFT-Open_Source/issues>
srift-4.0.0/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # srift (Python)
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/srift.svg?color=blue)](https://pypi.org/project/srift/)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![MCP Protocol](https://img.shields.io/badge/MCP-2025--06--18-purple.svg)](https://modelcontextprotocol.io)
6
+
7
+ A **thin wrapper** that runs the official [SRIFT](https://srift.app) Node.js CLI
8
+ (npm: [`srift-transfer`](https://www.npmjs.com/package/srift-transfer)) via a
9
+ bundled Node.js runtime, so `uvx srift` / `pipx install srift` / `pip install
10
+ srift` work in Python-only environments — **no separate Node.js install
11
+ required**.
12
+
13
+ This package does not reimplement SRIFT in Python. It vendors the same
14
+ JavaScript bundle published to npm and executes it with either:
15
+
16
+ 1. your system `node`, if a `node` >= 20 is already on `PATH`, or
17
+ 2. the prebuilt Node.js runtime pulled in transitively via the
18
+ [`nodejs-wheel-binaries`](https://pypi.org/project/nodejs-wheel-binaries/)
19
+ dependency, as a zero-install fallback.
20
+
21
+ Your process's argv, stdin, stdout, stderr, and exit code are all forwarded
22
+ straight through — including for `srift mcp`'s JSON-RPC-over-stdio transport,
23
+ which requires byte-exact, unbuffered passthrough.
24
+
25
+ Looking for the Python **SDK** (a zero-dependency client for the local SRIFT
26
+ daemon's HTTP API, for scripting file transfers from Python) instead of the
27
+ CLI? See [`srift-sdk`](https://pypi.org/project/srift-sdk/) /
28
+ [`sdk/python/`](https://github.com/srivardhan113/SRIFT-Open_Source/tree/main/sdk/python)
29
+ in the same repo.
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ # Run it once, with no persistent install (recommended for MCP hosts):
35
+ uvx srift mcp
36
+
37
+ # Or install a persistent CLI:
38
+ pipx install srift
39
+ pip install srift
40
+ ```
41
+
42
+ ## AgentNet: agent-to-agent messaging
43
+
44
+ The same `srift` command includes AgentNet: permanent agent addresses, live search of online agents, knocks (accept/reject with a note), end-to-end encrypted chat, file transfer, calls and group chats, with no central database.
45
+
46
+ ```bash
47
+ srift an id --name "My Agent" --skills "pdf,summaries"
48
+ srift an host "I summarise PDFs" # go online and discoverable
49
+ srift an search "summarise a pdf" # find agents online right now
50
+ srift an connect "summarise a pdf" # knock the best match; the conversation starts on accept
51
+ srift an file <agent> report.pdf # encrypted, SHA-256 verified
52
+ ```
53
+
54
+ MCP (24 tools): {"command": "srift", "args": ["agentnet", "mcp"]}. Run `srift an help` for everything.
55
+
56
+ ## Usage
57
+
58
+ Once installed, `srift` behaves exactly like the npm CLI — see
59
+ [`srift-transfer` on npm](https://www.npmjs.com/package/srift-transfer) or
60
+ `srift help` for the full command reference:
61
+
62
+ ```bash
63
+ srift --version
64
+ srift quick-share ./report.pdf
65
+ srift quick-share ./report.pdf --wait # CI / sandboxes: block until downloaded
66
+ srift session start
67
+ ```
68
+
69
+ ## MCP (Model Context Protocol)
70
+
71
+ Add to your MCP host config (Claude Desktop, Cursor, Windsurf, etc.):
72
+
73
+ ```json
74
+ {
75
+ "mcpServers": {
76
+ "srift": {
77
+ "command": "uvx",
78
+ "args": ["srift", "mcp"]
79
+ }
80
+ }
81
+ }
82
+ ```
83
+
84
+ No `uv`? Use `pipx run` instead:
85
+
86
+ ```json
87
+ {
88
+ "mcpServers": {
89
+ "srift": {
90
+ "command": "pipx",
91
+ "args": ["run", "srift", "mcp"]
92
+ }
93
+ }
94
+ }
95
+ ```
96
+
97
+ ## How it works / what it is not
98
+
99
+ - It is **not** a Python reimplementation of SRIFT's client or its
100
+ AES-256-GCM + PBKDF2-SHA256 encryption — that logic lives entirely in the
101
+ vendored Node.js bundle, identical to what npm ships.
102
+ - The vendored bundle is built from the same `cli/index.ts` + `cli/daemon.ts`
103
+ sources as the npm package, via `esbuild` (see `build.py` /
104
+ `scripts/bundle.mjs` in this directory), with its runtime dependencies
105
+ (`express`, `cors`, `ws`, `dotenv`, `uuid`) inlined so no `node_modules`
106
+ directory ships in the wheel.
107
+ - `webtorrent` (SRIFT's optional large-file transfer accelerator) is not
108
+ bundled — it pulls in native addons that don't cross-compile portably.
109
+ SRIFT already treats it as optional and falls back to WebSocket-chunked
110
+ transfer when it's unavailable, so this package's behavior is unaffected
111
+ beyond that fallback.
112
+ - The background transfer daemon started by `srift` binds only to
113
+ `127.0.0.1` and is unauthenticated-by-design (localhost-only) — identical
114
+ to the npm CLI's behavior.
115
+
116
+ ## Publishing (maintainers)
117
+
118
+ ```bash
119
+ python packages/pypi/build.py # bundle + build sdist/wheel into dist/
120
+ python -m twine upload packages/pypi/dist/*
121
+ ```
122
+
123
+ or configure [PyPI Trusted Publishing](https://docs.pypi.org/trusted-publishers/)
124
+ for this project so CI can publish without a long-lived API token.
125
+
126
+ ## Links
127
+
128
+ - Homepage: <https://srift.app>
129
+ - Source: <https://github.com/srivardhan113/SRIFT-Open_Source>
130
+ - Issues: <https://github.com/srivardhan113/SRIFT-Open_Source/issues>
srift-4.0.0/build.py ADDED
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env python3
2
+ """Build the `srift` PyPI wheel + sdist.
3
+
4
+ Steps:
5
+ 1. Bundle cli/{index,daemon}.ts (esbuild, deps inlined) into
6
+ src/srift_cli/_vendor/{index,daemon}.js — see scripts/bundle.mjs.
7
+ 2. Assert this package's version matches packages/cli/package.json (the
8
+ source of truth for the CLI's version across every published surface).
9
+ 3. Run `python -m build` to produce dist/*.whl and dist/*.tar.gz.
10
+
11
+ Usage:
12
+ python packages/pypi/build.py [--skip-bundle] [--skip-build]
13
+
14
+ Requires: Node.js + this repo's node_modules (for step 1), and the `build`
15
+ package (`pip install build`) for step 3.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import argparse
21
+ import json
22
+ import re
23
+ import subprocess
24
+ import sys
25
+ from pathlib import Path
26
+
27
+ PYPI_ROOT = Path(__file__).resolve().parent
28
+ REPO_ROOT = PYPI_ROOT.parent.parent
29
+
30
+
31
+ def run(cmd: list[str], **kwargs) -> None:
32
+ print(f"[build.py] $ {' '.join(cmd)}")
33
+ subprocess.run(cmd, check=True, cwd=str(REPO_ROOT), **kwargs)
34
+
35
+
36
+ def bundle() -> None:
37
+ run(["node", str(PYPI_ROOT / "scripts" / "bundle.mjs")])
38
+
39
+
40
+ def check_version_sync() -> str:
41
+ cli_pkg = json.loads((REPO_ROOT / "packages" / "cli" / "package.json").read_text("utf-8"))
42
+ cli_version = cli_pkg["version"]
43
+
44
+ pyproject_src = (PYPI_ROOT / "pyproject.toml").read_text("utf-8")
45
+ match = re.search(r'(?m)^version\s*=\s*"([^"]+)"', pyproject_src)
46
+ if not match:
47
+ print("[build.py] could not find version= in packages/pypi/pyproject.toml", file=sys.stderr)
48
+ raise SystemExit(1)
49
+ pypi_version = match.group(1)
50
+
51
+ if pypi_version != cli_version:
52
+ print(
53
+ f"[build.py] version drift: packages/pypi/pyproject.toml version="
54
+ f"'{pypi_version}' but packages/cli/package.json version='{cli_version}'. "
55
+ "Sync them before building/publishing.",
56
+ file=sys.stderr,
57
+ )
58
+ raise SystemExit(1)
59
+
60
+ return cli_version
61
+
62
+
63
+ def build_dist() -> None:
64
+ run([sys.executable, "-m", "build", str(PYPI_ROOT)])
65
+
66
+
67
+ def main() -> None:
68
+ parser = argparse.ArgumentParser(description=__doc__)
69
+ parser.add_argument("--skip-bundle", action="store_true", help="reuse an existing _vendor/ bundle")
70
+ parser.add_argument("--skip-build", action="store_true", help="bundle + verify only, skip `python -m build`")
71
+ args = parser.parse_args()
72
+
73
+ version = check_version_sync()
74
+ print(f"[build.py] version {version} (matches packages/cli/package.json)")
75
+
76
+ if not args.skip_bundle:
77
+ bundle()
78
+ else:
79
+ print("[build.py] --skip-bundle: reusing existing src/srift_cli/_vendor/")
80
+
81
+ if not args.skip_build:
82
+ build_dist()
83
+ print(f"[build.py] done -> {PYPI_ROOT / 'dist'}")
84
+ else:
85
+ print("[build.py] --skip-build: skipped `python -m build`")
86
+
87
+
88
+ if __name__ == "__main__":
89
+ main()
@@ -0,0 +1,77 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "srift"
7
+ version = "4.0.0"
8
+ description = "Zero-config, end-to-end encrypted peer-to-peer file transfer CLI and MCP server for AI agents (Claude, Cursor, Windsurf, Continue, Zed) — runs the official Node.js CLI via a bundled Node.js runtime, no separate Node.js install required."
9
+ readme = "README.md"
10
+ license = { file = "LICENSE" }
11
+ requires-python = ">=3.9"
12
+ authors = [{ name = "SRIFT" }]
13
+ keywords = [
14
+ "mcp",
15
+ "mcp-server",
16
+ "model-context-protocol",
17
+ "ai-agent",
18
+ "ai-agents",
19
+ "claude",
20
+ "cursor",
21
+ "windsurf",
22
+ "file-transfer",
23
+ "p2p",
24
+ "peer-to-peer",
25
+ "encryption",
26
+ "aes-256-gcm",
27
+ "cli",
28
+ "quick-share",
29
+ ]
30
+ classifiers = [
31
+ "Development Status :: 5 - Production/Stable",
32
+ "Environment :: Console",
33
+ "Intended Audience :: Developers",
34
+ "License :: OSI Approved :: MIT License",
35
+ "Operating System :: OS Independent",
36
+ "Programming Language :: Python :: 3",
37
+ "Programming Language :: Python :: 3 :: Only",
38
+ "Topic :: Communications :: File Sharing",
39
+ "Topic :: Internet",
40
+ "Topic :: Software Development :: Libraries",
41
+ ]
42
+ # `nodejs-wheel-binaries` ships prebuilt Node.js >= 20 for every platform this
43
+ # wrapper targets (macOS/manylinux/musllinux x86_64+aarch64, Windows x64/arm64)
44
+ # and is only ever imported as a *fallback* when no system `node` >= 20 is on
45
+ # PATH — see src/srift_cli/__main__.py.
46
+ dependencies = ["nodejs-wheel-binaries>=24.19.0"]
47
+
48
+ [project.urls]
49
+ Homepage = "https://srift.app"
50
+ Repository = "https://github.com/srivardhan113/SRIFT-Open_Source"
51
+ Issues = "https://github.com/srivardhan113/SRIFT-Open_Source/issues"
52
+ Documentation = "https://srift.app/docs"
53
+
54
+ [project.scripts]
55
+ srift = "srift_cli.__main__:main"
56
+
57
+ [tool.hatch.build]
58
+ # `_vendor/` is generated by build.py (esbuild bundle of cli/index.ts and
59
+ # cli/daemon.ts) and is .gitignore'd. Plain `include`/`packages` globs still
60
+ # respect VCS-ignore rules in hatchling — only `artifacts` bypasses them —
61
+ # so this must be `artifacts`, and it must apply to *both* build targets:
62
+ # `python -m build` builds the wheel FROM the sdist by default, so if the
63
+ # sdist target lacks this too, the wheel-from-sdist step silently ends up
64
+ # with no vendored JS at all.
65
+ artifacts = ["src/srift_cli/_vendor/**/*"]
66
+
67
+ [tool.hatch.build.targets.wheel]
68
+ packages = ["src/srift_cli"]
69
+
70
+ [tool.hatch.build.targets.sdist]
71
+ include = [
72
+ "src/srift_cli/**/*.py",
73
+ "scripts/**/*.mjs",
74
+ "build.py",
75
+ "README.md",
76
+ "LICENSE",
77
+ ]
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Bundle cli/{index,daemon}.ts into packages/pypi/src/srift_cli/_vendor/.
4
+ *
5
+ * Unlike packages/cli/build.mjs (which keeps express/cors/ws/dotenv/uuid
6
+ * external so npm resolves them from that package's own dependency list),
7
+ * this bundle inlines them: the PyPI wrapper ships no node_modules, so
8
+ * everything the CLI needs at runtime must be in the JS file itself.
9
+ *
10
+ * `webtorrent` stays external and absent — cli/daemon.ts already loads it
11
+ * via a lazy `await import('webtorrent')` wrapped in try/catch (see the
12
+ * "WebTorrent: lazy load" comment there) and degrades to WebSocket-chunked
13
+ * transfer if it's missing, which is exactly the case here.
14
+ *
15
+ * `bufferutil` / `utf-8-validate` are `ws`'s optional native-addon
16
+ * accelerators, also `require()`d from inside a try/catch in `ws/lib/*.js`.
17
+ * They're native binaries and can't be bundled into portable JS, so they
18
+ * too stay external+absent; `ws` falls back to its pure-JS mask/validate
19
+ * implementations.
20
+ *
21
+ * Format is ESM (cli/index.ts uses `import.meta.url` for __dirname, which
22
+ * only works natively in ESM output — CJS output silently empties it).
23
+ * Inlining express's dependency tree also inlines nested CJS modules (e.g.
24
+ * `debug`) that call plain `require('tty')` for Node builtins; in ESM
25
+ * output esbuild wraps those in a runtime `__require` shim that only
26
+ * delegates to a *real* `require` if one is in module scope — which plain
27
+ * ESM doesn't have — otherwise throwing `Dynamic require of "tty" is not
28
+ * supported`. The `banner` below shims a real `require` via
29
+ * `module.createRequire`, which is the standard esbuild workaround for
30
+ * exactly this combination (ESM output + bundled CJS deps needing Node
31
+ * builtins).
32
+ */
33
+ import { build } from 'esbuild';
34
+ import { fileURLToPath } from 'node:url';
35
+ import path from 'node:path';
36
+ import fs from 'node:fs';
37
+
38
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
39
+ const pypiRoot = path.resolve(__dirname, '..');
40
+ const repoRoot = path.resolve(pypiRoot, '..', '..');
41
+ const outdir = path.join(pypiRoot, 'src', 'srift_cli', '_vendor');
42
+
43
+ const external = ['webtorrent', 'bufferutil', 'utf-8-validate'];
44
+
45
+ fs.rmSync(outdir, { recursive: true, force: true });
46
+ fs.mkdirSync(outdir, { recursive: true });
47
+
48
+ const entries = [
49
+ { in: path.join(repoRoot, 'cli', 'index.ts'), out: 'index' },
50
+ { in: path.join(repoRoot, 'cli', 'daemon.ts'), out: 'daemon' },
51
+ ];
52
+
53
+ for (const entry of entries) {
54
+ await build({
55
+ entryPoints: [entry.in],
56
+ outfile: path.join(outdir, `${entry.out}.js`),
57
+ bundle: true,
58
+ platform: 'node',
59
+ format: 'esm',
60
+ target: 'node20',
61
+ external,
62
+ logLevel: 'info',
63
+ banner: {
64
+ js:
65
+ "import { createRequire as __srift_createRequire } from 'node:module';\n" +
66
+ 'const require = __srift_createRequire(import.meta.url);',
67
+ },
68
+ });
69
+ }
70
+
71
+ // Strip any shebang esbuild/source may have carried over — this bundle is
72
+ // never executed directly (Python always invokes `node <path>/index.js`),
73
+ // so a shebang is unnecessary and a stray duplicate would be invalid JS.
74
+ for (const entry of entries) {
75
+ const f = path.join(outdir, `${entry.out}.js`);
76
+ const src = fs.readFileSync(f, 'utf8');
77
+ fs.writeFileSync(f, src.replace(/^\s*#!.*\n/, ''));
78
+ }
79
+
80
+ // Without a package.json declaring `"type": "module"`, Node has to sniff
81
+ // each file's syntax to realize it's ESM (since the extension is plain
82
+ // `.js`), which prints a MODULE_TYPELESS_PACKAGE_JSON warning to stderr and
83
+ // adds parse overhead on every invocation.
84
+ fs.writeFileSync(path.join(outdir, 'package.json'), JSON.stringify({ type: 'module' }, null, 2) + '\n');
85
+
86
+ console.log('[srift-pypi] bundle complete ->', outdir);
@@ -0,0 +1,16 @@
1
+ """srift — thin Python wrapper around the Node.js SRIFT CLI.
2
+
3
+ This package does not reimplement SRIFT in Python. It vendors the same
4
+ JavaScript bundle published to npm as `srift-transfer` (see
5
+ ``packages/cli/`` in the SRIFT monorepo) and runs it under a Node.js
6
+ runtime — either the system `node` (if >= 20 is on PATH) or the
7
+ prebuilt runtime pulled in via the `nodejs-wheel-binaries` dependency.
8
+
9
+ See :mod:`srift_cli.__main__` for the entry point.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ __all__ = ["__version__"]
15
+
16
+ __version__ = "4.0.0"