dosync 0.6.1__tar.gz → 0.6.2__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 (155) hide show
  1. {dosync-0.6.1 → dosync-0.6.2}/PKG-INFO +1 -1
  2. {dosync-0.6.1 → dosync-0.6.2}/dosync/__init__.py +1 -1
  3. {dosync-0.6.1 → dosync-0.6.2}/dosync/server.py +21 -1
  4. {dosync-0.6.1 → dosync-0.6.2}/dosync.egg-info/PKG-INFO +1 -1
  5. {dosync-0.6.1 → dosync-0.6.2}/tests/test_server.py +18 -0
  6. {dosync-0.6.1 → dosync-0.6.2}/LICENSE +0 -0
  7. {dosync-0.6.1 → dosync-0.6.2}/README.md +0 -0
  8. {dosync-0.6.1 → dosync-0.6.2}/dosync/adapter_drafting.py +0 -0
  9. {dosync-0.6.1 → dosync-0.6.2}/dosync/adapters/__init__.py +0 -0
  10. {dosync-0.6.1 → dosync-0.6.2}/dosync/adapters/ble.py +0 -0
  11. {dosync-0.6.1 → dosync-0.6.2}/dosync/adapters/declarative.py +0 -0
  12. {dosync-0.6.1 → dosync-0.6.2}/dosync/adapters/homeassistant.py +0 -0
  13. {dosync-0.6.1 → dosync-0.6.2}/dosync/adapters/matter.py +0 -0
  14. {dosync-0.6.1 → dosync-0.6.2}/dosync/adapters/mavlink.py +0 -0
  15. {dosync-0.6.1 → dosync-0.6.2}/dosync/adapters/mqtt.py +0 -0
  16. {dosync-0.6.1 → dosync-0.6.2}/dosync/adapters/notifications.py +0 -0
  17. {dosync-0.6.1 → dosync-0.6.2}/dosync/adapters/shelly.py +0 -0
  18. {dosync-0.6.1 → dosync-0.6.2}/dosync/adapters/wiz.py +0 -0
  19. {dosync-0.6.1 → dosync-0.6.2}/dosync/audit_backup.py +0 -0
  20. {dosync-0.6.1 → dosync-0.6.2}/dosync/auth.py +0 -0
  21. {dosync-0.6.1 → dosync-0.6.2}/dosync/auth_fastapi.py +0 -0
  22. {dosync-0.6.1 → dosync-0.6.2}/dosync/cert_signing.py +0 -0
  23. {dosync-0.6.1 → dosync-0.6.2}/dosync/certify.py +0 -0
  24. {dosync-0.6.1 → dosync-0.6.2}/dosync/cli.py +0 -0
  25. {dosync-0.6.1 → dosync-0.6.2}/dosync/composite_operations.py +0 -0
  26. {dosync-0.6.1 → dosync-0.6.2}/dosync/config_reference.py +0 -0
  27. {dosync-0.6.1 → dosync-0.6.2}/dosync/dashboard.html +0 -0
  28. {dosync-0.6.1 → dosync-0.6.2}/dosync/db.py +0 -0
  29. {dosync-0.6.1 → dosync-0.6.2}/dosync/declarative.py +0 -0
  30. {dosync-0.6.1 → dosync-0.6.2}/dosync/device_arbiter.py +0 -0
  31. {dosync-0.6.1 → dosync-0.6.2}/dosync/discoverers.py +0 -0
  32. {dosync-0.6.1 → dosync-0.6.2}/dosync/discoverers_mdns.py +0 -0
  33. {dosync-0.6.1 → dosync-0.6.2}/dosync/discoverers_ssdp.py +0 -0
  34. {dosync-0.6.1 → dosync-0.6.2}/dosync/discovery.py +0 -0
  35. {dosync-0.6.1 → dosync-0.6.2}/dosync/ed25519_pure.py +0 -0
  36. {dosync-0.6.1 → dosync-0.6.2}/dosync/examples/__init__.py +0 -0
  37. {dosync-0.6.1 → dosync-0.6.2}/dosync/examples/declarative/3d-printer.yaml +0 -0
  38. {dosync-0.6.1 → dosync-0.6.2}/dosync/examples/declarative/air-conditioner.yaml +0 -0
  39. {dosync-0.6.1 → dosync-0.6.2}/dosync/examples/declarative/building-lighting.json +0 -0
  40. {dosync-0.6.1 → dosync-0.6.2}/dosync/examples/declarative/industrial-conveyor.yaml +0 -0
  41. {dosync-0.6.1 → dosync-0.6.2}/dosync/examples/declarative/light-generic.yaml +0 -0
  42. {dosync-0.6.1 → dosync-0.6.2}/dosync/examples/declarative/television.yaml +0 -0
  43. {dosync-0.6.1 → dosync-0.6.2}/dosync/executor.py +0 -0
  44. {dosync-0.6.1 → dosync-0.6.2}/dosync/geo.py +0 -0
  45. {dosync-0.6.1 → dosync-0.6.2}/dosync/hub.py +0 -0
  46. {dosync-0.6.1 → dosync-0.6.2}/dosync/hub_monitor.py +0 -0
  47. {dosync-0.6.1 → dosync-0.6.2}/dosync/lightweight.py +0 -0
  48. {dosync-0.6.1 → dosync-0.6.2}/dosync/manage.py +0 -0
  49. {dosync-0.6.1 → dosync-0.6.2}/dosync/mcp_server.py +0 -0
  50. {dosync-0.6.1 → dosync-0.6.2}/dosync/metrics.py +0 -0
  51. {dosync-0.6.1 → dosync-0.6.2}/dosync/models.py +0 -0
  52. {dosync-0.6.1 → dosync-0.6.2}/dosync/operation_guards.py +0 -0
  53. {dosync-0.6.1 → dosync-0.6.2}/dosync/operation_supervisor.py +0 -0
  54. {dosync-0.6.1 → dosync-0.6.2}/dosync/operations.py +0 -0
  55. {dosync-0.6.1 → dosync-0.6.2}/dosync/paths.py +0 -0
  56. {dosync-0.6.1 → dosync-0.6.2}/dosync/plugins.py +0 -0
  57. {dosync-0.6.1 → dosync-0.6.2}/dosync/policies.py +0 -0
  58. {dosync-0.6.1 → dosync-0.6.2}/dosync/policy_config.py +0 -0
  59. {dosync-0.6.1 → dosync-0.6.2}/dosync/py.typed +0 -0
  60. {dosync-0.6.1 → dosync-0.6.2}/dosync/reconciler.py +0 -0
  61. {dosync-0.6.1 → dosync-0.6.2}/dosync/route_composer.py +0 -0
  62. {dosync-0.6.1 → dosync-0.6.2}/dosync/security.py +0 -0
  63. {dosync-0.6.1 → dosync-0.6.2}/dosync/spec_coverage.py +0 -0
  64. {dosync-0.6.1 → dosync-0.6.2}/dosync/templates/adapter-draft-prompt.md +0 -0
  65. {dosync-0.6.1 → dosync-0.6.2}/dosync/validation.py +0 -0
  66. {dosync-0.6.1 → dosync-0.6.2}/dosync.egg-info/SOURCES.txt +0 -0
  67. {dosync-0.6.1 → dosync-0.6.2}/dosync.egg-info/dependency_links.txt +0 -0
  68. {dosync-0.6.1 → dosync-0.6.2}/dosync.egg-info/entry_points.txt +0 -0
  69. {dosync-0.6.1 → dosync-0.6.2}/dosync.egg-info/requires.txt +0 -0
  70. {dosync-0.6.1 → dosync-0.6.2}/dosync.egg-info/top_level.txt +0 -0
  71. {dosync-0.6.1 → dosync-0.6.2}/pyproject.toml +0 -0
  72. {dosync-0.6.1 → dosync-0.6.2}/setup.cfg +0 -0
  73. {dosync-0.6.1 → dosync-0.6.2}/tests/test_adapter_drafting.py +0 -0
  74. {dosync-0.6.1 → dosync-0.6.2}/tests/test_adapters.py +0 -0
  75. {dosync-0.6.1 → dosync-0.6.2}/tests/test_audit_archive.py +0 -0
  76. {dosync-0.6.1 → dosync-0.6.2}/tests/test_audit_backup.py +0 -0
  77. {dosync-0.6.1 → dosync-0.6.2}/tests/test_audit_chain_integrity.py +0 -0
  78. {dosync-0.6.1 → dosync-0.6.2}/tests/test_audit_provenance.py +0 -0
  79. {dosync-0.6.1 → dosync-0.6.2}/tests/test_auth.py +0 -0
  80. {dosync-0.6.1 → dosync-0.6.2}/tests/test_ble_adapter.py +0 -0
  81. {dosync-0.6.1 → dosync-0.6.2}/tests/test_certification_honesty.py +0 -0
  82. {dosync-0.6.1 → dosync-0.6.2}/tests/test_claim_state_machine.py +0 -0
  83. {dosync-0.6.1 → dosync-0.6.2}/tests/test_composite_operations.py +0 -0
  84. {dosync-0.6.1 → dosync-0.6.2}/tests/test_composite_orchestration.py +0 -0
  85. {dosync-0.6.1 → dosync-0.6.2}/tests/test_composition_kind_db.py +0 -0
  86. {dosync-0.6.1 → dosync-0.6.2}/tests/test_composition_kind_endpoint.py +0 -0
  87. {dosync-0.6.1 → dosync-0.6.2}/tests/test_composition_routing.py +0 -0
  88. {dosync-0.6.1 → dosync-0.6.2}/tests/test_dashboard_tells_the_truth.py +0 -0
  89. {dosync-0.6.1 → dosync-0.6.2}/tests/test_db.py +0 -0
  90. {dosync-0.6.1 → dosync-0.6.2}/tests/test_declarative_adapters.py +0 -0
  91. {dosync-0.6.1 → dosync-0.6.2}/tests/test_declarative_quarantine.py +0 -0
  92. {dosync-0.6.1 → dosync-0.6.2}/tests/test_deployment_env_contract.py +0 -0
  93. {dosync-0.6.1 → dosync-0.6.2}/tests/test_deployment_layout.py +0 -0
  94. {dosync-0.6.1 → dosync-0.6.2}/tests/test_device_health.py +0 -0
  95. {dosync-0.6.1 → dosync-0.6.2}/tests/test_device_heartbeat.py +0 -0
  96. {dosync-0.6.1 → dosync-0.6.2}/tests/test_device_identity.py +0 -0
  97. {dosync-0.6.1 → dosync-0.6.2}/tests/test_direct_action_governance.py +0 -0
  98. {dosync-0.6.1 → dosync-0.6.2}/tests/test_discovery_adoption.py +0 -0
  99. {dosync-0.6.1 → dosync-0.6.2}/tests/test_documentation_is_navigable.py +0 -0
  100. {dosync-0.6.1 → dosync-0.6.2}/tests/test_drone_policies.py +0 -0
  101. {dosync-0.6.1 → dosync-0.6.2}/tests/test_ed25519_pure.py +0 -0
  102. {dosync-0.6.1 → dosync-0.6.2}/tests/test_emergency_preemption.py +0 -0
  103. {dosync-0.6.1 → dosync-0.6.2}/tests/test_env_loading_is_explicit.py +0 -0
  104. {dosync-0.6.1 → dosync-0.6.2}/tests/test_evaluation_metrics.py +0 -0
  105. {dosync-0.6.1 → dosync-0.6.2}/tests/test_event_loop_migration.py +0 -0
  106. {dosync-0.6.1 → dosync-0.6.2}/tests/test_explain_consistency.py +0 -0
  107. {dosync-0.6.1 → dosync-0.6.2}/tests/test_explain_resolve_parity.py +0 -0
  108. {dosync-0.6.1 → dosync-0.6.2}/tests/test_geo.py +0 -0
  109. {dosync-0.6.1 → dosync-0.6.2}/tests/test_ha_bridge_hygiene.py +0 -0
  110. {dosync-0.6.1 → dosync-0.6.2}/tests/test_hub_monitor.py +0 -0
  111. {dosync-0.6.1 → dosync-0.6.2}/tests/test_idempotency.py +0 -0
  112. {dosync-0.6.1 → dosync-0.6.2}/tests/test_independent_observation.py +0 -0
  113. {dosync-0.6.1 → dosync-0.6.2}/tests/test_integration_suite.py +0 -0
  114. {dosync-0.6.1 → dosync-0.6.2}/tests/test_lightweight_heartbeat.py +0 -0
  115. {dosync-0.6.1 → dosync-0.6.2}/tests/test_mavlink_adapter.py +0 -0
  116. {dosync-0.6.1 → dosync-0.6.2}/tests/test_mavlink_channels.py +0 -0
  117. {dosync-0.6.1 → dosync-0.6.2}/tests/test_mavlink_listener.py +0 -0
  118. {dosync-0.6.1 → dosync-0.6.2}/tests/test_mavlink_return_home.py +0 -0
  119. {dosync-0.6.1 → dosync-0.6.2}/tests/test_mavlink_single_reader.py +0 -0
  120. {dosync-0.6.1 → dosync-0.6.2}/tests/test_mavlink_telemetry_closure.py +0 -0
  121. {dosync-0.6.1 → dosync-0.6.2}/tests/test_mcp_dynamic_intents.py +0 -0
  122. {dosync-0.6.1 → dosync-0.6.2}/tests/test_mcp_partial_progress.py +0 -0
  123. {dosync-0.6.1 → dosync-0.6.2}/tests/test_metrics.py +0 -0
  124. {dosync-0.6.1 → dosync-0.6.2}/tests/test_models.py +0 -0
  125. {dosync-0.6.1 → dosync-0.6.2}/tests/test_multihub_endpoints.py +0 -0
  126. {dosync-0.6.1 → dosync-0.6.2}/tests/test_no_operator_data.py +0 -0
  127. {dosync-0.6.1 → dosync-0.6.2}/tests/test_notification_templates.py +0 -0
  128. {dosync-0.6.1 → dosync-0.6.2}/tests/test_operation_guards.py +0 -0
  129. {dosync-0.6.1 → dosync-0.6.2}/tests/test_operation_supervisor.py +0 -0
  130. {dosync-0.6.1 → dosync-0.6.2}/tests/test_operations.py +0 -0
  131. {dosync-0.6.1 → dosync-0.6.2}/tests/test_operations_endpoints.py +0 -0
  132. {dosync-0.6.1 → dosync-0.6.2}/tests/test_operations_persistence.py +0 -0
  133. {dosync-0.6.1 → dosync-0.6.2}/tests/test_operations_wiring.py +0 -0
  134. {dosync-0.6.1 → dosync-0.6.2}/tests/test_panel_polish_2026_07_21.py +0 -0
  135. {dosync-0.6.1 → dosync-0.6.2}/tests/test_policies.py +0 -0
  136. {dosync-0.6.1 → dosync-0.6.2}/tests/test_policy_config.py +0 -0
  137. {dosync-0.6.1 → dosync-0.6.2}/tests/test_public_claims.py +0 -0
  138. {dosync-0.6.1 → dosync-0.6.2}/tests/test_pushed_verification.py +0 -0
  139. {dosync-0.6.1 → dosync-0.6.2}/tests/test_quickstart_is_runnable.py +0 -0
  140. {dosync-0.6.1 → dosync-0.6.2}/tests/test_reachability_cause.py +0 -0
  141. {dosync-0.6.1 → dosync-0.6.2}/tests/test_recall_benchmark_postpolicy.py +0 -0
  142. {dosync-0.6.1 → dosync-0.6.2}/tests/test_reconciler.py +0 -0
  143. {dosync-0.6.1 → dosync-0.6.2}/tests/test_resolution_wiring.py +0 -0
  144. {dosync-0.6.1 → dosync-0.6.2}/tests/test_resolver_scoring.py +0 -0
  145. {dosync-0.6.1 → dosync-0.6.2}/tests/test_resolver_semantics.py +0 -0
  146. {dosync-0.6.1 → dosync-0.6.2}/tests/test_route_composer.py +0 -0
  147. {dosync-0.6.1 → dosync-0.6.2}/tests/test_sensor_kind.py +0 -0
  148. {dosync-0.6.1 → dosync-0.6.2}/tests/test_simulation_is_declared.py +0 -0
  149. {dosync-0.6.1 → dosync-0.6.2}/tests/test_telemetry_bridge.py +0 -0
  150. {dosync-0.6.1 → dosync-0.6.2}/tests/test_third_party_adapters.py +0 -0
  151. {dosync-0.6.1 → dosync-0.6.2}/tests/test_transport_discoverers.py +0 -0
  152. {dosync-0.6.1 → dosync-0.6.2}/tests/test_universal_intent_contract.py +0 -0
  153. {dosync-0.6.1 → dosync-0.6.2}/tests/test_validation.py +0 -0
  154. {dosync-0.6.1 → dosync-0.6.2}/tests/test_validation_integration.py +0 -0
  155. {dosync-0.6.1 → dosync-0.6.2}/tests/test_wiring_audit.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dosync
