rpp-protocol 0.1.5__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.
- rpp/__init__.py +60 -0
- rpp/adapters/__init__.py +14 -0
- rpp/adapters/filesystem.py +151 -0
- rpp/adapters/memory.py +95 -0
- rpp/address.py +249 -0
- rpp/cli.py +608 -0
- rpp/i18n.py +426 -0
- rpp/resolver.py +216 -0
- rpp/visual.py +389 -0
- rpp_protocol-0.1.5.dist-info/METADATA +390 -0
- rpp_protocol-0.1.5.dist-info/RECORD +14 -0
- rpp_protocol-0.1.5.dist-info/WHEEL +4 -0
- rpp_protocol-0.1.5.dist-info/entry_points.txt +2 -0
- rpp_protocol-0.1.5.dist-info/licenses/LICENSE +219 -0
rpp/visual.py
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RPP Visual Output Module
|
|
3
|
+
|
|
4
|
+
ASCII art and optional ANSI visualizations for RPP operations.
|
|
5
|
+
Designed for terminal-based feedback that works in any environment.
|
|
6
|
+
|
|
7
|
+
Two modes:
|
|
8
|
+
- Default (ASCII): Works everywhere (SSH, PuTTY, serial, emulators)
|
|
9
|
+
- Fancy (ANSI): Color and styling for modern terminals (opt-in)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from typing import Optional
|
|
13
|
+
|
|
14
|
+
# ANSI color codes (only used when fancy=True)
|
|
15
|
+
ANSI = {
|
|
16
|
+
"reset": "\033[0m",
|
|
17
|
+
"bold": "\033[1m",
|
|
18
|
+
"dim": "\033[2m",
|
|
19
|
+
"green": "\033[32m",
|
|
20
|
+
"red": "\033[31m",
|
|
21
|
+
"yellow": "\033[33m",
|
|
22
|
+
"blue": "\033[34m",
|
|
23
|
+
"cyan": "\033[36m",
|
|
24
|
+
"magenta": "\033[35m",
|
|
25
|
+
"bg_green": "\033[42m",
|
|
26
|
+
"bg_red": "\033[41m",
|
|
27
|
+
"bg_blue": "\033[44m",
|
|
28
|
+
"bg_yellow": "\033[43m",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _c(text: str, color: str, fancy: bool) -> str:
|
|
33
|
+
"""Apply color if fancy mode is enabled."""
|
|
34
|
+
if fancy and color in ANSI:
|
|
35
|
+
return f"{ANSI[color]}{text}{ANSI['reset']}"
|
|
36
|
+
return text
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _bold(text: str, fancy: bool) -> str:
|
|
40
|
+
"""Apply bold if fancy mode is enabled."""
|
|
41
|
+
if fancy:
|
|
42
|
+
return f"{ANSI['bold']}{text}{ANSI['reset']}"
|
|
43
|
+
return text
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def bit_layout_diagram(shell: int, theta: int, phi: int, harmonic: int,
|
|
47
|
+
raw: int, fancy: bool = False) -> str:
|
|
48
|
+
"""
|
|
49
|
+
Generate ASCII diagram showing the 28-bit address layout.
|
|
50
|
+
|
|
51
|
+
Uses ASCII-only characters for Windows compatibility.
|
|
52
|
+
|
|
53
|
+
Example output:
|
|
54
|
+
+-------------------------------------------------------------+
|
|
55
|
+
| 28-bit RPP Address: 0x0018A041 |
|
|
56
|
+
+------+----------+----------+----------+--------------------+
|
|
57
|
+
| Rsrv | Shell | Theta | Phi | Harmonic |
|
|
58
|
+
| 4bit | 2bit | 9bit | 9bit | 8bit |
|
|
59
|
+
+------+----------+----------+----------+--------------------+
|
|
60
|
+
| 0000 | 00 | 000001100| 100101000| 01000001 |
|
|
61
|
+
| (0) | (0) | (12) | (296) | (65) |
|
|
62
|
+
| | Hot | Gene | Abstract | |
|
|
63
|
+
+------+----------+----------+----------+--------------------+
|
|
64
|
+
"""
|
|
65
|
+
# Convert to binary strings
|
|
66
|
+
shell_bin = f"{shell:02b}"
|
|
67
|
+
theta_bin = f"{theta:09b}"
|
|
68
|
+
phi_bin = f"{phi:09b}"
|
|
69
|
+
harmonic_bin = f"{harmonic:08b}"
|
|
70
|
+
|
|
71
|
+
# Get semantic names
|
|
72
|
+
shell_names = {0: "Hot", 1: "Warm", 2: "Cold", 3: "Frozen"}
|
|
73
|
+
shell_name = shell_names[shell]
|
|
74
|
+
|
|
75
|
+
if theta < 64:
|
|
76
|
+
sector = "Gene"
|
|
77
|
+
elif theta < 128:
|
|
78
|
+
sector = "Memory"
|
|
79
|
+
elif theta < 192:
|
|
80
|
+
sector = "Witness"
|
|
81
|
+
elif theta < 256:
|
|
82
|
+
sector = "Dream"
|
|
83
|
+
elif theta < 320:
|
|
84
|
+
sector = "Bridge"
|
|
85
|
+
elif theta < 384:
|
|
86
|
+
sector = "Guardian"
|
|
87
|
+
elif theta < 448:
|
|
88
|
+
sector = "Emergence"
|
|
89
|
+
else:
|
|
90
|
+
sector = "Meta"
|
|
91
|
+
|
|
92
|
+
if phi < 128:
|
|
93
|
+
grounding = "Grounded"
|
|
94
|
+
elif phi < 256:
|
|
95
|
+
grounding = "Transit"
|
|
96
|
+
elif phi < 384:
|
|
97
|
+
grounding = "Abstract"
|
|
98
|
+
else:
|
|
99
|
+
grounding = "Ethereal"
|
|
100
|
+
|
|
101
|
+
# Color the header and key values
|
|
102
|
+
header = _c(f"28-bit RPP Address: 0x{raw:07X}", "cyan", fancy)
|
|
103
|
+
shell_val = _c(shell_name, "green" if shell == 0 else "yellow" if shell < 3 else "red", fancy)
|
|
104
|
+
sector_val = _c(sector, "blue", fancy)
|
|
105
|
+
ground_val = _c(grounding, "magenta", fancy)
|
|
106
|
+
|
|
107
|
+
lines = [
|
|
108
|
+
"+-------------------------------------------------------------+",
|
|
109
|
+
f"| {header:<58} |",
|
|
110
|
+
"+------+----------+----------+----------+--------------------+",
|
|
111
|
+
"| Rsrv | Shell | Theta | Phi | Harmonic |",
|
|
112
|
+
"| 4bit | 2bit | 9bit | 9bit | 8bit |",
|
|
113
|
+
"+------+----------+----------+----------+--------------------+",
|
|
114
|
+
f"| 0000 | {shell_bin} | {theta_bin}| {phi_bin}| {harmonic_bin} |",
|
|
115
|
+
f"| (0) | ({shell}) | ({theta:^3}) | ({phi:^3}) | ({harmonic:^3}) |",
|
|
116
|
+
f"| | {shell_val:^8} | {sector_val:^8} | {ground_val:^8} | |",
|
|
117
|
+
"+------+----------+----------+----------+--------------------+",
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
return "\n".join(lines)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def routing_diagram(shell: int, allowed: bool, route: Optional[str],
|
|
124
|
+
reason: str, fancy: bool = False) -> str:
|
|
125
|
+
"""
|
|
126
|
+
Generate ASCII diagram showing routing decision.
|
|
127
|
+
|
|
128
|
+
Uses ASCII-only characters for Windows compatibility.
|
|
129
|
+
|
|
130
|
+
Example output:
|
|
131
|
+
+-----------------------------------------+
|
|
132
|
+
| ROUTING DECISION |
|
|
133
|
+
+-----------------------------------------+
|
|
134
|
+
| +-----+ |
|
|
135
|
+
| | REQ | --> [RESOLVER] --> [ALLOWED] |
|
|
136
|
+
| +-----+ | |
|
|
137
|
+
| v |
|
|
138
|
+
| +---------+ |
|
|
139
|
+
| | HOT | |
|
|
140
|
+
| | STORAGE | |
|
|
141
|
+
| +---------+ |
|
|
142
|
+
+-----------------------------------------+
|
|
143
|
+
"""
|
|
144
|
+
shell_names = {0: "HOT", 1: "WARM", 2: "COLD", 3: "FROZEN"}
|
|
145
|
+
shell_name = shell_names.get(shell, "???")
|
|
146
|
+
|
|
147
|
+
if allowed:
|
|
148
|
+
status_ascii = _c("[ALLOWED]", "green", fancy)
|
|
149
|
+
else:
|
|
150
|
+
status_ascii = _c("[DENIED]", "red", fancy)
|
|
151
|
+
|
|
152
|
+
route_display = route if route else "null"
|
|
153
|
+
shell_box = _c(shell_name, "cyan", fancy)
|
|
154
|
+
|
|
155
|
+
lines = [
|
|
156
|
+
"+-----------------------------------------+",
|
|
157
|
+
"| ROUTING DECISION |",
|
|
158
|
+
"+-----------------------------------------+",
|
|
159
|
+
"| +-----+ |",
|
|
160
|
+
f"| | REQ | --> [RESOLVER] --> {status_ascii:<10}|",
|
|
161
|
+
"| +-----+ | |",
|
|
162
|
+
"| v |",
|
|
163
|
+
"| +---------+ |",
|
|
164
|
+
f"| | {shell_box:^7} | |",
|
|
165
|
+
"| | STORAGE | |",
|
|
166
|
+
"| +---------+ |",
|
|
167
|
+
"+-----------------------------------------+",
|
|
168
|
+
f"| Route: {route_display:<30}|",
|
|
169
|
+
f"| Reason: {reason:<30}|",
|
|
170
|
+
"+-----------------------------------------+",
|
|
171
|
+
]
|
|
172
|
+
|
|
173
|
+
return "\n".join(lines)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def consent_meter(phi: int, fancy: bool = False) -> str:
|
|
177
|
+
"""
|
|
178
|
+
Generate ASCII consent/grounding meter based on phi value.
|
|
179
|
+
|
|
180
|
+
Uses ASCII-only characters for Windows compatibility.
|
|
181
|
+
|
|
182
|
+
Example output:
|
|
183
|
+
Consent Level: [########............] 40/511 (Grounded)
|
|
184
|
+
"""
|
|
185
|
+
# Normalize to 20-char bar
|
|
186
|
+
filled = int((phi / 511) * 20)
|
|
187
|
+
empty = 20 - filled
|
|
188
|
+
|
|
189
|
+
if phi < 128:
|
|
190
|
+
level = "Grounded"
|
|
191
|
+
color = "green"
|
|
192
|
+
elif phi < 256:
|
|
193
|
+
level = "Transitional"
|
|
194
|
+
color = "yellow"
|
|
195
|
+
elif phi < 384:
|
|
196
|
+
level = "Abstract"
|
|
197
|
+
color = "yellow"
|
|
198
|
+
else:
|
|
199
|
+
level = "Ethereal"
|
|
200
|
+
color = "red"
|
|
201
|
+
|
|
202
|
+
bar_filled = _c("#" * filled, color, fancy)
|
|
203
|
+
bar_empty = "." * empty
|
|
204
|
+
level_text = _c(level, color, fancy)
|
|
205
|
+
|
|
206
|
+
return f"Consent Level: [{bar_filled}{bar_empty}] {phi}/511 ({level_text})"
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def shell_tier_visual(shell: int, fancy: bool = False) -> str:
|
|
210
|
+
"""
|
|
211
|
+
Generate ASCII representation of shell tier.
|
|
212
|
+
|
|
213
|
+
Uses ASCII-only characters for Windows compatibility.
|
|
214
|
+
|
|
215
|
+
Example output:
|
|
216
|
+
o Frozen (3)
|
|
217
|
+
o Cold (2)
|
|
218
|
+
o Warm (1)
|
|
219
|
+
> * Hot (0) < ACTIVE
|
|
220
|
+
"""
|
|
221
|
+
lines = []
|
|
222
|
+
shell_info = [
|
|
223
|
+
(0, "Hot", "In-memory, immediate access"),
|
|
224
|
+
(1, "Warm", "Fast storage, quick retrieval"),
|
|
225
|
+
(2, "Cold", "Archive storage, slower access"),
|
|
226
|
+
(3, "Frozen", "Deep archive, consent required"),
|
|
227
|
+
]
|
|
228
|
+
|
|
229
|
+
for s, name, desc in reversed(shell_info):
|
|
230
|
+
if s == shell:
|
|
231
|
+
marker = _c("*", "green", fancy)
|
|
232
|
+
arrow = _c(">", "cyan", fancy)
|
|
233
|
+
suffix = _c("< ACTIVE", "cyan", fancy)
|
|
234
|
+
lines.append(f" {arrow} {marker} {name} ({s}) {suffix}")
|
|
235
|
+
else:
|
|
236
|
+
marker = "o"
|
|
237
|
+
lines.append(f" {marker} {name} ({s})")
|
|
238
|
+
|
|
239
|
+
return "\n".join(lines)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def theta_wheel(theta: int, fancy: bool = False) -> str:
|
|
243
|
+
"""
|
|
244
|
+
Generate ASCII representation of theta sectors as a wheel.
|
|
245
|
+
|
|
246
|
+
Uses ASCII-only characters for Windows compatibility.
|
|
247
|
+
Shows the 8 semantic sectors with the active one highlighted.
|
|
248
|
+
"""
|
|
249
|
+
sectors = [
|
|
250
|
+
(0, 63, "Gene"),
|
|
251
|
+
(64, 127, "Memory"),
|
|
252
|
+
(128, 191, "Witness"),
|
|
253
|
+
(192, 255, "Dream"),
|
|
254
|
+
(256, 319, "Bridge"),
|
|
255
|
+
(320, 383, "Guardian"),
|
|
256
|
+
(384, 447, "Emergence"),
|
|
257
|
+
(448, 511, "Meta"),
|
|
258
|
+
]
|
|
259
|
+
|
|
260
|
+
# Find active sector
|
|
261
|
+
active_idx = 0
|
|
262
|
+
for i, (start, end, name) in enumerate(sectors):
|
|
263
|
+
if start <= theta <= end:
|
|
264
|
+
active_idx = i
|
|
265
|
+
break
|
|
266
|
+
|
|
267
|
+
# Simple linear representation
|
|
268
|
+
parts = []
|
|
269
|
+
for i, (start, end, name) in enumerate(sectors):
|
|
270
|
+
if i == active_idx:
|
|
271
|
+
parts.append(_c(f"[{name}]", "cyan", fancy))
|
|
272
|
+
else:
|
|
273
|
+
parts.append(f" {name} ")
|
|
274
|
+
|
|
275
|
+
wheel = " -> ".join(parts[:4]) + "\n" + " -> ".join(parts[4:])
|
|
276
|
+
header = f"Theta Sector: {theta}/511"
|
|
277
|
+
|
|
278
|
+
return f"{header}\n{wheel}"
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def operation_status(operation: str, success: bool, fancy: bool = False) -> str:
|
|
282
|
+
"""
|
|
283
|
+
Generate operation status indicator.
|
|
284
|
+
|
|
285
|
+
Example: [ENCODE] OK / [ENCODE] FAIL
|
|
286
|
+
"""
|
|
287
|
+
op_text = _c(f"[{operation.upper()}]", "bold", fancy)
|
|
288
|
+
|
|
289
|
+
if success:
|
|
290
|
+
# Use ASCII-safe symbols for Windows compatibility
|
|
291
|
+
check = "[OK]" if not fancy else "OK"
|
|
292
|
+
status = _c(check, "green", fancy)
|
|
293
|
+
else:
|
|
294
|
+
cross = "[FAIL]" if not fancy else "FAIL"
|
|
295
|
+
status = _c(cross, "red", fancy)
|
|
296
|
+
|
|
297
|
+
return f"{op_text} {status}"
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def spinner_frame(frame: int) -> str:
|
|
301
|
+
"""
|
|
302
|
+
Get a spinner animation frame.
|
|
303
|
+
|
|
304
|
+
Uses ASCII-only characters for Windows compatibility.
|
|
305
|
+
For use in fancy mode with animation.
|
|
306
|
+
"""
|
|
307
|
+
frames = ["|", "/", "-", "\\"]
|
|
308
|
+
return frames[frame % len(frames)]
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def demo_banner(fancy: bool = False) -> str:
|
|
312
|
+
"""
|
|
313
|
+
Generate RPP demo banner.
|
|
314
|
+
|
|
315
|
+
Uses ASCII-only characters for Windows compatibility.
|
|
316
|
+
"""
|
|
317
|
+
if fancy:
|
|
318
|
+
banner = f"""{ANSI['cyan']}{ANSI['bold']}
|
|
319
|
+
+===========================================================+
|
|
320
|
+
| |
|
|
321
|
+
| RRRR PPPP PPPP |
|
|
322
|
+
| R R P P P P Rotational Packet Protocol |
|
|
323
|
+
| RRRR PPPP PPPP 28-bit Semantic Addressing |
|
|
324
|
+
| R R P P |
|
|
325
|
+
| R R P P Consent-Aware Routing |
|
|
326
|
+
| |
|
|
327
|
+
+===========================================================+
|
|
328
|
+
{ANSI['reset']}"""
|
|
329
|
+
else:
|
|
330
|
+
banner = """
|
|
331
|
+
+===========================================================+
|
|
332
|
+
| |
|
|
333
|
+
| RRRR PPPP PPPP |
|
|
334
|
+
| R R P P P P Rotational Packet Protocol |
|
|
335
|
+
| RRRR PPPP PPPP 28-bit Semantic Addressing |
|
|
336
|
+
| R R P P |
|
|
337
|
+
| R R P P Consent-Aware Routing |
|
|
338
|
+
| |
|
|
339
|
+
+===========================================================+
|
|
340
|
+
"""
|
|
341
|
+
return banner
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def address_mini(addr_hex: str, shell_name: str, sector: str,
|
|
345
|
+
grounding: str, fancy: bool = False) -> str:
|
|
346
|
+
"""
|
|
347
|
+
Generate compact single-line address summary.
|
|
348
|
+
|
|
349
|
+
Uses ASCII-only characters for Windows compatibility.
|
|
350
|
+
|
|
351
|
+
Example: 0x0018A041 | Hot | Gene | Abstract
|
|
352
|
+
"""
|
|
353
|
+
parts = [
|
|
354
|
+
_c(addr_hex, "cyan", fancy),
|
|
355
|
+
_c(shell_name, "green", fancy),
|
|
356
|
+
_c(sector, "blue", fancy),
|
|
357
|
+
_c(grounding, "magenta", fancy),
|
|
358
|
+
]
|
|
359
|
+
return " | ".join(parts)
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def success_box(message: str, fancy: bool = False) -> str:
|
|
363
|
+
"""Generate a success message box. Uses ASCII-only characters."""
|
|
364
|
+
width = len(message) + 4
|
|
365
|
+
border = "=" * width
|
|
366
|
+
|
|
367
|
+
if fancy:
|
|
368
|
+
return f"""{ANSI['green']}+{border}+
|
|
369
|
+
| {message} |
|
|
370
|
+
+{border}+{ANSI['reset']}"""
|
|
371
|
+
else:
|
|
372
|
+
return f"""+{border}+
|
|
373
|
+
| {message} |
|
|
374
|
+
+{border}+"""
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def error_box(message: str, fancy: bool = False) -> str:
|
|
378
|
+
"""Generate an error message box. Uses ASCII-only characters."""
|
|
379
|
+
width = len(message) + 4
|
|
380
|
+
border = "=" * width
|
|
381
|
+
|
|
382
|
+
if fancy:
|
|
383
|
+
return f"""{ANSI['red']}+{border}+
|
|
384
|
+
| {message} |
|
|
385
|
+
+{border}+{ANSI['reset']}"""
|
|
386
|
+
else:
|
|
387
|
+
return f"""+{border}+
|
|
388
|
+
| {message} |
|
|
389
|
+
+{border}+"""
|