open-packet 0.1.0__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 (191) hide show
  1. open_packet-0.1.0/.github/workflows/docs.yml +108 -0
  2. open_packet-0.1.0/.github/workflows/publish.yaml +70 -0
  3. open_packet-0.1.0/.github/workflows/test-and-build.yml +32 -0
  4. open_packet-0.1.0/.gitignore +5 -0
  5. open_packet-0.1.0/.gitmodules +3 -0
  6. open_packet-0.1.0/CLAUDE.md +88 -0
  7. open_packet-0.1.0/LICENSE +21 -0
  8. open_packet-0.1.0/PKG-INFO +124 -0
  9. open_packet-0.1.0/README.md +111 -0
  10. open_packet-0.1.0/docs/AX25.2.2-Jul 98-2.pdf +0 -0
  11. open_packet-0.1.0/docs/hugo/.gitignore +3 -0
  12. open_packet-0.1.0/docs/hugo/content/_index.md +34 -0
  13. open_packet-0.1.0/docs/hugo/content/docs/_index.md +14 -0
  14. open_packet-0.1.0/docs/hugo/content/docs/development/_index.md +11 -0
  15. open_packet-0.1.0/docs/hugo/content/docs/development/architecture.md +124 -0
  16. open_packet-0.1.0/docs/hugo/content/docs/development/contributing.md +73 -0
  17. open_packet-0.1.0/docs/hugo/content/docs/print/_index.md +7 -0
  18. open_packet-0.1.0/docs/hugo/content/docs/reference/_index.md +11 -0
  19. open_packet-0.1.0/docs/hugo/content/docs/reference/configuration.md +47 -0
  20. open_packet-0.1.0/docs/hugo/content/docs/reference/keyboard-shortcuts.md +62 -0
  21. open_packet-0.1.0/docs/hugo/content/docs/user-guide/_index.md +18 -0
  22. open_packet-0.1.0/docs/hugo/content/docs/user-guide/bulletins.md +48 -0
  23. open_packet-0.1.0/docs/hugo/content/docs/user-guide/files.md +35 -0
  24. open_packet-0.1.0/docs/hugo/content/docs/user-guide/forms.md +41 -0
  25. open_packet-0.1.0/docs/hugo/content/docs/user-guide/getting-started.md +65 -0
  26. open_packet-0.1.0/docs/hugo/content/docs/user-guide/messages.md +78 -0
  27. open_packet-0.1.0/docs/hugo/content/docs/user-guide/settings.md +83 -0
  28. open_packet-0.1.0/docs/hugo/content/docs/user-guide/terminal.md +32 -0
  29. open_packet-0.1.0/docs/hugo/go.mod +10 -0
  30. open_packet-0.1.0/docs/hugo/go.sum +4 -0
  31. open_packet-0.1.0/docs/hugo/hugo.toml +83 -0
  32. open_packet-0.1.0/docs/hugo/layouts/docs/print/list.html +157 -0
  33. open_packet-0.1.0/docs/hugo/static/images/.gitkeep +0 -0
  34. open_packet-0.1.0/docs/superpowers/plans/2026-03-22-open-packet-poc.md +3632 -0
  35. open_packet-0.1.0/docs/superpowers/plans/2026-03-22-operator-node-setup.md +1145 -0
  36. open_packet-0.1.0/docs/superpowers/plans/2026-03-23-ax25-layer.md +1712 -0
  37. open_packet-0.1.0/docs/superpowers/plans/2026-03-23-outbox-folder-counts.md +916 -0
  38. open_packet-0.1.0/docs/superpowers/plans/2026-03-23-readme.md +219 -0
  39. open_packet-0.1.0/docs/superpowers/plans/2026-03-24-bulletins.md +1525 -0
  40. open_packet-0.1.0/docs/superpowers/plans/2026-03-24-status-bar-identity.md +507 -0
  41. open_packet-0.1.0/docs/superpowers/plans/2026-03-24-telnet-interface-library.md +2287 -0
  42. open_packet-0.1.0/docs/superpowers/plans/2026-03-25-multi-hop-connections.md +1951 -0
  43. open_packet-0.1.0/docs/superpowers/plans/2026-04-04-interactive-terminal-sessions.md +1652 -0
  44. open_packet-0.1.0/docs/superpowers/plans/2026-04-06-bulletin-retrieval.md +830 -0
  45. open_packet-0.1.0/docs/superpowers/plans/2026-04-06-folder-pane-message-list-improvements.md +715 -0
  46. open_packet-0.1.0/docs/superpowers/plans/2026-04-07-message-forms.md +1163 -0
  47. open_packet-0.1.0/docs/superpowers/plans/2026-04-07-settings-overhaul.md +2081 -0
  48. open_packet-0.1.0/docs/superpowers/specs/2026-03-22-operator-node-setup-design.md +197 -0
  49. open_packet-0.1.0/docs/superpowers/specs/2026-03-22-packet-client-design.md +297 -0
  50. open_packet-0.1.0/docs/superpowers/specs/2026-03-23-outbox-folder-counts-design.md +301 -0
  51. open_packet-0.1.0/docs/superpowers/specs/2026-03-23-readme-design.md +84 -0
  52. open_packet-0.1.0/docs/superpowers/specs/2026-03-24-bulletins-design.md +390 -0
  53. open_packet-0.1.0/docs/superpowers/specs/2026-03-24-defcon34-talk-abstract-design.md +69 -0
  54. open_packet-0.1.0/docs/superpowers/specs/2026-03-24-status-bar-identity-design.md +156 -0
  55. open_packet-0.1.0/docs/superpowers/specs/2026-03-24-telnet-interface-library-design.md +237 -0
  56. open_packet-0.1.0/docs/superpowers/specs/2026-03-25-multi-hop-connections-design.md +228 -0
  57. open_packet-0.1.0/docs/superpowers/specs/2026-04-04-interactive-terminal-sessions-design.md +150 -0
  58. open_packet-0.1.0/docs/superpowers/specs/2026-04-06-bulletin-retrieval-design.md +87 -0
  59. open_packet-0.1.0/docs/superpowers/specs/2026-04-06-folder-pane-message-list-improvements-design.md +100 -0
  60. open_packet-0.1.0/docs/superpowers/specs/2026-04-07-message-forms-design.md +184 -0
  61. open_packet-0.1.0/docs/superpowers/specs/2026-04-07-settings-overhaul-design.md +174 -0
  62. open_packet-0.1.0/docs/superpowers/specs/2026-04-08-file-retrieval-design.md +184 -0
  63. open_packet-0.1.0/docs/superpowers/specs/2026-04-09-console-log-level-design.md +179 -0
  64. open_packet-0.1.0/forms/General Forms/field_situation_report.yaml +248 -0
  65. open_packet-0.1.0/forms/General Forms/quick_message.yaml +40 -0
  66. open_packet-0.1.0/forms/General Forms/radio_net_log.yaml +331 -0
  67. open_packet-0.1.0/forms/ICS USA Forms/ics202_incident_objectives.yaml +112 -0
  68. open_packet-0.1.0/forms/ICS USA Forms/ics205_radio_plan.yaml +331 -0
  69. open_packet-0.1.0/forms/ICS USA Forms/ics213_general_message.yaml +75 -0
  70. open_packet-0.1.0/forms/ICS USA Forms/ics213rr_resource_request.yaml +275 -0
  71. open_packet-0.1.0/forms/ICS USA Forms/ics214_activity_log.yaml +261 -0
  72. open_packet-0.1.0/forms/NTS Forms/nts_radiogram.yaml +101 -0
  73. open_packet-0.1.0/images/image.png +0 -0
  74. open_packet-0.1.0/open_packet/__init__.py +0 -0
  75. open_packet-0.1.0/open_packet/ax25/__init__.py +0 -0
  76. open_packet-0.1.0/open_packet/ax25/address.py +33 -0
  77. open_packet-0.1.0/open_packet/ax25/connection.py +467 -0
  78. open_packet-0.1.0/open_packet/ax25/frame.py +206 -0
  79. open_packet-0.1.0/open_packet/ax25/timer.py +22 -0
  80. open_packet-0.1.0/open_packet/engine/__init__.py +0 -0
  81. open_packet-0.1.0/open_packet/engine/commands.py +63 -0
  82. open_packet-0.1.0/open_packet/engine/engine.py +542 -0
  83. open_packet-0.1.0/open_packet/engine/events.py +89 -0
  84. open_packet-0.1.0/open_packet/forms/__init__.py +0 -0
  85. open_packet-0.1.0/open_packet/forms/loader.py +107 -0
  86. open_packet-0.1.0/open_packet/forms/renderer.py +18 -0
  87. open_packet-0.1.0/open_packet/forms/updater.py +164 -0
  88. open_packet-0.1.0/open_packet/forms/validator.py +43 -0
  89. open_packet-0.1.0/open_packet/link/__init__.py +0 -0
  90. open_packet-0.1.0/open_packet/link/base.py +24 -0
  91. open_packet-0.1.0/open_packet/link/kiss.py +85 -0
  92. open_packet-0.1.0/open_packet/link/telnet.py +126 -0
  93. open_packet-0.1.0/open_packet/node/__init__.py +0 -0
  94. open_packet-0.1.0/open_packet/node/base.py +73 -0
  95. open_packet-0.1.0/open_packet/node/bpq.py +274 -0
  96. open_packet-0.1.0/open_packet/store/__init__.py +0 -0
  97. open_packet-0.1.0/open_packet/store/database.py +603 -0
  98. open_packet-0.1.0/open_packet/store/exporter.py +45 -0
  99. open_packet-0.1.0/open_packet/store/models.py +106 -0
  100. open_packet-0.1.0/open_packet/store/settings.py +73 -0
  101. open_packet-0.1.0/open_packet/store/store.py +458 -0
  102. open_packet-0.1.0/open_packet/terminal/__init__.py +0 -0
  103. open_packet-0.1.0/open_packet/terminal/session.py +91 -0
  104. open_packet-0.1.0/open_packet/transport/__init__.py +0 -0
  105. open_packet-0.1.0/open_packet/transport/base.py +20 -0
  106. open_packet-0.1.0/open_packet/transport/serial.py +45 -0
  107. open_packet-0.1.0/open_packet/transport/tcp.py +50 -0
  108. open_packet-0.1.0/open_packet/ui/__init__.py +0 -0
  109. open_packet-0.1.0/open_packet/ui/base.py +13 -0
  110. open_packet-0.1.0/open_packet/ui/tui/__init__.py +0 -0
  111. open_packet-0.1.0/open_packet/ui/tui/app.py +1040 -0
  112. open_packet-0.1.0/open_packet/ui/tui/screens/__init__.py +3 -0
  113. open_packet-0.1.0/open_packet/ui/tui/screens/compose.py +92 -0
  114. open_packet-0.1.0/open_packet/ui/tui/screens/compose_bulletin.py +54 -0
  115. open_packet-0.1.0/open_packet/ui/tui/screens/connect_terminal.py +169 -0
  116. open_packet-0.1.0/open_packet/ui/tui/screens/delete_confirm.py +54 -0
  117. open_packet-0.1.0/open_packet/ui/tui/screens/form_fill.py +231 -0
  118. open_packet-0.1.0/open_packet/ui/tui/screens/form_picker.py +68 -0
  119. open_packet-0.1.0/open_packet/ui/tui/screens/general_settings.py +149 -0
  120. open_packet-0.1.0/open_packet/ui/tui/screens/interface_picker.py +102 -0
  121. open_packet-0.1.0/open_packet/ui/tui/screens/main.py +118 -0
  122. open_packet-0.1.0/open_packet/ui/tui/screens/manage_interfaces.py +147 -0
  123. open_packet-0.1.0/open_packet/ui/tui/screens/manage_nodes.py +264 -0
  124. open_packet-0.1.0/open_packet/ui/tui/screens/manage_operators.py +162 -0
  125. open_packet-0.1.0/open_packet/ui/tui/screens/new_item.py +71 -0
  126. open_packet-0.1.0/open_packet/ui/tui/screens/node_multi_picker.py +83 -0
  127. open_packet-0.1.0/open_packet/ui/tui/screens/node_picker.py +105 -0
  128. open_packet-0.1.0/open_packet/ui/tui/screens/operator_picker.py +102 -0
  129. open_packet-0.1.0/open_packet/ui/tui/screens/search.py +150 -0
  130. open_packet-0.1.0/open_packet/ui/tui/screens/settings.py +51 -0
  131. open_packet-0.1.0/open_packet/ui/tui/screens/setup_interface.py +194 -0
  132. open_packet-0.1.0/open_packet/ui/tui/screens/setup_node.py +357 -0
  133. open_packet-0.1.0/open_packet/ui/tui/screens/setup_node_group.py +138 -0
  134. open_packet-0.1.0/open_packet/ui/tui/screens/setup_operator.py +111 -0
  135. open_packet-0.1.0/open_packet/ui/tui/screens/shorter_path_confirm.py +44 -0
  136. open_packet-0.1.0/open_packet/ui/tui/widgets/__init__.py +0 -0
  137. open_packet-0.1.0/open_packet/ui/tui/widgets/console_panel.py +53 -0
  138. open_packet-0.1.0/open_packet/ui/tui/widgets/file_list.py +61 -0
  139. open_packet-0.1.0/open_packet/ui/tui/widgets/folder_tree.py +180 -0
  140. open_packet-0.1.0/open_packet/ui/tui/widgets/message_body.py +43 -0
  141. open_packet-0.1.0/open_packet/ui/tui/widgets/message_list.py +70 -0
  142. open_packet-0.1.0/open_packet/ui/tui/widgets/status_bar.py +138 -0
  143. open_packet-0.1.0/open_packet/ui/tui/widgets/terminal_view.py +54 -0
  144. open_packet-0.1.0/pyproject.toml +32 -0
  145. open_packet-0.1.0/test.yaml +7 -0
  146. open_packet-0.1.0/tests/__init__.py +0 -0
  147. open_packet-0.1.0/tests/conftest.py +2 -0
  148. open_packet-0.1.0/tests/test_ax25/__init__.py +0 -0
  149. open_packet-0.1.0/tests/test_ax25/test_address.py +67 -0
  150. open_packet-0.1.0/tests/test_ax25/test_connection.py +298 -0
  151. open_packet-0.1.0/tests/test_ax25/test_frame.py +165 -0
  152. open_packet-0.1.0/tests/test_ax25/test_timer.py +39 -0
  153. open_packet-0.1.0/tests/test_engine/__init__.py +0 -0
  154. open_packet-0.1.0/tests/test_engine/test_engine.py +608 -0
  155. open_packet-0.1.0/tests/test_engine/test_integration.py +116 -0
  156. open_packet-0.1.0/tests/test_engine/test_node_targeting.py +210 -0
  157. open_packet-0.1.0/tests/test_forms/__init__.py +0 -0
  158. open_packet-0.1.0/tests/test_forms/test_loader.py +165 -0
  159. open_packet-0.1.0/tests/test_forms/test_nts_radiogram.py +201 -0
  160. open_packet-0.1.0/tests/test_forms/test_renderer.py +49 -0
  161. open_packet-0.1.0/tests/test_forms/test_updater.py +323 -0
  162. open_packet-0.1.0/tests/test_forms/test_validator.py +140 -0
  163. open_packet-0.1.0/tests/test_link/__init__.py +0 -0
  164. open_packet-0.1.0/tests/test_link/test_kiss.py +89 -0
  165. open_packet-0.1.0/tests/test_link/test_telnet.py +151 -0
  166. open_packet-0.1.0/tests/test_node/__init__.py +0 -0
  167. open_packet-0.1.0/tests/test_node/test_bpq.py +405 -0
  168. open_packet-0.1.0/tests/test_store/__init__.py +0 -0
  169. open_packet-0.1.0/tests/test_store/test_database_helpers.py +239 -0
  170. open_packet-0.1.0/tests/test_store/test_node_groups.py +111 -0
  171. open_packet-0.1.0/tests/test_store/test_node_tracking.py +186 -0
  172. open_packet-0.1.0/tests/test_store/test_settings.py +110 -0
  173. open_packet-0.1.0/tests/test_store/test_soft_delete.py +110 -0
  174. open_packet-0.1.0/tests/test_store/test_store.py +1265 -0
  175. open_packet-0.1.0/tests/test_terminal/__init__.py +0 -0
  176. open_packet-0.1.0/tests/test_terminal/test_session.py +176 -0
  177. open_packet-0.1.0/tests/test_transport/__init__.py +0 -0
  178. open_packet-0.1.0/tests/test_transport/test_tcp.py +64 -0
  179. open_packet-0.1.0/tests/test_ui/__init__.py +0 -0
  180. open_packet-0.1.0/tests/test_ui/conftest.py +4 -0
  181. open_packet-0.1.0/tests/test_ui/test_connect_terminal.py +151 -0
  182. open_packet-0.1.0/tests/test_ui/test_manage_screens.py +214 -0
  183. open_packet-0.1.0/tests/test_ui/test_node_multi_picker.py +81 -0
  184. open_packet-0.1.0/tests/test_ui/test_notifications.py +119 -0
  185. open_packet-0.1.0/tests/test_ui/test_picker_screens.py +114 -0
  186. open_packet-0.1.0/tests/test_ui/test_scheduled_sr.py +90 -0
  187. open_packet-0.1.0/tests/test_ui/test_setup_screens.py +494 -0
  188. open_packet-0.1.0/tests/test_ui/test_status_bar.py +120 -0
  189. open_packet-0.1.0/tests/test_ui/test_terminal_view.py +83 -0
  190. open_packet-0.1.0/tests/test_ui/test_tui.py +938 -0
  191. open_packet-0.1.0/uv.lock +1065 -0