3
- Version: 0.6.1
3
+ Version: 0.6.2
4
4
  Summary: The semantic layer between AI agents and physical devices
5
5
  Author-email: Rodrigo Giuliani <rgiuliani@dosync.dev>
6
6
  License-Expression: Apache-2.0
@@ -13,5 +13,5 @@ The two numbers move independently on purpose:
13
13
  __version__ this implementation of the hub (semver)
14
14
  __protocol_version__ the wire contract other implementations must match
15
15
  """
16
- __version__ = "0.6.1"
16
+ __version__ = "0.6.2"
17
17
  __protocol_version__ = "0.4"
@@ -12,7 +12,8 @@ import json
12
12
  import os
13
13
  import re
14
14
  from fastapi import Depends, FastAPI, HTTPException, Request, WebSocket, WebSocketDisconnect
15
- from fastapi.responses import FileResponse, HTMLResponse, PlainTextResponse
15
+ from fastapi.responses import (FileResponse, HTMLResponse, JSONResponse,
16
+ PlainTextResponse)
16
17
  from fastapi.staticfiles import StaticFiles
17
18
  from pydantic import BaseModel, field_validator
18
19
 
@@ -933,7 +934,26 @@ async def lifespan(app: FastAPI):
933
934
  log.warning("Could not flush the audit head on shutdown: %s", _fh_e)
934
935
  log.info("DoSync Hub shutting down")
935
936
 
937
+ class _UTF8JSONResponse(JSONResponse):
938
+ """`application/json; charset=utf-8`, said out loud rather than assumed.
939
+
940
+ JSON is UTF-8 by definition and FastAPI therefore omits the charset — which
941
+ is correct and, for one widely used client, useless. Windows PowerShell 5.1
942
+ falls back to Latin-1 when a response does not declare one, so an operator
943
+ following this project's own Windows instructions saw
944
+ `read-only status query â device has no sensors` where an em dash belonged,
945
+ and would see the same for every accented character a deployment uses in a
946
+ device name.
947
+
948
+ Being right about the specification while a reader gets mojibake is the
949
+ kind of correctness this project has decided is not worth much.
950
+ """
951
+
952
+ media_type = "application/json; charset=utf-8"
953
+
954
+
936
955
  app = FastAPI(
956
+ default_response_class=_UTF8JSONResponse,
937
957
  title="DoSync Hub",
938
958
  description=(
939
959
  "DoSync Protocol — REST API\n\n"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dosync
3
- Version: 0.6.1
3
+ Version: 0.6.2
4
4
  Summary: The semantic layer between AI agents and physical devices
5
5
  Author-email: Rodrigo Giuliani <rgiuliani@dosync.dev>
6
6
  License-Expression: Apache-2.0
@@ -199,3 +199,21 @@ def test_the_shipped_gpio_adapter_uses_the_current_endpoint():
199
199
  src = (REPO / "gpio_adapter.py").read_text()
200
200
  assert 'hub_post("/v1/intent/async"' in src
201
201
  assert 'hub_post("/v1/intent"' not in src
202
+
203
+
204
+ def test_json_responses_declare_utf8():
205
+ """`read-only status query â device has no sensors to read`.
206
+
207
+ That is what a Windows operator saw following this project's own
208
+ instructions. JSON is UTF-8 by definition, so FastAPI omits the charset —
209
+ correct, and useless for Windows PowerShell 5.1, which falls back to
210
+ Latin-1 when a response does not declare one. Every em dash and every
211
+ accented character in a device name arrives mangled.
212
+
213
+ The README documents `Invoke-RestMethod` as the way to call this API from
214
+ Windows, so the tool it recommends was the one showing broken text.
215
+ """
216
+ response = client.get("/v1/status")
217
+ assert "charset=utf-8" in response.headers.get("content-type", "").lower(), (
218
+ "JSON responses do not declare their charset, so clients that guess "
219
+ "wrongly — PowerShell 5.1 among them — mangle every non-ASCII byte")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes