dosync 0.4.1__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.
dosync/validation.py ADDED
@@ -0,0 +1,98 @@
1
+ """
2
+ DoSync — Parameter Schema Validation
3
+ ====================================
4
+ Validates actuator parameter schemas (and, optionally, incoming action params)
5
+ against JSON Schema draft 2020-12.
6
+
7
+ Two distinct validations, per the design panel:
8
+
9
+ 1. MANIFEST validation (integrity of the standard): when a device registers, is
10
+ each actuator's `params_schema` itself a well-formed JSON Schema? This protects
11
+ the standard — a manifest claiming JSON Schema must actually be valid JSON Schema.
12
+
13
+ 2. PARAMS validation (execution policy, optional): when an action is about to run,
14
+ do the supplied params satisfy the actuator's schema? This is a per-request
15
+ policy — it can be disabled on the emergency path where latency matters.
16
+
17
+ Graceful degradation (panel condition): the `jsonschema` library is an OPTIONAL
18
+ dependency. If it is not installed, the hub still runs — validation is skipped with
19
+ a visible warning, never a hard failure. The dumb device never needs this library;
20
+ validation is the hub's responsibility.
21
+
22
+ The protocol commits to JSON Schema draft 2020-12 in the spec. The library is an
23
+ implementation choice of this reference implementation, not part of the standard.
24
+ """
25
+
26
+ from __future__ import annotations
27
+ import logging
28
+
29
+ log = logging.getLogger("dosync.validation")
30
+
31
+ try:
32
+ from jsonschema import Draft202012Validator
33
+ from jsonschema.exceptions import SchemaError, ValidationError
34
+ _JSONSCHEMA_AVAILABLE = True
35
+ except Exception: # pragma: no cover - depends on host
36
+ Draft202012Validator = None # type: ignore
37
+ SchemaError = ValidationError = Exception # type: ignore
38
+ _JSONSCHEMA_AVAILABLE = False
39
+
40
+
41
+ def jsonschema_available() -> bool:
42
+ """Whether schema validation is active on this host."""
43
+ return _JSONSCHEMA_AVAILABLE
44
+
45
+
46
+ def is_valid_json_schema(schema: dict) -> tuple[bool, str | None]:
47
+ """Check that `schema` is itself a well-formed JSON Schema (draft 2020-12).
48
+
49
+ An empty dict {} means 'no parameters' and is treated as valid.
50
+ Returns (ok, error_message). If jsonschema is unavailable, returns (True, None)
51
+ with a logged warning — degradation, not failure.
52
+ """
53
+ if not schema:
54
+ return True, None
55
+ if not _JSONSCHEMA_AVAILABLE:
56
+ log.warning("Schema validation skipped — jsonschema not installed")
57
+ return True, None
58
+ try:
59
+ Draft202012Validator.check_schema(schema)
60
+ return True, None
61
+ except SchemaError as e:
62
+ return False, f"invalid JSON Schema: {e.message}"
63
+
64
+
65
+ def validate_manifest_schemas(manifest) -> list[str]:
66
+ """Validate every actuator's params_schema in a manifest.
67
+
68
+ Returns a list of human-readable problems (empty list = all valid). Used at
69
+ device registration to protect the integrity of the standard.
70
+ """
71
+ problems: list[str] = []
72
+ for actuator in getattr(manifest, "actuators", []):
73
+ schema = getattr(actuator, "params_schema", None) or {}
74
+ ok, err = is_valid_json_schema(schema)
75
+ if not ok:
76
+ problems.append(f"actuator '{actuator.type}': {err}")
77
+ return problems
78
+
79
+
80
+ def validate_params(schema: dict, params: dict) -> tuple[bool, str | None]:
81
+ """Validate action params against an actuator's JSON Schema.
82
+
83
+ Returns (ok, error_message). Empty schema accepts anything. If jsonschema is
84
+ unavailable, returns (True, None) — degradation, not failure. This is the
85
+ OPTIONAL per-request validation; callers may skip it on the emergency path.
86
+ """
87
+ if not schema:
88
+ return True, None
89
+ if not _JSONSCHEMA_AVAILABLE:
90
+ return True, None
91
+ try:
92
+ Draft202012Validator(schema).validate(params or {})
93
+ return True, None
94
+ except ValidationError as e:
95
+ return False, f"parameter validation failed: {e.message}"
96
+ except SchemaError as e:
97
+ # The schema itself is broken — report distinctly from a params problem.
98
+ return False, f"actuator schema is invalid: {e.message}"
@@ -0,0 +1,372 @@
1
+ Metadata-Version: 2.4
2
+ Name: dosync
3
+ Version: 0.4.1
4
+ Summary: The semantic layer between AI agents and physical devices
5
+ Author-email: Rodrigo Giuliani <rgiuliani@dosync.dev>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://dosync.dev
8
+ Project-URL: Repository, https://github.com/giulianireg-spec/dosync-protocol
9
+ Project-URL: Specification, https://github.com/giulianireg-spec/dosync-protocol/blob/main/spec/DoSync-SPEC-v0.1.md
10
+ Project-URL: Issues, https://github.com/giulianireg-spec/dosync-protocol/issues
11
+ Keywords: iot,ai-agents,protocol,semantic,orchestration,audit,governance,mcp,home-automation,robotics
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Home Automation
21
+ Classifier: Topic :: System :: Distributed Computing
22
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: fastapi<1.0,>=0.115.0
27
+ Requires-Dist: uvicorn<1.0,>=0.23.0
28
+ Requires-Dist: pydantic<3.0,>=2.7.0
29
+ Requires-Dist: jsonschema<5.0,>=4.18
30
+ Provides-Extra: wiz
31
+ Requires-Dist: pywizlight>=0.5.0; extra == "wiz"
32
+ Provides-Extra: mqtt
33
+ Requires-Dist: paho-mqtt>=2.0.0; extra == "mqtt"
34
+ Provides-Extra: ha
35
+ Requires-Dist: aiohttp>=3.8.0; extra == "ha"
36
+ Provides-Extra: ble
37
+ Requires-Dist: bleak>=0.21; extra == "ble"
38
+ Provides-Extra: sms
39
+ Requires-Dist: twilio>=8.0.0; extra == "sms"
40
+ Provides-Extra: mavlink
41
+ Requires-Dist: pymavlink>=2.4.0; extra == "mavlink"
42
+ Provides-Extra: mcp
43
+ Requires-Dist: mcp>=1.0.0; extra == "mcp"
44
+ Provides-Extra: all
45
+ Requires-Dist: pywizlight>=0.5.0; extra == "all"
46
+ Requires-Dist: paho-mqtt>=2.0.0; extra == "all"
47
+ Requires-Dist: aiohttp>=3.8.0; extra == "all"
48
+ Requires-Dist: bleak>=0.21; extra == "all"
49
+ Requires-Dist: twilio>=8.0.0; extra == "all"
50
+ Requires-Dist: pymavlink>=2.4.0; extra == "all"
51
+ Requires-Dist: mcp>=1.0.0; extra == "all"
52
+ Provides-Extra: dev
53
+ Requires-Dist: pytest>=7.4; extra == "dev"
54
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
55
+ Requires-Dist: httpx>=0.27; extra == "dev"
56
+ Dynamic: license-file
57
+
58
+ # DoSync Protocol
59
+
60
+ > The semantic layer between AI agents and physical devices.
61
+
62
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
63
+ [![Protocol](https://img.shields.io/badge/protocol-v0.4-green.svg)](spec/DoSync-SPEC-v0.1.md)
64
+ [![PyPI](https://img.shields.io/pypi/v/dosync.svg)](https://pypi.org/project/dosync/)
65
+ [![Python](https://img.shields.io/pypi/pyversions/dosync.svg)](https://pypi.org/project/dosync/)
66
+ [![CI](https://github.com/giulianireg-spec/dosync-protocol/actions/workflows/ci.yml/badge.svg)](https://github.com/giulianireg-spec/dosync-protocol/actions/workflows/ci.yml)
67
+ [![Certification](https://img.shields.io/badge/certification-Conformance%2052%2F52-orange.svg)](dosync/certify.py)
68
+ [![MCP](https://img.shields.io/badge/MCP-compatible-purple.svg)](dosync/mcp_server.py)
69
+
70
+ ---
71
+
72
+ ## The problem
73
+
74
+ Today's IoT protocols speak the language of commands. AI speaks the language of goals.
75
+
76
+ ```python
77
+ # Existing protocols
78
+ lock.unlock()
79
+ light.set_brightness(100)
80
+ thermostat.set_temperature(21)
81
+
82
+ # What an AI actually expresses
83
+ "there is an emergency at home"
84
+ "nobody is home — save energy"
85
+ "good morning"
86
+ ```
87
+
88
+ Someone has to translate. Today, that translation is custom code written per-device, per-platform, per-scenario. It breaks when you add a new device. It completely fails in emergencies where milliseconds matter.
89
+
90
+ **DoSync is the bridge.**
91
+
92
+ ---
93
+
94
+ ## What it does
95
+
96
+ DoSync is an open protocol (Apache 2.0) that lets AI systems interact with physical devices using **semantic intent** — expressing *what they want to achieve*, not *how to achieve it*.
97
+
98
+ When the hub receives `"ensure_safety / emergency"`, every registered device figures out its own role automatically based on its declared capabilities — no hardcoded rules, no manual configuration.
99
+
100
+ ---
101
+
102
+ ## Scope and safety boundaries
103
+
104
+ DoSync coordinates **non-safety-critical systems** — lighting, access, climate, notifications, logging — and produces a tamper-evident record of every action. It is infrastructure for coordination and auditability, not a certified safety system.
105
+
106
+ DoSync is **not** certified to IEC 61508 / IEC 62304 / ISO 13849 and must not be the sole or primary mechanism for:
107
+
108
+ - Primary control of medical devices or life-support systems
109
+ - Fire suppression, gas detection, or emergency shutdown of SIL-rated machinery
110
+ - Any function where a failure could cause injury or loss of life
111
+
112
+ In regulated or industrial environments, DoSync **complements** the certified safety systems already in place — coordinating the peripherals around them and recording what happened — but never replaces them. The certified safety system remains in charge of safety.
113
+
114
+ See [Protocol Specification §12.3](spec/DoSync-SPEC-v0.1.md) for the full operational boundaries.
115
+
116
+ ---
117
+
118
+ ## Is DoSync for you?
119
+
120
+ DoSync earns its place in specific situations — and honestly gets in the way in others. A quick filter:
121
+
122
+ **It probably fits if you:**
123
+ - Are building an **AI agent that acts on physical devices** and need an auditable record of what it did, when, and why.
124
+ - Coordinate **heterogeneous devices** (different brands / transports) and want one semantic layer — express a goal, devices resolve it — with a tamper-evident audit trail.
125
+ - Work in **robotics or physical automation** and want a policy + safety layer (emergency preemption, confirmation policies) *between* the AI and the actuators.
126
+ - Keep hand-writing per-device command sequences and wish you could just say *"secure the space."*
127
+
128
+ **It's probably not for you if you:**
129
+ - Want home automation (schedules, motion → light). [Home Assistant](https://www.home-assistant.io/) and its automations — and its MCP server — already do that better; DoSync would be overhead.
130
+ - Have a single device or one brand's ecosystem — you don't need a coordination layer.
131
+ - Don't need auditability or a policy layer.
132
+
133
+ **If the first list is you:** the fastest way in is the **[20-minute device tutorial](TUTORIAL.md)** — build a device that senses, expresses a goal, and acts, with the full audit trail. Or open an [issue](https://github.com/giulianireg-spec/dosync-protocol/issues) describing what you're trying to coordinate and we'll tell you honestly whether DoSync fits.
134
+
135
+ ---
136
+
137
+ ## Demo
138
+
139
+ [![DoSync Demo](https://img.shields.io/badge/▶_Watch_Demo-YouTube-red?style=for-the-badge)](https://youtu.be/2czAqoIrd08)
140
+
141
+ **What you'll see:** Claude AI triggers a physical emergency protocol in real time — 10 Philips WiZ bulbs at full brightness, SMS notification sent, audit log updated. No commands. No rules. No cloud.
142
+
143
+ ---
144
+
145
+ ## How it works
146
+
147
+ ```
148
+ User / AI says: "there is an emergency at home"
149
+ │
150
+ DoSync Hub v0.3.0
151
+ │
152
+ ┌───────────────┼───────────────┐
153
+ ▼ ▼ ▼
154
+ 💡 All lights 📱 SMS sent 🚨 Alarm
155
+ at maximum to family activated
156
+ (10 WiZ bulbs) immediately
157
+ │ │ │
158
+ └───────────────┴───────────────┘
159
+ │
160
+ Audit log updated
161
+ (SHA-256 tamper-evident)
162
+ ```
163
+
164
+ The **Capability-based Resolver** matches the intent against every device's **Capability Manifest** — what it can sense, what it can do, whether it's emergency-capable. No rules to write. Add a new device and it participates automatically.
165
+
166
+ Benchmark (Raspberry Pi 5, Python 3.11.2):
167
+
168
+ | Devices | Mean | p99 | Within 500ms limit |
169
+ |---|---|---|---|
170
+ | 38 (production) | 0.076ms | 0.097ms | ✓ |
171
+ | 1000 | 1.336ms | 5.690ms | ✓ |
172
+ | 5000 | 9.163ms | 24.541ms | ✓ (20× margin) |
173
+
174
+ ---
175
+
176
+ ## Protocol architecture
177
+
178
+ | Layer | Name | Role |
179
+ |---|---|---|
180
+ | 5 | **Intent** | AI expresses semantic goals |
181
+ | 4 | **Semantic** | Resolver maps intent → device actions |
182
+ | 3 | **Registry** | Devices self-declare capabilities on join |
183
+ | 2 | **Secure channel** | mTLS, local PKI — no internet required |
184
+ | 1 | **Transport (HAL)** | Reference: WiFi/HTTP-WS · MQTT. Via bridge: Zigbee · Z-Wave · Thread · Matter (Home Assistant). Native BLE/radio bindings: roadmap |
185
+
186
+ ---
187
+
188
+ ## Quick start
189
+
190
+ ### Install and run — five minutes, no hardware
191
+
192
+ ```bash
193
+ pip install dosync
194
+ dosync-hub
195
+ ```
196
+
197
+ That is a working hub on `http://127.0.0.1:47200`. It starts with a simulated
198
+ executor, so you can drive the whole protocol — register devices, fire intents,
199
+ read the audit chain — before you own a single smart device.
200
+
201
+ Register something and give it a goal:
202
+
203
+ ```bash
204
+ # 1. A device declares what it CAN DO (not what commands it takes)
205
+ curl -X POST http://127.0.0.1:47200/v1/devices/register \
206
+ -H 'Content-Type: application/json' -d '{
207
+ "device_id": "siren-hall", "device_name": "Hall Siren",
208
+ "manufacturer": "acme", "model": "S1", "firmware": "1.0",
209
+ "category": "actuator", "tags": ["alarm", "emergency"],
210
+ "emergency_capable": true, "cert_tier": "basic",
211
+ "sensors": [], "actuators": [{"id": "alarm", "type": "alarm",
212
+ "description": "audible alarm"}]}'
213
+
214
+ # 2. An AI expresses a GOAL — not a command, and it names no device
215
+ curl -X POST http://127.0.0.1:47200/v1/intent/async \
216
+ -H 'Content-Type: application/json' \
217
+ -d '{"intent": "ensure_safety", "urgency": "emergency", "context": {}}'
218
+
219
+ # 3. Ask WHY those devices were chosen
220
+ curl http://127.0.0.1:47200/v1/intents/ensure_safety/explain
221
+
222
+ # 4. Read the tamper-evident record of what happened
223
+ curl http://127.0.0.1:47200/v1/audit?limit=10
224
+ ```
225
+
226
+ Step 3 is the one worth pausing on: the hub tells you which devices it
227
+ evaluated, which it included, and the score breakdown behind each decision.
228
+ Step 4 is the other: every action leaves a SHA-256-chained entry, so what the
229
+ system did is provable after the fact rather than merely logged.
230
+
231
+ Install only the adapters you need:
232
+
233
+ ```bash
234
+ pip install 'dosync[wiz]' # Philips WiZ bulbs
235
+ pip install 'dosync[ha]' # Home Assistant bridge
236
+ pip install 'dosync[mqtt]' # MQTT devices
237
+ pip install 'dosync[all]' # everything
238
+ ```
239
+
240
+ ### Docker
241
+
242
+ ```bash
243
+ docker run -p 47200:47200 dosync/hub # published image
244
+ # or, from a clone:
245
+ docker compose up
246
+ ```
247
+
248
+ ### From source (development)
249
+
250
+ ```bash
251
+ git clone https://github.com/giulianireg-spec/dosync-protocol
252
+ cd dosync-protocol
253
+ python3 -m venv venv && source venv/bin/activate
254
+ pip install -e '.[dev]'
255
+ pytest # 667 tests
256
+ dosync-hub --reload
257
+ ```
258
+
259
+ ---
260
+
261
+ ## What's built today
262
+
263
+ | Component | Status |
264
+ |---|---|
265
+ | REST API (12+ endpoints) | ✅ |
266
+ | WebSocket real-time events | ✅ |
267
+ | Web dashboard | ✅ |
268
+ | API key authentication + SHA-256 audit log | ✅ |
269
+ | Capability-based resolver | ✅ |
270
+ | Certification CLI — Standard 33/33 · Emergency 44/44 (signed reports) | ✅ |
271
+ | Philips WiZ adapter (UDP local) | ✅ |
272
+ | Home Assistant bridge (10 domains) | ✅ |
273
+ | Native MCP server (Claude, ChatGPT, any LLM) | ✅ |
274
+ | GPIO adapter — Raspberry Pi 5 (PIR + DHT22) | ✅ |
275
+ | SMS notifications via Twilio | ✅ code (requires an active Twilio plan) |
276
+ | MQTT transport adapter (Mosquitto) | ✅ |
277
+ | Shelly adapter (HTTP local, Gen1 + Gen2) | ✅ code, not hardware-tested |
278
+ | Matter adapter (via HA bridge / python-matter-server) | ✅ code, not hardware-tested |
279
+ | External Resolver Protocol (HTTP wire format) | ✅ |
280
+ | SQLite persistence (survives restarts) | ✅ |
281
+ | CI pipeline (GitHub Actions) | ✅ |
282
+ | Multi-hub assisted failover (Phase A — operator-in-the-loop) | ✅ |
283
+ | Long-running operations + telemetry reconciliation (state machine) | ✅ |
284
+ | Drone / MAVLink adapter — full AI→intent→mission loop in ArduPilot SITL | ✅ software (physical flight pending) |
285
+
286
+ ---
287
+
288
+ ## MQTT transport
289
+
290
+ DoSync supports MQTT as a Layer 1 transport for devices that can't use HTTP. Requires Mosquitto and proper authentication. See [config/mosquitto-secure.conf](config/mosquitto-secure.conf) for secure setup.
291
+
292
+ ```bash
293
+ # Enable MQTT in the hub service
294
+ Environment="DOSYNC_MQTT_BROKER=localhost"
295
+ Environment="DOSYNC_MQTT_USER=dosync-hub"
296
+ Environment="DOSYNC_MQTT_PASSWORD=<password>"
297
+ Environment="DOSYNC_MQTT_SECRET=<registration-secret>"
298
+ ```
299
+
300
+ ---
301
+
302
+ ## Certification
303
+
304
+ Self-certifiable with the CLI:
305
+
306
+ ```bash
307
+ python3 certify.py --host <hub-ip> --port 47200 --tier standard
308
+ # Output: dosync-cert-standard-*.json
309
+ ```
310
+
311
+ | Tier | Tests | What it validates |
312
+ |---|---|---|
313
+ | **Basic** | 10 | Connectivity, auth, device manifest |
314
+ | **Standard** | 33 | Protocol conformance, events, health, version headers |
315
+ | **Emergency** | 44 | Everything in Standard + emergency override, policy engine, audit log integrity |
316
+
317
+ ---
318
+
319
+ ## Implementations
320
+
321
+ | Language | Location | Author | Certification |
322
+ |---|---|---|---|
323
+ | Python (reference) | `server.py` | this project | Standard 33/33 · Emergency 44/44 ✅ |
324
+ | Node.js (companion) | [giulianireg-spec/dosync-node](https://github.com/giulianireg-spec/dosync-node) | this project | 33/33 Standard ✅ |
325
+
326
+ The Node.js implementation is a **companion** port that validates the protocol
327
+ is implementable in a second language against the same certification suite —
328
+ both share the same author. A genuinely **independent** implementation
329
+ (different author or organization) is a tracked milestone for v1.0: a protocol
330
+ needs multiple independent implementations to become a standard. See the
331
+ [roadmap](ROADMAP.md).
332
+
333
+ ---
334
+
335
+ ## Works with Home Assistant — a layer on top, not a replacement
336
+
337
+ Home Assistant already solved the hardest problem: talking to thousands of devices, and since 2025 it ships an MCP server so an AI can control them directly. DoSync doesn't reinvent that — it reads devices from HA through a bridge already in the repo and adds **one thing**: it turns a semantic goal (`ensure_safety`, `away_mode`) into a coordinated, **auditable** set of actions across *any* source (HA, WiZ, GPIO, MQTT, BLE).
338
+
339
+ The honest version: for everyday automation ("porch light when I get home") you **don't need DoSync** — HA's automations and its MCP cover that completely. DoSync earns its place only when **coordination and traceability matter at once** — e.g. a fall-response that unlocks the door, lights the house, and messages family, with a tamper-evident record of exactly what fired and when. Full reasoning: [Home Assistant Already Talks to Your Devices. So What Would DoSync Add?](https://dev.to/giulianiregspec/home-assistant-already-talks-to-your-devices-so-what-would-dosync-add-1iei)
340
+
341
+ ---
342
+
343
+ ## Beyond the home
344
+
345
+ Nothing in DoSync assumes a house — the same 5-layer stack coordinates physical systems anywhere an AI needs to act: retail cold-chain, hotels, factory peripherals (alongside certified safety systems, never replacing them).
346
+
347
+ The proof: we took it to the hardest device, an **autonomous drone**. From a single plain-language sentence, an AI model (Claude Haiku, via DoSync's MCP server) fired an `inspect_area` intent and the drone flew the full mission in ArduPilot SITL — every step confirmed by real telemetry. When the AI guessed coordinates 11,000 km away, the supervisor didn't fake success: it waited for a confirmed arrival, none came, and it aborted with a clear diagnosis. **The AI can be wrong; the protocol doesn't have to be.** [Full build log](https://dev.to/giulianiregspec/i-gave-an-ai-one-sentence-a-drone-flew-the-mission-and-when-the-ai-guessed-wrong-the-system-2h3m) · *(validated in SITL; physical-hardware flight is the next step, not a claim made today.)*
348
+
349
+ ---
350
+
351
+ ## Contributing
352
+
353
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development workflow, including the CI pipeline that runs on every push.
354
+
355
+ ---
356
+
357
+ ## Specification
358
+
359
+ - [spec/DoSync-SPEC-v0.1.md](spec/DoSync-SPEC-v0.1.md) — full protocol specification
360
+ - [spec/RESOLVER-SPEC-v0.3.md](spec/RESOLVER-SPEC-v0.3.md) — resolver interface + external resolver protocol
361
+ - [DESIGN-PRINCIPLES.md](DESIGN-PRINCIPLES.md) — architectural decisions and rationale
362
+ - [COMPATIBILITY.md](COMPATIBILITY.md) — backward compatibility guarantees
363
+
364
+ ---
365
+
366
+ ## License
367
+
368
+ Apache 2.0 — free to implement, free to extend, no royalties.
369
+
370
+ ---
371
+
372
+ *DoSync Protocol v0.3.0 · © 2026 Rodrigo Giuliani · rgiuliani@dosync.dev*
@@ -0,0 +1,46 @@
1
+ dosync/__init__.py,sha256=SMw2W4Y5dqQ3Stubn5O4qcSGXAr4hsbI2Bz6qNz0vqs,839
2
+ dosync/audit_backup.py,sha256=44C45gWI5MrnMkI_ZtOnkU-LdL3ADjRradMq_IBjeKE,7581
3
+ dosync/auth.py,sha256=vZDSKLyOgKJruJCzbe9cLCV5RHL0KTmfwDFK9Cdu-Gw,7404
4
+ dosync/auth_fastapi.py,sha256=xrpNYzGyqJyhgb_4_eoJcafbI9EDm2HDoOJBM9y4hG4,2719
5
+ dosync/cert_signing.py,sha256=6MlGb8hvABBFidgVAwwCavrQpGoaIaOlKRo9ofZ_bT8,4625
6
+ dosync/certify.py,sha256=Plsl5G9Hz_XJOIeE3Gaf7zyoUBq0zUkbkzbv-LB77NQ,50427
7
+ dosync/cli.py,sha256=rYFTV7ZGGo50FYGszNsGXJJxYVmHz7ADct1QvnSJhiw,2840
8
+ dosync/composite_operations.py,sha256=z65zZZTC9KRDaPDTWC3-ztV93Rz-r0FmYXPBahDfnwk,14247
9
+ dosync/db.py,sha256=dKGdbjH45gOeArHqWFAn3a8zTtmna1vWC7KWIHkKuTY,36007
10
+ dosync/device_arbiter.py,sha256=YdTo06lq8AUjzx55fTivZZmrSW0xax2n8pMsICstIws,12553
11
+ dosync/discovery.py,sha256=CTB6ckJLusUWZbI20h-YD3EHUwlVMRyIHy-mFfzPmnw,6885
12
+ dosync/ed25519_pure.py,sha256=LoxGYUbbtDrkdIDK9sLQn3MC313_yC3fB8lYQwh4ARQ,6189
13
+ dosync/executor.py,sha256=URxZeshp0ftF2jhOD5gRszzZ0Ivw0L9r45IgE1eIx9s,4060
14
+ dosync/geo.py,sha256=k9b0exTcfFf766apWtbfRbJro8pRCcUc_Pokb_TnyTI,2827
15
+ dosync/hub.py,sha256=I8Mr_sKEkcTULzWT6zGEN2JB7TAUOOUroy4-3KDFOIw,142321
16
+ dosync/hub_monitor.py,sha256=xsxwsRws36x3UG4F4E25IbHubL8phwaD2p4WXIsEC5M,6345
17
+ dosync/manage.py,sha256=oEDwattBfU68RAL2tqdjZJ3IIDvEuw6ncNt25j0fChc,36058
18
+ dosync/mcp_server.py,sha256=nvO7Fx6_tlrHCtwoOEWRqxMxMSgKMiiqXUq2kXaxjA4,33153
19
+ dosync/metrics.py,sha256=g749tzyF5uMecscGxz9ERrtybmQqYE_rn9OhLf90p7U,10333
20
+ dosync/models.py,sha256=swxnC0nXAU2KNCWfyCHM7BbP3ybToJnY1R-g4vGvXhs,23628
21
+ dosync/operation_guards.py,sha256=noIKu9flKJ56L8mbFPc8MQ4DEb7IQ9OZNT2GeJI2xKQ,9926
22
+ dosync/operation_supervisor.py,sha256=NjHI0l_zsCx6z9W9Nw8uXWXUOu6-1vFbENjpKLzNqQc,10727
23
+ dosync/operations.py,sha256=Oqpqe8469HBAHZG1EFA5gnCA6SmgTUNYfmFJGxXUDak,15976
24
+ dosync/policies.py,sha256=YLPeVQUgN_2fpzXht7IiF8An09fH-IU2dMZfsaQ9feU,47356
25
+ dosync/policy_config.py,sha256=-PYnn26390ixP7O5IAiBEeX6tkezMBo7dPRzg5yTZi0,10565
26
+ dosync/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ dosync/reconciler.py,sha256=rEebPlNqjF_fbKjh8hSGAijCQhWXWSawzmvtA4iplAo,10003
28
+ dosync/route_composer.py,sha256=gqKtwTKPonKX1VUdGfO_uMHVuls5WqecbhwH1Z0-QOk,8934
29
+ dosync/security.py,sha256=kuQme0o0FfJUNpv5Ath9emV9V55bRq-K31fZXy61moQ,22825
30
+ dosync/server.py,sha256=lbSYxlj8sq28QDWj4aCt6RYZfsFhhnZ-h0lN0II40yI,83838
31
+ dosync/validation.py,sha256=CTgomrgP9VWoeitr365h3F1d8znDoUUSZfyIL31LnPU,3940
32
+ dosync/adapters/__init__.py,sha256=RXaAuYZuGxZtJMyWgqUQBWPa7X1zcl_Mbxc9EisBcAY,9809
33
+ dosync/adapters/ble.py,sha256=0vTbuldxDTBTRYvhVkLKiyMo1vgednormqnseAd7bm4,7754
34
+ dosync/adapters/homeassistant.py,sha256=_s0I_VY_fc28LQ6ugDJi6ngpcWoNCMFjOJwheM7uqgo,27843
35
+ dosync/adapters/matter.py,sha256=fli6jLfNE_-8RTLOnVQ-NX3rh3SRjQY7_vJu6Z7BEkQ,12432
36
+ dosync/adapters/mavlink.py,sha256=Z8r33JIlQe2md4fScMJboKPb0wULVrG-v5LFhBs0fPE,62496
37
+ dosync/adapters/mqtt.py,sha256=eQNtTFd2ypwV1tlQ-JLybfZ57y-SV74wpD_PXKe5GL0,17974
38
+ dosync/adapters/notifications.py,sha256=TXQRwg8XeV6Hw3jrqAGZrDOctZNRpsGV_6k_2kcfnE4,5896
39
+ dosync/adapters/shelly.py,sha256=yfIf8wKw-VWDU_P2UxaPFHpqI5mqb6VIZzp632pnsxk,13286
40
+ dosync/adapters/wiz.py,sha256=4s9-CxydsJ-YN47r49CuRpIAEYXQEtSVUBPlU0aObWk,13157
41
+ dosync-0.4.1.dist-info/licenses/LICENSE,sha256=CrztwUlJbww0ayaNDlD7F6Io8aNlvj_epa8K7PQ5HzA,11346
42
+ dosync-0.4.1.dist-info/METADATA,sha256=KW52OblR7lWdvrg7FX5x6g0mFEvFnh3XPwCa2nZT0bw,16666
43
+ dosync-0.4.1.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
44
+ dosync-0.4.1.dist-info/entry_points.txt,sha256=abiGvO_Xvos_ggjM2eVX7JCyK32guaOlV10E7ADFBR0,118
45
+ dosync-0.4.1.dist-info/top_level.txt,sha256=Tm-0WJ9qFe_yTHjuE2QGdtGAGuBeY-QbF-Hbn_Mu6XQ,7
46
+ dosync-0.4.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,4 @@
1
+ [console_scripts]
2
+ dosync-certify = dosync.certify:main
3
+ dosync-hub = dosync.cli:hub
4
+ dosync-manage = dosync.manage:main