witbitz-code 1.2.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.
- witbitz_code/__init__.py +7 -0
- witbitz_code/__main__.py +3 -0
- witbitz_code/_js.py +312 -0
- witbitz_code/account.py +127 -0
- witbitz_code/asks.py +119 -0
- witbitz_code/attachments.py +266 -0
- witbitz_code/auto.py +561 -0
- witbitz_code/auto_runner.py +481 -0
- witbitz_code/cli.py +223 -0
- witbitz_code/codetools.py +128 -0
- witbitz_code/compress.py +25 -0
- witbitz_code/computers.py +189 -0
- witbitz_code/connector.py +818 -0
- witbitz_code/devicelink.py +159 -0
- witbitz_code/folders.py +250 -0
- witbitz_code/link.py +205 -0
- witbitz_code/net.py +67 -0
- witbitz_code/opencode_plugins/notes-init.md +8 -0
- witbitz_code/opencode_plugins/witbitz-media-server.mjs +791 -0
- witbitz_code/opencode_plugins/witbitz-notes.js +356 -0
- witbitz_code/opencode_plugins/witbitz-progress.js +120 -0
- witbitz_code/outputs.py +115 -0
- witbitz_code/pair.py +222 -0
- witbitz_code/pairings.py +214 -0
- witbitz_code/plugins.py +140 -0
- witbitz_code/policy.py +48 -0
- witbitz_code/qr.py +59 -0
- witbitz_code/relay.py +783 -0
- witbitz_code/seen.py +49 -0
- witbitz_code/tools_probe.py +67 -0
- witbitz_code-1.2.0.dist-info/METADATA +145 -0
- witbitz_code-1.2.0.dist-info/RECORD +36 -0
- witbitz_code-1.2.0.dist-info/WHEEL +5 -0
- witbitz_code-1.2.0.dist-info/entry_points.txt +2 -0
- witbitz_code-1.2.0.dist-info/licenses/LICENSE +21 -0
- witbitz_code-1.2.0.dist-info/top_level.txt +1 -0
witbitz_code/seen.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""What the person has seen in the Code session list, shared by their devices — spaces/public/codeUnread.js, in Python.
|
|
2
|
+
|
|
3
|
+
The owner: "When I switch devices I get green dots". The page kept the record per device, so a session read on the phone
|
|
4
|
+
was news on the laptop. The computer keeps one too: the connector answers SEEN_ROUTE (GET: its record; POST a device's
|
|
5
|
+
record: merged, and the merge back), and every device merges with it. The rules are codeUnread.js's normSeen/mergeSeen;
|
|
6
|
+
tests/test_connector_e2e.py runs the same sequence against both connectors.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import math
|
|
12
|
+
import re
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
SEEN_ROUTE = "/witbitz/seen"
|
|
16
|
+
_SEEN_ID = re.compile(r"[A-Za-z0-9_-]{1,128}")
|
|
17
|
+
SEEN_MAX = 5000
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _num(v: Any) -> bool:
|
|
21
|
+
return isinstance(v, (int, float)) and not isinstance(v, bool) and math.isfinite(v) and v > 0
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _plain(v: float | int) -> float | int:
|
|
25
|
+
return int(v) if isinstance(v, float) and v.is_integer() else v # 9000.0 → 9000, as JSON.stringify writes it
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def norm_seen(o: Any) -> dict:
|
|
29
|
+
"""A record from the wire or the disk, checked: session ids, positive numbers, at most SEEN_MAX (the latest looks kept)."""
|
|
30
|
+
if not isinstance(o, dict):
|
|
31
|
+
return {"since": 0, "at": {}}
|
|
32
|
+
raw = o.get("at")
|
|
33
|
+
entries = [(k, _plain(v)) for k, v in (raw.items() if isinstance(raw, dict) else []) if isinstance(k, str) and _SEEN_ID.fullmatch(k) and _num(v)]
|
|
34
|
+
if len(entries) > SEEN_MAX:
|
|
35
|
+
entries = sorted(entries, key=lambda e: -e[1])[:SEEN_MAX]
|
|
36
|
+
since = o.get("since")
|
|
37
|
+
return {"since": _plain(since) if _num(since) else 0, "at": dict(entries)}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def merge_seen(a: dict, b: dict) -> dict:
|
|
41
|
+
"""Two records → one: each session's LATER look, the EARLIER first look. The same `a` back when `b` adds nothing."""
|
|
42
|
+
since = min(a["since"], b["since"]) if a["since"] and b["since"] else (a["since"] or b["since"])
|
|
43
|
+
at = a["at"]
|
|
44
|
+
for sid, v in b["at"].items():
|
|
45
|
+
if not (sid in a["at"] and a["at"][sid] >= v):
|
|
46
|
+
if at is a["at"]:
|
|
47
|
+
at = dict(a["at"])
|
|
48
|
+
at[sid] = v
|
|
49
|
+
return a if since == a["since"] and at is a["at"] else {"since": since, "at": at}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Which suggested tools this computer has — tools/code-tools-probe.mjs, in Python ("Set up this computer").
|
|
2
|
+
|
|
3
|
+
A PATH lookup, nothing else: no process is started, no model is asked, nothing is installed. The connector answers the
|
|
4
|
+
page's nonce-checked `{t:'tools'}` with this. The catalog is spaces/public/codeTools.js; tests/test_tools_probe.py holds
|
|
5
|
+
this copy of the binary names and the answers to the JavaScript ones.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import stat
|
|
12
|
+
import sys
|
|
13
|
+
from collections.abc import Callable, Mapping
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
# (tool id, binaries — any one on PATH means installed), in the catalog's order.
|
|
17
|
+
TOOL_BINS: list[tuple[str, list[str]]] = [
|
|
18
|
+
("git", ["git"]), ("ripgrep", ["rg"]), ("jq", ["jq"]), ("python", ["python3", "python"]), ("uv", ["uv"]),
|
|
19
|
+
("ffmpeg", ["ffmpeg"]), ("whisper", ["whisper-cli", "whisper-cpp", "whisper"]), ("poppler", ["pdftotext"]),
|
|
20
|
+
("qpdf", ["qpdf"]), ("tesseract", ["tesseract"]), ("pandoc", ["pandoc"]), ("imagemagick", ["magick", "convert"]),
|
|
21
|
+
]
|
|
22
|
+
# Package managers, most preferred first per OS: (id the page knows, binary).
|
|
23
|
+
PACKAGE_MANAGERS: dict[str, list[tuple[str, str]]] = {
|
|
24
|
+
"darwin": [("brew", "brew"), ("port", "port")],
|
|
25
|
+
"linux": [("apt", "apt-get"), ("dnf", "dnf"), ("pacman", "pacman"), ("zypper", "zypper"), ("apk", "apk"), ("brew", "brew")],
|
|
26
|
+
"win32": [("winget", "winget"), ("choco", "choco"), ("scoop", "scoop")],
|
|
27
|
+
}
|
|
28
|
+
_EXTRA_POSIX = ["/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/snap/bin", "/home/linuxbrew/.linuxbrew/bin"]
|
|
29
|
+
_EXTRA_HOME = [".local/bin", ".cargo/bin", "bin"]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _is_executable(path: str) -> bool:
|
|
33
|
+
try:
|
|
34
|
+
st = os.stat(path)
|
|
35
|
+
except OSError:
|
|
36
|
+
return False
|
|
37
|
+
return stat.S_ISREG(st.st_mode) and os.access(path, os.X_OK)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def search_dirs(*, env: Mapping[str, str], platform: str, home: str) -> list[str]:
|
|
41
|
+
"""The folders searched, in order, without repeats."""
|
|
42
|
+
win = platform == "win32"
|
|
43
|
+
raw = env.get("PATH") or env.get("Path") or ""
|
|
44
|
+
from_path = [d for d in raw.split(";" if win else ":") if d]
|
|
45
|
+
extra = [] if win else _EXTRA_POSIX + ([f"{home.rstrip('/')}/{d}" for d in _EXTRA_HOME] if home else [])
|
|
46
|
+
return list(dict.fromkeys(from_path + extra))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def probe_tools(*, env: Mapping[str, str] | None = None, platform: str | None = None, home: str | None = None,
|
|
50
|
+
is_executable: Callable[[str], bool] = _is_executable) -> dict:
|
|
51
|
+
env = os.environ if env is None else env
|
|
52
|
+
platform = sys.platform if platform is None else platform
|
|
53
|
+
home = str(Path.home()) if home is None else home
|
|
54
|
+
win = platform == "win32"
|
|
55
|
+
dirs = search_dirs(env=env, platform=platform, home=home)
|
|
56
|
+
exts = [""] + [e.lower() for e in (env.get("PATHEXT") or ".COM;.EXE;.BAT;.CMD").split(";") if e] if win else [""]
|
|
57
|
+
|
|
58
|
+
def join(d: str, b: str) -> str:
|
|
59
|
+
return f"{d.rstrip(chr(92) + '/')}\\{b}" if win else f"{d.rstrip('/')}/{b}"
|
|
60
|
+
|
|
61
|
+
def has(b: str) -> bool:
|
|
62
|
+
return any(is_executable(join(d, b + e)) for d in dirs for e in exts)
|
|
63
|
+
|
|
64
|
+
tools = {tid: any(has(b) for b in bins if not (win and b == "convert")) for tid, bins in TOOL_BINS} # Windows' convert.exe is not ImageMagick
|
|
65
|
+
os_id = platform if platform in PACKAGE_MANAGERS else ""
|
|
66
|
+
pm = next((pid for pid, b in PACKAGE_MANAGERS[os_id] if has(b)), "") if os_id else ""
|
|
67
|
+
return {"tools": tools, "platform": {"os": os_id, "pm": pm}}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: witbitz-code
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: Reach OpenCode on this computer from the Witbitz Spaces Code section, through an end-to-end sealed relay.
|
|
5
|
+
Author: Witbitz
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Documentation, https://witbitz.chat/docs/opencode.md
|
|
8
|
+
Project-URL: Repository, https://github.com/witbitzchat/witbitz-code
|
|
9
|
+
Keywords: witbitz,opencode,relay,e2ee
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Topic :: Software Development
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: cryptography>=41
|
|
18
|
+
Requires-Dist: websockets>=13
|
|
19
|
+
Requires-Dist: httpx>=0.25
|
|
20
|
+
Requires-Dist: segno>=1.5
|
|
21
|
+
Provides-Extra: test
|
|
22
|
+
Requires-Dist: pytest>=8; extra == "test"
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# witbitz-code
|
|
26
|
+
|
|
27
|
+
Use the **Code** section of Witbitz Spaces, on any device you're signed in on, to reach
|
|
28
|
+
[OpenCode](https://opencode.ai) running on your computer. It's end-to-end encrypted, needs no open port, and doesn't need
|
|
29
|
+
Tailscale.
|
|
30
|
+
|
|
31
|
+
This is the Python build of the `witbitz-code` tool. It speaks the same wire protocol, uses the same pairing file and the
|
|
32
|
+
same account registry as the single-file Node download (`node witbitz-code.mjs`), so either one can pair a computer and
|
|
33
|
+
the other can serve or unpair it.
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
pipx install witbitz-code # or: pip install witbitz-code
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Python 3.10 or newer. Dependencies: `cryptography`, `websockets`, `httpx`, `segno`.
|
|
42
|
+
|
|
43
|
+
You also need OpenCode itself: `npm install -g opencode-ai` or `curl -fsSL https://opencode.ai/install | bash`.
|
|
44
|
+
|
|
45
|
+
## Use
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
witbitz-code pair # shows a QR code: scan it in Spaces → Settings → Back up & recovery → Add a device
|
|
49
|
+
witbitz-code serve # starts OpenCode on 127.0.0.1:4096 (unless it is running) and the connector
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Then open Code in Spaces. Leave `serve` running (Ctrl-C stops it).
|
|
53
|
+
|
|
54
|
+
| command | what it does |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `pair [--name <name>] [--port <n> \| --opencode-url <url>]` | Show the QR code. The account that scans it gets this computer. `--name` sets the label your devices show (default: the hostname). |
|
|
57
|
+
| `serve [--port <n>] [--no-opencode]` | Start OpenCode on `127.0.0.1:<n>` (default 4096) if nothing is listening there, then connect the pairings whose OpenCode is on that port. One OpenCode per port, one `serve` per OpenCode. |
|
|
58
|
+
| `status` | List this computer's pairings: name, account, OpenCode address and relay. Secrets are never printed. |
|
|
59
|
+
| `rotate [--account <email>]` | Replace the pairing secret(s) without scanning again, then restart `serve`. Devices pick up the new secret on their next sync. |
|
|
60
|
+
| `unpair [--account <email>]` | Remove this computer from an account. Every device drops it on its next sync. |
|
|
61
|
+
| `version`, `--help` | |
|
|
62
|
+
|
|
63
|
+
`pair`, `rotate` and `unpair` also accept `--dry-run`.
|
|
64
|
+
|
|
65
|
+
**More than one account.** Each account that scans the QR code gets its own pairing, with its own secret and relay
|
|
66
|
+
channel. OpenCode has no users, so every paired account reaches the same sessions, files and shell. That's fine when
|
|
67
|
+
all the accounts are yours. If a second account belongs to **another person**, run a separate OpenCode for them
|
|
68
|
+
(another port, ideally another OS user) and pair that account with `--port`.
|
|
69
|
+
|
|
70
|
+
## How it works
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
phone / desktop (Code page) this computer
|
|
74
|
+
seal ▸ frames ◂ open ── wss ─▶ code-relay.witbitz.chat ◀─ wss ── witbitz-code serve ──▶ opencode (127.0.0.1)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- **Both ends dial out** to `wss://code-relay.witbitz.chat`. Nothing listens on your network, and OpenCode never leaves
|
|
78
|
+
`127.0.0.1`.
|
|
79
|
+
- **Pairing** uses a device link: the QR code holds only an ephemeral public key. Your signed-in device seals the account
|
|
80
|
+
pointer to that key. The computer then mints a random 32-byte **secret** for this pairing and does two things with it:
|
|
81
|
+
- stores it in `~/.witbitz/code/pairings.json` (mode 0600);
|
|
82
|
+
- publishes it into the account's sealed `computers` registry, which every signed-in device reads.
|
|
83
|
+
- **Keys:** the relay channel id and two direction keys (page→computer and computer→page, AES-256-GCM) are derived from
|
|
84
|
+
the secret with HKDF-SHA256. A frame reflected back at its sender doesn't decrypt.
|
|
85
|
+
- **Every frame is sealed.** The relay forwards ciphertext it can't read, and the clear header (sender id, sequence
|
|
86
|
+
number) is authenticated. Receivers drop replays. Large bodies are split into parts below the relay's message size cap.
|
|
87
|
+
- **Replays across restarts:** each time the connector's socket opens, it announces a fresh random nonce inside its
|
|
88
|
+
sealed hello. Every request and subscription must carry that nonce, so a request recorded before a restart or
|
|
89
|
+
reconnect is refused (409) and never reaches OpenCode.
|
|
90
|
+
- **The connector only forwards what the Code page itself calls:** list and read sessions, send a message, abort, answer
|
|
91
|
+
a permission prompt, rename and delete. Every other request gets a 403 without touching OpenCode. OpenCode can run shell
|
|
92
|
+
commands, so a leaked secret must not unlock more than the page can do. The live event stream is forwarded only while
|
|
93
|
+
a device is watching.
|
|
94
|
+
- **The OpenCode password** lives in `~/.opencode-server.env` (created 0600 on first pair). The connector adds it to local
|
|
95
|
+
calls, and it never leaves the computer.
|
|
96
|
+
|
|
97
|
+
**Auto mode** (Manual · Accept edits · Plan · **Auto** in the Code composer's mode chip, per session) lets this computer answer OpenCode's permission
|
|
98
|
+
prompts while you are away:
|
|
99
|
+
- **Refused at once:** what is never safe, like `rm -rf ~`, `mkfs` or `dd` onto a disk. The agent is told why.
|
|
100
|
+
- **Allowed at once:** read-only commands that stay inside the project, and edits to ordinary files in it.
|
|
101
|
+
- **Everything else** goes to the session's own model, in a throw-away session that can use no tools. Only a clear,
|
|
102
|
+
low-severity allow runs. A refusal, "ask", an unclear answer or a timeout leaves the prompt for you.
|
|
103
|
+
- **Never "always":** each answer covers that one call.
|
|
104
|
+
|
|
105
|
+
Each decision is logged to `~/.witbitz/code/auto-log.jsonl` as a digest, never the command. The rules are shared with the
|
|
106
|
+
Node connector and tested against the same cases, so both decide alike.
|
|
107
|
+
|
|
108
|
+
**What is encrypted, and what isn't.** Requests, responses and events travel end to end. The relay operator sees a
|
|
109
|
+
pseudonymous channel id, IP addresses, connection times, and frame sizes and timing. That's the same class of metadata
|
|
110
|
+
the Spaces room store sees. Anyone holding a pairing secret can drive OpenCode within the allowlist until you run
|
|
111
|
+
`rotate`.
|
|
112
|
+
|
|
113
|
+
Design: `docs/opencode-relay.md` in the Witbitz repository.
|
|
114
|
+
|
|
115
|
+
## Files and environment
|
|
116
|
+
|
|
117
|
+
| | default | override |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| pairings | `~/.witbitz/code/pairings.json` | `WITBITZ_CODE_PAIRINGS` |
|
|
120
|
+
| OpenCode password | `~/.opencode-server.env` (`OPENCODE_SERVER_PASSWORD=`) | `OPENCODE_ENV_FILE` |
|
|
121
|
+
| pairing QR, as SVG | `~/.witbitz-rc.link.svg` | |
|
|
122
|
+
| Auto mode state + decision log | `~/.witbitz/code/auto-<computer>.json`, `auto-log.jsonl` | `WITBITZ_CODE_AUTO_DIR` |
|
|
123
|
+
| account API | `https://api.witbitz.chat/v1/space` | `RC_BASE`, `RC_ORIGIN` |
|
|
124
|
+
| device-link origins | `https://spaces.witbitz.chat,https://witbitz-spaces.pages.dev` | `RC_LINK_ORIGIN` |
|
|
125
|
+
|
|
126
|
+
## Development
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
pip install -e '.[test]'
|
|
130
|
+
python -m pytest tests -q
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The tests hold this package to the JavaScript reference implementation. They run the modules in `spaces/public/` and
|
|
134
|
+
`tools/` under `node` (22 or newer), and they cover:
|
|
135
|
+
|
|
136
|
+
- the pinned HKDF vectors;
|
|
137
|
+
- frames sealed on either side opening on the other;
|
|
138
|
+
- chunking through surrogate pairs;
|
|
139
|
+
- the device-link reply and the backup keys;
|
|
140
|
+
- the registry merge rules, compared byte for byte;
|
|
141
|
+
- the pairing file in both directions;
|
|
142
|
+
- the gzip wrap of account docs;
|
|
143
|
+
- a connector of each language driven by a client of the other, through a local fake relay and a fake OpenCode.
|
|
144
|
+
|
|
145
|
+
Without the repository checkout (`WITBITZ_REPO`) or `node`, the cross-implementation tests are skipped.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
witbitz_code/__init__.py,sha256=Ip38w5d2nF2_LLuLFtZyq9dkyXe6n-bXbAHfcpedcFg,290
|
|
2
|
+
witbitz_code/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30
|
|
3
|
+
witbitz_code/_js.py,sha256=56cKC97SfM1UZAcOGzGnL-SgIB4SfdAlqVDXX3Vi-N0,11458
|
|
4
|
+
witbitz_code/account.py,sha256=JoCbG1H-qK0hrh2PyNTFYoPpaHukuB8zfD_xaE6lsjA,6133
|
|
5
|
+
witbitz_code/asks.py,sha256=PuuM_WItEim4gKyn4tY9uEo3u_ejmcmwcJAYk2cziYs,5703
|
|
6
|
+
witbitz_code/attachments.py,sha256=1IxpI0YOTl-8x8AtPXwmXYMuxU5qip0ggoBo1I7rAS4,12409
|
|
7
|
+
witbitz_code/auto.py,sha256=lHwCzGOgQd42WUQTCCF4a-otEXaGQ9H4QDdPOJh1wtI,27609
|
|
8
|
+
witbitz_code/auto_runner.py,sha256=mvjlstcHetr-tmJttht4r9rEJ9Qps9VXangBxbGPCKA,26067
|
|
9
|
+
witbitz_code/cli.py,sha256=NCg0Cv3NscYcXHZrEtZKVbly44GNsYFWA6bJL-umHxM,9806
|
|
10
|
+
witbitz_code/codetools.py,sha256=MAZ3CkeHhHgaNa1Mi_nmL7eIC-uOroskdnSSVgomkCI,6758
|
|
11
|
+
witbitz_code/compress.py,sha256=ghZf_HTmYyHOwJDxDgJumr-7hIeohwio_SIMrzs1jtM,759
|
|
12
|
+
witbitz_code/computers.py,sha256=CJccZsL2Km4anrAbwKdhkENe1ZGXqOd_ou05k-gITDU,8280
|
|
13
|
+
witbitz_code/connector.py,sha256=JiK7m4qmH5pu7rgncQWhzfswAD5YghlNASri0ynJLSY,43313
|
|
14
|
+
witbitz_code/devicelink.py,sha256=v_xW6OkrdCJkkyvBtwuzmgc46uSngi7MiGeamiDN00g,7043
|
|
15
|
+
witbitz_code/folders.py,sha256=wi_WYJWNg6bhMfd9258BNsRH23hHwwoCTpFmqBbpSyc,10153
|
|
16
|
+
witbitz_code/link.py,sha256=UgLYh86NBX4m-FseRqo6Y90fpuKrz8AljxpJPN7njAI,8759
|
|
17
|
+
witbitz_code/net.py,sha256=YnqhwZPer4RADTtNIGdp02NXzI5v45fq9XsWOr-yLns,2062
|
|
18
|
+
witbitz_code/outputs.py,sha256=Sibj4Gb6yNEgBQdM7DDlOXbZS93Wo0CxHz7Llzgmyvs,5808
|
|
19
|
+
witbitz_code/pair.py,sha256=OD-Kmy-UBSVUAHvmRH2ApP4H6mpPxUJ3GzNp8MRWN5M,9681
|
|
20
|
+
witbitz_code/pairings.py,sha256=tb9A3jfa4AHmJUsuApJGUPNlI4T8oX7oQry17BP0xcQ,9808
|
|
21
|
+
witbitz_code/plugins.py,sha256=c4soyUM-VSwcLSmvey2aEYNfuu8J6jrsZtAAv4YzS6I,6679
|
|
22
|
+
witbitz_code/policy.py,sha256=kuvtkdKRTE-wf7_nBdwCs9PQvq_n2m-BCVqG6B7Iz1Y,2014
|
|
23
|
+
witbitz_code/qr.py,sha256=Rd5sitzrdGNktHsn7ISGBs-OURtPHmEPbwqPNRXbTTs,2776
|
|
24
|
+
witbitz_code/relay.py,sha256=9pHVrqQj0c4kGGPmckHZLsIchdLtexC5zGUjm3IwWWg,34626
|
|
25
|
+
witbitz_code/seen.py,sha256=ltMM6RgOu9b2mdpGOgTKWGWME_gLHUs1UxJiY7n_AyI,2182
|
|
26
|
+
witbitz_code/tools_probe.py,sha256=fELe69rzJwpB0omek9twRHN3OOolky3wrKVXFk28VFg,3404
|
|
27
|
+
witbitz_code/opencode_plugins/notes-init.md,sha256=7SkhvxSFhKY0W1EZv4DIk34RzbpxoQbqub3f7DJs9c0,768
|
|
28
|
+
witbitz_code/opencode_plugins/witbitz-media-server.mjs,sha256=M-wEUBlDASM89txnCyYLMUYci6Ss5du14fmEx27TZvo,75529
|
|
29
|
+
witbitz_code/opencode_plugins/witbitz-notes.js,sha256=M8V0WZiJdPE78hcjHT3oo1aybbD513rMWlxbcDBOdzg,26661
|
|
30
|
+
witbitz_code/opencode_plugins/witbitz-progress.js,sha256=6J9B71eZqhXpWoCLm-hSBSrlTfflCmHnWHp9yhEItbQ,10349
|
|
31
|
+
witbitz_code-1.2.0.dist-info/licenses/LICENSE,sha256=tAdpEnopN3C7_Mtwt4FpOt54tdJcytanMIPmfjWQyX8,1064
|
|
32
|
+
witbitz_code-1.2.0.dist-info/METADATA,sha256=1x4pzOpJjfPv8FMBcS3IMs_y6IPyAobaPmwjA5uqX5Y,8041
|
|
33
|
+
witbitz_code-1.2.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
34
|
+
witbitz_code-1.2.0.dist-info/entry_points.txt,sha256=rjZTJptXZoB2fSJowQBgbsNiiTfsmJGXEwJNIYJHbu4,55
|
|
35
|
+
witbitz_code-1.2.0.dist-info/top_level.txt,sha256=_Q9iBQXeIhv110W9Do9iSt_V4RRTbWIFBIjEhN_hq94,13
|
|
36
|
+
witbitz_code-1.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Witbitz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
witbitz_code
|