witbitz-code 1.3.3__tar.gz → 1.3.4__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.
Files changed (80) hide show
  1. {witbitz_code-1.3.3/src/witbitz_code.egg-info → witbitz_code-1.3.4}/PKG-INFO +1 -1
  2. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/pyproject.toml +1 -1
  3. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/__init__.py +1 -1
  4. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/codekeys.py +3 -12
  5. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/payers.py +1 -7
  6. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/uninstall.py +1 -1
  7. {witbitz_code-1.3.3 → witbitz_code-1.3.4/src/witbitz_code.egg-info}/PKG-INFO +1 -1
  8. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code.egg-info/SOURCES.txt +2 -1
  9. witbitz_code-1.3.4/tests/test_windows_files.py +28 -0
  10. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/LICENSE +0 -0
  11. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/README.md +0 -0
  12. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/setup.cfg +0 -0
  13. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/__main__.py +0 -0
  14. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/_js.py +0 -0
  15. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/account.py +0 -0
  16. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/asks.py +0 -0
  17. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/attachments.py +0 -0
  18. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/auto.py +0 -0
  19. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/auto_runner.py +0 -0
  20. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/cli.py +0 -0
  21. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/codetools.py +0 -0
  22. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/compress.py +0 -0
  23. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/computers.py +0 -0
  24. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/confidential.py +0 -0
  25. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/confidential_models.json +0 -0
  26. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/connector.py +0 -0
  27. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/devicelink.py +0 -0
  28. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/folders.py +0 -0
  29. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/gateway.py +0 -0
  30. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/keys.py +0 -0
  31. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/link.py +0 -0
  32. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/models.py +0 -0
  33. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/net.py +0 -0
  34. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/offered_models.json +0 -0
  35. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/opencode_plugins/notes-init.md +0 -0
  36. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/opencode_plugins/witbitz-media-server.mjs +0 -0
  37. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/opencode_plugins/witbitz-notes.js +0 -0
  38. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/opencode_plugins/witbitz-progress.js +0 -0
  39. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/outputs.py +0 -0
  40. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/pair.py +0 -0
  41. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/pairings.py +0 -0
  42. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/plugins.py +0 -0
  43. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/policy.py +0 -0
  44. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/ports.py +0 -0
  45. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/qr.py +0 -0
  46. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/receipt.py +0 -0
  47. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/relay.py +0 -0
  48. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/seen.py +0 -0
  49. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/tinfoil_read.py +0 -0
  50. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/tools_probe.py +0 -0
  51. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/winagent.py +0 -0
  52. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/winconsole.py +0 -0
  53. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code/wizard.py +0 -0
  54. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code.egg-info/dependency_links.txt +0 -0
  55. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code.egg-info/entry_points.txt +0 -0
  56. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code.egg-info/requires.txt +0 -0
  57. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/src/witbitz_code.egg-info/top_level.txt +0 -0
  58. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_asks.py +0 -0
  59. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_attachments.py +0 -0
  60. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_auto.py +0 -0
  61. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_cli.py +0 -0
  62. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_codekeys.py +0 -0
  63. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_codetools.py +0 -0
  64. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_confidential.py +0 -0
  65. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_connector_e2e.py +0 -0
  66. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_devicelink.py +0 -0
  67. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_files_and_compress.py +0 -0
  68. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_folders.py +0 -0
  69. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_outputs.py +0 -0
  70. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_pair_flows.py +0 -0
  71. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_plugins.py +0 -0
  72. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_policy.py +0 -0
  73. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_ports.py +0 -0
  74. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_registry.py +0 -0
  75. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_relay_codec.py +0 -0
  76. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_setup.py +0 -0
  77. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_tools_probe.py +0 -0
  78. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_uninstall.py +0 -0
  79. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_winagent.py +0 -0
  80. {witbitz_code-1.3.3 → witbitz_code-1.3.4}/tests/test_winconsole.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: witbitz-code
3
- Version: 1.3.3
3
+ Version: 1.3.4
4
4
  Summary: Reach OpenCode on this computer from the Witbitz Spaces Code section, through an end-to-end sealed relay.