@@ -0,0 +1,108 @@
1
+ name: Build and Publish Documentation
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch: # Allow manual trigger for testing
7
+
8
+ jobs:
9
+ build-docs:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+ steps:
14
+ - name: Checkout repository
15
+ uses: actions/checkout@v4
16
+ with:
17
+ submodules: recursive
18
+ fetch-depth: 0 # Fetch full history for git info in Hugo
19
+
20
+ - name: Set up Go
21
+ uses: actions/setup-go@v5
22
+ with:
23
+ go-version: "stable"
24
+
25
+ - name: Set up Hugo
26
+ uses: peaceiris/actions-hugo@v3
27
+ with:
28
+ hugo-version: "latest"
29
+ extended: true
30
+
31
+ - name: Build Hugo site
32
+ run: |
33
+ cd docs/hugo
34
+ hugo --minify --baseURL "https://loredous.github.io/open-packet/"
35
+
36
+ - name: Generate PDF
37
+ run: |
38
+ sudo apt-get install -y chromium-browser
39
+ chromium-browser --headless --disable-gpu \
40
+ --print-to-pdf=docs/hugo/public/open-packet-docs.pdf \
41
+ --no-margins \
42
+ "file://$(pwd)/docs/hugo/public/docs/print/index.html" 2>/dev/null || \
43
+ chromium --headless --disable-gpu \
44
+ --print-to-pdf=docs/hugo/public/open-packet-docs.pdf \
45
+ --no-margins \
46
+ "file://$(pwd)/docs/hugo/public/docs/print/index.html" 2>/dev/null || true
47
+
48
+ - name: Upload Pages artifact
49
+ uses: actions/upload-pages-artifact@v3
50
+ with:
51
+ path: docs/hugo/public
52
+
53
+ attach-pdf:
54
+ needs: build-docs
55
+ runs-on: ubuntu-latest
56
+ if: github.event_name == 'release'
57
+ permissions:
58
+ contents: write
59
+ steps:
60
+ - name: Checkout repository
61
+ uses: actions/checkout@v4
62
+
63
+ - name: Set up Go
64
+ uses: actions/setup-go@v5
65
+ with:
66
+ go-version: "stable"
67
+
68
+ - name: Set up Hugo
69
+ uses: peaceiris/actions-hugo@v3
70
+ with:
71
+ hugo-version: "latest"
72
+ extended: true
73
+
74
+ - name: Build Hugo site for PDF
75
+ run: |
76
+ cd docs/hugo
77
+ hugo --minify --baseURL "file://$(pwd)/public/"
78
+
79
+ - name: Generate PDF
80
+ run: |
81
+ sudo apt-get install -y chromium-browser
82
+ chromium-browser --headless --disable-gpu \
83
+ --print-to-pdf=open-packet-docs.pdf \
84
+ --no-margins \
85
+ "file://$(pwd)/docs/hugo/public/docs/print/index.html" 2>/dev/null || \
86
+ chromium --headless --disable-gpu \
87
+ --print-to-pdf=open-packet-docs.pdf \
88
+ --no-margins \
89
+ "file://$(pwd)/docs/hugo/public/docs/print/index.html" 2>/dev/null
90
+
91
+ - name: Attach PDF to release
92
+ uses: softprops/action-gh-release@v2
93
+ with:
94
+ files: open-packet-docs.pdf
95
+
96
+ deploy-pages:
97
+ needs: build-docs
98
+ runs-on: ubuntu-latest
99
+ permissions:
100
+ pages: write
101
+ id-token: write
102
+ environment:
103
+ name: github-pages
104
+ url: ${{ steps.deployment.outputs.page_url }}
105
+ steps:
106
+ - name: Deploy to GitHub Pages
107
+ id: deployment
108
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,70 @@
1
+ # This workflow will upload a Python Package to PyPI when a release is created
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3
+
4
+ # This workflow uses actions that are not certified by GitHub.
5
+ # They are provided by a third-party and are governed by
6
+ # separate terms of service, privacy policy, and support
7
+ # documentation.
8
+
9
+ name: Upload Python Package
10
+
11
+ on:
12
+ release:
13
+ types: [published]
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ release-build:
20
+ runs-on: ubuntu-latest
21
+
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+
25
+ - uses: actions/setup-python@v5
26
+ with:
27
+ python-version: "3.x"
28
+
29
+ - name: Install uv
30
+ run: pip install uv
31
+
32
+ - name: Build release distributions
33
+ run: uv build
34
+
35
+ - name: Upload distributions
36
+ uses: actions/upload-artifact@v4
37
+ with:
38
+ name: release-dists
39
+ path: dist/
40
+
41
+ pypi-publish:
42
+ runs-on: ubuntu-latest
43
+ needs:
44
+ - release-build
45
+ permissions:
46
+ # IMPORTANT: this permission is mandatory for trusted publishing
47
+ id-token: write
48
+
49
+ # Dedicated environments with protections for publishing are strongly recommended.
50
+ # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules
51
+ environment:
52
+ name: pypi
53
+ # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status:
54
+ # url: https://pypi.org/p/YOURPROJECT
55
+ #
56
+ # ALTERNATIVE: if your GitHub Release name is the PyPI project version string
57
+ # ALTERNATIVE: exactly, uncomment the following line instead:
58
+ # url: https://pypi.org/project/YOURPROJECT/${{ github.event.release.name }}
59
+
60
+ steps:
61
+ - name: Retrieve release distributions
62
+ uses: actions/download-artifact@v4
63
+ with:
64
+ name: release-dists
65
+ path: dist/
66
+
67
+ - name: Publish release distributions to PyPI
68
+ uses: pypa/gh-action-pypi-publish@release/v1
69
+ with:
70
+ packages-dir: dist/
@@ -0,0 +1,32 @@
1
+ # This workflow will install Python dependencies, run tests and lint with a single version of Python
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3
+
4
+ name: Python application
5
+
6
+ on:
7
+ push:
8
+ branches: [ "main" ]
9
+ pull_request:
10
+ branches: [ "main" ]
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ build:
17
+
18
+ runs-on: ubuntu-latest
19
+
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - name: Set up Python 3.11
23
+ uses: actions/setup-python@v3
24
+ with:
25
+ python-version: "3.11"
26
+ - name: Install UV
27
+ run: pip install uv
28
+ - name: Run Tests
29
+ run: uv run pytest
30
+ - name: Build
31
+ run: uv build
32
+
@@ -0,0 +1,5 @@
1
+ .superpowers/
2
+ .worktrees/
3
+ __pycache__/
4
+ *.pyc
5
+ .python-version
@@ -0,0 +1,3 @@
1
+ [submodule "docs/hugo/themes/lotusdocs"]
2
+ path = docs/hugo/themes/lotusdocs
3
+ url = https://github.com/colinwilson/lotusdocs
@@ -0,0 +1,88 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ uv sync # install dependencies
9
+ uv run pytest # run full test suite
10
+ uv run pytest tests/test_store # run tests in one directory
11
+ uv run pytest tests/test_store/test_store.py::test_list_outbox_excludes_sent_and_deleted # run single test
12
+ uv run open-packet # run the app (requires config.yaml)
13
+ uv run open-packet test.yaml # run with a specific config file
14
+ uv run textual run --dev open_packet/ui/tui/app.py # run with Textual live-reload + DOM inspector
15
+ ```
16
+
17
+ `asyncio_mode = "auto"` is set in `pyproject.toml`, so async tests do not need `@pytest.mark.asyncio`.
18
+
19
+ ## Architecture
20
+
21
+ The codebase is layered: **Transport → Link → AX.25 → Node → Engine → Store / TUI**. Each layer communicates only with its immediate neighbors via well-defined interfaces.
22
+
23
+ ```
24
+ Transport (tcp.py / serial.py) — raw byte I/O
25
+ └─ Link / KISSLink (kiss.py) — KISS framing; implements ConnectionBase
26
+ └─ AX25Connection — AX.25 v2.2 state machine; implements ConnectionBase
27
+ └─ BPQNode — BBS protocol (L/R/S/K commands); implements NodeBase
28
+ └─ Engine — command/event loop running in a daemon thread
29
+ ├─ Store — SQLite message persistence
30
+ └─ TUI — Textual app, polls Engine event queue every 100ms
31
+ ```
32
+
33
+ ### Engine (`engine/`)
34
+
35
+ `Engine` runs in a background thread. The TUI sends it `Command` objects via a `queue.Queue` and reads `Event` objects from a second queue, polled every 100 ms in `OpenPacketApp._poll_events()`. Commands and events are defined in `commands.py` and `events.py`. Adding a new capability means adding a Command, an Event, a `_do_*` handler in `Engine`, and a handler branch in `app._handle_event()`.
36
+
37
+ ### Store (`store/`)
38
+
39
+ - `models.py` — plain dataclasses: `Operator`, `Node`, `Message`, `Bulletin`
40
+ - `database.py` — raw SQLite DDL, schema migrations, and low-level insert/query helpers
41
+ - `store.py` — higher-level query methods used by the engine and TUI (`list_messages`, `list_outbox`, `count_folder_stats`, etc.)
42
+
43
+ Schema migrations use `ALTER TABLE ... ADD COLUMN` in `Database.initialize()` with `except sqlite3.OperationalError: pass`. Always use `self._conn.execute()` for migrations — never `executescript()` (which issues an implicit COMMIT).
44
+
45
+ **Message state matrix:**
46
+ | Type | `queued` | `sent` |
47
+ |------|----------|--------|
48
+ | Received from BBS | 0 | 0 |
49
+ | Composed, awaiting send | 1 | 0 |
50
+ | Composed, transmitted | 1 | 1 |
51
+
52
+ **Bulletin body sentinel:** `Bulletin.body` is `Optional[str]` — `None` means header-only (not yet retrieved). Because the SQLite `body` column has `NOT NULL`, header-only rows are stored as `"\x00"` (NUL byte); `_row_to_bulletin` maps `"\x00"` back to `None`. Do not change this to `""` — empty string is a valid retrieved body. `wants_retrieval: bool` records user intent to fetch the body on the next sync.
53
+
54
+ The TUI calls `self._store` directly for lightweight operations that don't need connectivity (e.g. `mark_message_read`, `mark_bulletin_wants_retrieval`). Only operations that require a BBS connection go through the engine command queue.
55
+
56
+ ### TUI (`ui/tui/`)
57
+
58
+ - `app.py` (`OpenPacketApp`) — top-level Textual `App`; owns the engine, store, and active operator; handles all cross-widget coordination
59
+ - `screens/main.py` — primary layout; key bindings defined here in `BINDINGS`
60
+ - `widgets/folder_tree.py` — uses `node.data` (not `str(node.label)`) for folder routing so count suffixes don't break selection
61
+ - `widgets/console_panel.py` — receives `ConsoleEvent` objects from the engine via `log_frame(direction, text)`
62
+
63
+ Operator identity and node configuration are stored in SQLite and managed via TUI screens, not the config file. The config file (`~/.config/open-packet/config.yaml`) covers connection and storage settings only.
64
+
65
+ ### AX.25 / Node (`ax25/`, `node/`)
66
+
67
+ `AX25Connection` implements the AX.25 v2.2 data-link state machine (SABM/UA/DISC/I-frames, T1/T3 timers, Go-Back-N windowing). `BPQNode` sits on top and speaks the BPQ32 BBS text protocol. `connect_node()` sends `BBS\r`, waits for a prompt ending in `>`, and handles name prompts by replying with the operator callsign.
68
+
69
+ ## Documentation
70
+
71
+ The user-facing documentation lives in `docs/hugo/` as a [Hugo](https://gohugo.io/) static site using the [Lotus Docs](https://github.com/colinwilson/lotusdocs) theme (included as a Git submodule at `docs/hugo/themes/lotusdocs`). Hugo module dependencies (Bootstrap SCSS) are declared in `docs/hugo/go.mod`.
72
+
73
+ Content lives under `docs/hugo/content/docs/` organised into three sections: `user-guide/`, `reference/`, and `development/`. A print/PDF view of the full documentation is available at `/docs/print/`.
74
+
75
+ **When to update docs:** Update the relevant page in `docs/hugo/content/docs/` whenever you:
76
+ - Add or change a user-visible feature → update `user-guide/`
77
+ - Add, remove, or change a keyboard shortcut → update `reference/keyboard-shortcuts.md`
78
+ - Change the config file format → update `reference/configuration.md`
79
+ - Change the architecture (new commands, events, layers) → update `development/architecture.md`
80
+
81
+ **To preview docs locally:**
82
+ ```bash
83
+ cd docs/hugo
84
+ git submodule update --init --recursive
85
+ hugo server # then open http://localhost:1313
86
+ ```
87
+
88
+ The documentation is built and published to GitHub Pages automatically when a release is published. A combined PDF is also generated and attached to the release. See `.github/workflows/docs.yml`.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jeremy Banker - K0JLB
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,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: open-packet
3
+ Version: 0.1.0
4
+ Summary: Amateur radio packet messaging client
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: jinja2>=3.1
8
+ Requires-Dist: pyserial>=3.5
9
+ Requires-Dist: pyyaml>=6.0
10
+ Requires-Dist: textual-serve>=1.1.3
11
+ Requires-Dist: textual>=0.60.0
12
+ Description-Content-Type: text/markdown
13
+
14
+ # open-packet
15
+
16
+ An open-source packet messaging client for amateur radio operators.
17
+
18
+ > **Early development:** v0.1 — expect breaking changes between releases.
19
+
20
+ ![Screenshot of the open-packet terminal UI showing the message inbox](images/image.png)
21
+
22
+ ---
23
+
24
+ ## Quickstart
25
+
26
+ **Requirements:**
27
+ - Linux (Windows and MacOS are currently untested, but should probably work)
28
+ - Python >= 3.11
29
+ - A KISS-capable TNC connected via TCP or serial port. If you don't have hardware, [Direwolf](https://github.com/wb2osz/direwolf) is a good software TNC.
30
+
31
+ **Install:**
32
+
33
+ ```bash
34
+ uv tool install git+https://github.com/loredous/open-packet
35
+ ```
36
+
37
+ **Configure:**
38
+
39
+ Create `~/.config/open-packet/config.yaml`:
40
+
41
+ ```yaml
42
+ connection:
43
+ type: kiss_tcp # kiss_tcp | kiss_serial
44
+ host: localhost # TCP only
45
+ port: 8001 # TCP only
46
+ ```
47
+
48
+ **Run:**
49
+
50
+ ```bash
51
+ open-packet
52
+ ```
53
+
54
+ On first launch, you'll be prompted to enter your callsign and BBS node details. You can update these later via the Settings screen (`s`).
55
+
56
+ ---
57
+
58
+ ## How It Works
59
+
60
+ open-packet connects to a BBS node over AX.25 packet radio via a KISS TNC, syncing your personal messages and bulletins to a local SQLite database. The core engine is interface-agnostic — the terminal client is the first frontend, with a web client and other interfaces planned.
61
+
62
+ ---
63
+
64
+ ## Configuration
65
+
66
+ The config file lives at `~/.config/open-packet/config.yaml` (or pass a custom path as the first argument to `open-packet`).
67
+
68
+ ```yaml
69
+ connection:
70
+ type: kiss_tcp # kiss_tcp | kiss_serial
71
+ host: localhost # TCP only
72
+ port: 8001 # TCP only
73
+ # device: /dev/ttyUSB0 # serial only
74
+ # baud: 9600 # serial only
75
+
76
+ store:
77
+ db_path: ~/.local/share/open-packet/messages.db # SQLite message database
78
+ export_path: ~/.local/share/open-packet/export # flat-file export directory
79
+
80
+ ui:
81
+ console_visible: false # show AX.25 frame console on startup
82
+ console_buffer: 500 # number of lines to keep in the console ring buffer
83
+ # console_log: ~/.local/share/open-packet/console.log # log frame traffic to file (omit to disable)
84
+ ```
85
+
86
+ Operator identity (callsign, SSID) and BBS node configuration are managed interactively through the TUI rather than in the config file. Access them via the Settings screen (`s`).
87
+
88
+ ---
89
+
90
+ ## Development
91
+
92
+ ```bash
93
+ # Clone and install dependencies
94
+ git clone https://github.com/loredous/open-packet.git
95
+ cd open-packet
96
+ uv sync
97
+
98
+ # Run the app
99
+ uv run open-packet
100
+
101
+ # Run tests
102
+ uv run pytest
103
+
104
+ # Run with Textual's dev tools (live reload + DOM inspector)
105
+ # Note: this launches OpenPacketApp directly, bypassing main() — config loads from the default path
106
+ uv run textual run --dev open_packet/ui/tui/app.py
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Contributing
112
+
113
+ Contributions are welcome.
114
+
115
+ - Fork the repo and create a feature branch
116
+ - Write tests for new functionality
117
+ - Run `uv run pytest` before opening a pull request
118
+ - Open a pull request with a clear description of the change
119
+
120
+ ---
121
+
122
+ ## License
123
+
124
+ MIT — see [LICENSE](LICENSE) for details.
@@ -0,0 +1,111 @@
1
+ # open-packet
2
+
3
+ An open-source packet messaging client for amateur radio operators.
4
+
5
+ > **Early development:** v0.1 — expect breaking changes between releases.
6
+
7
+ ![Screenshot of the open-packet terminal UI showing the message inbox](images/image.png)
8
+
9
+ ---
10
+
11
+ ## Quickstart
12
+
13
+ **Requirements:**
14
+ - Linux (Windows and MacOS are currently untested, but should probably work)
15
+ - Python >= 3.11
16
+ - A KISS-capable TNC connected via TCP or serial port. If you don't have hardware, [Direwolf](https://github.com/wb2osz/direwolf) is a good software TNC.
17
+
18
+ **Install:**
19
+
20
+ ```bash
21
+ uv tool install git+https://github.com/loredous/open-packet
22
+ ```
23
+
24
+ **Configure:**
25
+
26
+ Create `~/.config/open-packet/config.yaml`:
27
+
28
+ ```yaml
29
+ connection:
30
+ type: kiss_tcp # kiss_tcp | kiss_serial
31
+ host: localhost # TCP only
32
+ port: 8001 # TCP only
33
+ ```
34
+
35
+ **Run:**
36
+
37
+ ```bash
38
+ open-packet
39
+ ```
40
+
41
+ On first launch, you'll be prompted to enter your callsign and BBS node details. You can update these later via the Settings screen (`s`).
42
+
43
+ ---
44
+
45
+ ## How It Works
46
+
47
+ open-packet connects to a BBS node over AX.25 packet radio via a KISS TNC, syncing your personal messages and bulletins to a local SQLite database. The core engine is interface-agnostic — the terminal client is the first frontend, with a web client and other interfaces planned.
48
+
49
+ ---
50
+
51
+ ## Configuration
52
+
53
+ The config file lives at `~/.config/open-packet/config.yaml` (or pass a custom path as the first argument to `open-packet`).
54
+
55
+ ```yaml
56
+ connection:
57
+ type: kiss_tcp # kiss_tcp | kiss_serial
58
+ host: localhost # TCP only
59
+ port: 8001 # TCP only
60
+ # device: /dev/ttyUSB0 # serial only
61
+ # baud: 9600 # serial only
62
+
63
+ store:
64
+ db_path: ~/.local/share/open-packet/messages.db # SQLite message database
65
+ export_path: ~/.local/share/open-packet/export # flat-file export directory
66
+
67
+ ui:
68
+ console_visible: false # show AX.25 frame console on startup
69
+ console_buffer: 500 # number of lines to keep in the console ring buffer
70
+ # console_log: ~/.local/share/open-packet/console.log # log frame traffic to file (omit to disable)
71
+ ```
72
+
73
+ Operator identity (callsign, SSID) and BBS node configuration are managed interactively through the TUI rather than in the config file. Access them via the Settings screen (`s`).
74
+
75
+ ---
76
+
77
+ ## Development
78
+
79
+ ```bash
80
+ # Clone and install dependencies
81
+ git clone https://github.com/loredous/open-packet.git
82
+ cd open-packet
83
+ uv sync
84
+
85
+ # Run the app
86
+ uv run open-packet
87
+
88
+ # Run tests
89
+ uv run pytest
90
+
91
+ # Run with Textual's dev tools (live reload + DOM inspector)
92
+ # Note: this launches OpenPacketApp directly, bypassing main() — config loads from the default path
93
+ uv run textual run --dev open_packet/ui/tui/app.py
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Contributing
99
+
100
+ Contributions are welcome.
101
+
102
+ - Fork the repo and create a feature branch
103
+ - Write tests for new functionality
104
+ - Run `uv run pytest` before opening a pull request
105
+ - Open a pull request with a clear description of the change
106
+
107
+ ---
108
+
109
+ ## License
110
+
111
+ MIT — see [LICENSE](LICENSE) for details.
@@ -0,0 +1,3 @@
1
+ public/
2
+ resources/
3
+ .hugo_build.lock
@@ -0,0 +1,34 @@
1
+ ---
2
+ title: "open-packet Documentation"
3
+ description: "Open-source amateur radio packet messaging client for Linux"
4
+ ---
5
+
6
+ # open-packet
7
+
8
+ **open-packet** is an open-source amateur radio packet messaging client for Linux. It connects to a BBS node over AX.25 packet radio via a KISS TNC, syncing your personal messages and bulletins to a local SQLite database and presenting them through a terminal user interface (TUI).
9
+
10
+ > **Early development:** v0.1 — expect breaking changes between releases.
11
+
12
+ ## Features
13
+
14
+ - **Messages** — read, compose, reply, archive, and delete personal packet messages
15
+ - **Bulletins** — browse bulletin categories and retrieve full bulletin bodies on demand
16
+ - **BBS Files** — list and download files from BBS file directories
17
+ - **ICS Forms** — compose and send structured ICS/standard forms messages
18
+ - **Terminal Connect** — open a raw terminal session to any AX.25 node
19
+ - **Multiple Operators & Nodes** — manage multiple callsigns and BBS nodes in a single installation
20
+ - **Offline-first** — all messages are stored locally in SQLite; connectivity is only needed to sync
21
+
22
+ ## Quick Navigation
23
+
24
+ ### [Getting Started]({{< relref "/docs/user-guide/getting-started" >}})
25
+ New to open-packet? Start here with installation and first-launch setup.
26
+
27
+ ### [User Guide]({{< relref "/docs/user-guide" >}})
28
+ Learn how to use messages, bulletins, BBS files, forms, and the terminal.
29
+
30
+ ### [Reference]({{< relref "/docs/reference" >}})
31
+ Configuration file reference and keyboard shortcuts.
32
+
33
+ ### [Development]({{< relref "/docs/development" >}})
34
+ Architecture overview and contribution guide.
@@ -0,0 +1,14 @@
1
+ ---
2
+ title: "Documentation"
3
+ description: "open-packet documentation home"
4
+ icon: "menu_book"
5
+ weight: 1
6
+ ---
7
+
8
+ Welcome to the open-packet documentation. Use the sidebar to navigate between sections.
9
+
10
+ | Section | Description |
11
+ |---------|-------------|
12
+ | [User Guide]({{< relref "user-guide" >}}) | Install, configure, and use open-packet day-to-day |
13
+ | [Reference]({{< relref "reference" >}}) | Keyboard shortcuts and configuration reference |
14
+ | [Development]({{< relref "development" >}}) | Architecture guide and contribution information |
@@ -0,0 +1,11 @@
1
+ ---
2
+ title: "Development"
3
+ description: "Architecture and contribution guide for open-packet"
4
+ icon: "code"
5
+ weight: 3
6
+ ---
7
+
8
+ | Topic | Description |
9
+ |-------|-------------|
10
+ | [Architecture]({{< relref "architecture" >}}) | Codebase layers and design principles |
11
+ | [Contributing]({{< relref "contributing" >}}) | How to contribute to open-packet |