5
5
  Author: Witbitz
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "witbitz-code"
7
- version = "1.3.3"
7
+ version = "1.3.4"
8
8
  description = "Reach OpenCode on this computer from the Witbitz Spaces Code section, through an end-to-end sealed relay."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -4,4 +4,4 @@ The Python implementation of tools/witbitz-code.mjs (docs/opencode-relay.md phas
4
4
  vectors and cross-implementation tests.
5
5
  """
6
6
 
7
- __version__ = "1.3.3"
7
+ __version__ = "1.3.4"
@@ -15,7 +15,6 @@ from __future__ import annotations
15
15
  import base64
16
16
  import json
17
17
  import os
18
- import tempfile
19
18
  import time
20
19
  from email.utils import parsedate_to_datetime
21
20
  from pathlib import Path
@@ -147,17 +146,9 @@ def read_all() -> dict:
147
146
 
148
147
 
149
148
  def _write_all(doc: dict) -> None:
150
- path = keys_path()
151
- path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
152
- fd, tmp = tempfile.mkstemp(dir=str(path.parent), prefix=".account-keys.")
153
- try:
154
- os.fchmod(fd, 0o600)
155
- with os.fdopen(fd, "w", encoding="utf-8") as f:
156
- f.write(json.dumps(doc, indent=1) + "\n")
157
- os.replace(tmp, path)
158
- except BaseException:
159
- Path(tmp).unlink(missing_ok=True)
160
- raise
149
+ # pairings.write_private: 0600, atomic, and Windows-safe (Windows Python 3.12 has no os.fchmod — the owner's native
150
+ # Windows pairing died here, the real error hidden by a cleanup that could not delete the still-open temp file).
151
+ pp.write_private(keys_path(), json.dumps(doc, indent=1) + "\n")
161
152
 
162
153
 
163
154
  def for_computer(computer_id: str) -> dict | None:
@@ -16,7 +16,6 @@ from __future__ import annotations
16
16
 
17
17
  import json
18
18
  import os
19
- import tempfile
20
19
  import threading
21
20
  from pathlib import Path
22
21
 
@@ -49,12 +48,7 @@ class SessionPayers:
49
48
  if not self._persist:
50
49
  return
51
50
  try:
52
- self._path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
53
- fd, tmp = tempfile.mkstemp(dir=str(self._path.parent), prefix=".session-payers.")
54
- os.fchmod(fd, 0o600)
55
- with os.fdopen(fd, "w", encoding="utf-8") as f:
56
- f.write(json.dumps({"v": 1, "owners": self._owner}))
57
- os.replace(tmp, self._path)
51
+ pp.write_private(self._path, json.dumps({"v": 1, "owners": self._owner})) # Windows-safe (no os.fchmod there)
58
52
  except OSError:
59
53
  pass # memory still knows; a restart forgets, and a forgotten conversation is refused, never misbilled
60
54
 
@@ -170,7 +170,7 @@ def stop_process(pid: int) -> bool:
170
170
  if gone():
171
171
  return True
172
172
  try:
173
- os.kill(pid, signal.SIGKILL)
173
+ os.kill(pid, getattr(signal, "SIGKILL", signal.SIGTERM)) # Windows has no SIGKILL
174
174
  except OSError:
175
175
  pass
176
176
  time.sleep(0.3)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: witbitz-code
3
- Version: 1.3.3
3
+ Version: 1.3.4
4
4
  Summary: Reach OpenCode on this computer from the Witbitz Spaces Code section, through an end-to-end sealed relay.
5
5
  Author: Witbitz
6
6
  License-Expression: MIT
@@ -74,4 +74,5 @@ tests/test_setup.py
74
74
  tests/test_tools_probe.py
75
75
  tests/test_uninstall.py
76
76
  tests/test_winagent.py
77
- tests/test_winconsole.py
77
+ tests/test_winconsole.py
78
+ tests/test_windows_files.py
@@ -0,0 +1,28 @@
1
+ """Private files on Windows (the owner's native Windows run, 2026-10-08: pairing succeeded, then "FATAL — [WinError 32] The
2
+ process cannot access the file because it is being used by another process: …\\.account-keys.<tmp>"). Windows Python 3.12
3
+ (the installer's) has no os.fchmod; the keys writer called it on the open temp file, and its cleanup then tried to delete
4
+ that still-open file — which Windows refuses, hiding the real error. Every private file goes through pairings.write_private."""
5
+
6
+ import os
7
+ from pathlib import Path
8
+
9
+ from witbitz_code import codekeys
10
+ from witbitz_code.payers import SessionPayers
11
+
12
+ SRC = Path(__file__).resolve().parent.parent / "src" / "witbitz_code"
13
+
14
+
15
+ def test_the_keys_and_payers_files_are_written_where_python_has_no_fchmod(monkeypatch):
16
+ from fakes import give_code_keys
17
+
18
+ monkeypatch.delattr(os, "fchmod", raising=False)
19
+ e = give_code_keys("cmp_win")
20
+ assert codekeys.for_computer("cmp_win")["keyId"] == e["keyId"]
21
+ p = SessionPayers()
22
+ assert p.begin("ses_W", "cmp_win")
23
+ assert SessionPayers().payer("ses_W") == "cmp_win", "the payer was saved, not lost to an AttributeError"
24
+
25
+
26
+ def test_no_module_calls_fchmod():
27
+ hits = [f.name for f in SRC.glob("*.py") if "os.fchmod(" in f.read_text(encoding="utf-8")]
28
+ assert hits == [], f"os.fchmod does not exist on Windows Python before 3.13 — use pairings.write_private: {hits}"
File without changes
File without changes
File without changes