jotline 0.9.6__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 (134) hide show
  1. jotline-0.9.6/.github/ISSUE_TEMPLATE/bug.yml +32 -0
  2. jotline-0.9.6/.github/ISSUE_TEMPLATE/config.yml +5 -0
  3. jotline-0.9.6/.github/ISSUE_TEMPLATE/feature.yml +20 -0
  4. jotline-0.9.6/.github/pull_request_template.md +11 -0
  5. jotline-0.9.6/.github/workflows/release.yml +92 -0
  6. jotline-0.9.6/.github/workflows/test.yml +69 -0
  7. jotline-0.9.6/.gitignore +15 -0
  8. jotline-0.9.6/CHANGELOG.md +262 -0
  9. jotline-0.9.6/CONTRIBUTING.md +71 -0
  10. jotline-0.9.6/LICENSE +21 -0
  11. jotline-0.9.6/PKG-INFO +734 -0
  12. jotline-0.9.6/README.md +697 -0
  13. jotline-0.9.6/ROADMAP.md +51 -0
  14. jotline-0.9.6/SECURITY.md +19 -0
  15. jotline-0.9.6/docs/actions.md +52 -0
  16. jotline-0.9.6/docs/drafts-feature-review.md +75 -0
  17. jotline-0.9.6/docs/find.svg +204 -0
  18. jotline-0.9.6/docs/hardening-2026-09-12/context.md +14 -0
  19. jotline-0.9.6/docs/hardening-2026-09-12/hardening.json +35 -0
  20. jotline-0.9.6/docs/hardening-2026-09-12/hardening.md +63 -0
  21. jotline-0.9.6/docs/import-recovery.md +68 -0
  22. jotline-0.9.6/docs/install.md +132 -0
  23. jotline-0.9.6/docs/macos-fix.md +28 -0
  24. jotline-0.9.6/docs/make_screenshot.py +37 -0
  25. jotline-0.9.6/docs/navigation.md +13 -0
  26. jotline-0.9.6/docs/platforms.md +41 -0
  27. jotline-0.9.6/docs/quick-capture.md +98 -0
  28. jotline-0.9.6/docs/redteam-2026-09-12.md +146 -0
  29. jotline-0.9.6/docs/redteam-review.md +112 -0
  30. jotline-0.9.6/docs/release-notes.md +28 -0
  31. jotline-0.9.6/docs/release-verification.md +103 -0
  32. jotline-0.9.6/docs/screenshot.svg +189 -0
  33. jotline-0.9.6/docs/settings.svg +203 -0
  34. jotline-0.9.6/docs/terminal-testing.md +67 -0
  35. jotline-0.9.6/docs/theme-research.md +40 -0
  36. jotline-0.9.6/examples/actions/README.md +5 -0
  37. jotline-0.9.6/examples/actions/starter-recipes.json +40 -0
  38. jotline-0.9.6/pyproject.toml +57 -0
  39. jotline-0.9.6/scripts/install.ps1 +20 -0
  40. jotline-0.9.6/scripts/install.py +226 -0
  41. jotline-0.9.6/scripts/release_metadata.py +46 -0
  42. jotline-0.9.6/scripts/smoke_install.py +177 -0
  43. jotline-0.9.6/scripts/smoke_pty.py +85 -0
  44. jotline-0.9.6/src/jotline/__init__.py +2 -0
  45. jotline-0.9.6/src/jotline/__main__.py +2 -0
  46. jotline-0.9.6/src/jotline/_windows_fs.py +214 -0
  47. jotline-0.9.6/src/jotline/action_history.py +118 -0
  48. jotline-0.9.6/src/jotline/action_recipes.py +56 -0
  49. jotline-0.9.6/src/jotline/action_ui.py +367 -0
  50. jotline-0.9.6/src/jotline/actions.py +140 -0
  51. jotline-0.9.6/src/jotline/app.py +1028 -0
  52. jotline-0.9.6/src/jotline/capture_ui.py +66 -0
  53. jotline-0.9.6/src/jotline/cli.py +717 -0
  54. jotline-0.9.6/src/jotline/cli_doctor.py +252 -0
  55. jotline-0.9.6/src/jotline/cli_io.py +109 -0
  56. jotline-0.9.6/src/jotline/commands.py +17 -0
  57. jotline-0.9.6/src/jotline/completion.py +396 -0
  58. jotline-0.9.6/src/jotline/connect_ui.py +232 -0
  59. jotline-0.9.6/src/jotline/crypto.py +166 -0
  60. jotline-0.9.6/src/jotline/desktop.py +472 -0
  61. jotline-0.9.6/src/jotline/desktop_data/__init__.py +1 -0
  62. jotline-0.9.6/src/jotline/desktop_data/gnome.txt +12 -0
  63. jotline-0.9.6/src/jotline/desktop_data/hyprland.conf +12 -0
  64. jotline-0.9.6/src/jotline/desktop_data/kde.txt +10 -0
  65. jotline-0.9.6/src/jotline/desktop_data/omarchy.lua +6 -0
  66. jotline-0.9.6/src/jotline/desktop_data/org.jotline.capture.desktop +13 -0
  67. jotline-0.9.6/src/jotline/desktop_data/pipe.txt +9 -0
  68. jotline-0.9.6/src/jotline/encryption_ui.py +140 -0
  69. jotline-0.9.6/src/jotline/export.py +342 -0
  70. jotline-0.9.6/src/jotline/filesystem.py +255 -0
  71. jotline-0.9.6/src/jotline/history.py +492 -0
  72. jotline-0.9.6/src/jotline/import_ui.py +116 -0
  73. jotline-0.9.6/src/jotline/importing.py +259 -0
  74. jotline-0.9.6/src/jotline/limits.py +13 -0
  75. jotline-0.9.6/src/jotline/links.py +248 -0
  76. jotline-0.9.6/src/jotline/markdown_editor.py +850 -0
  77. jotline-0.9.6/src/jotline/modal.py +131 -0
  78. jotline-0.9.6/src/jotline/navigation.py +247 -0
  79. jotline-0.9.6/src/jotline/note_menu.py +89 -0
  80. jotline-0.9.6/src/jotline/omarchy.py +104 -0
  81. jotline-0.9.6/src/jotline/preferences.py +154 -0
  82. jotline-0.9.6/src/jotline/recovery_ui.py +46 -0
  83. jotline-0.9.6/src/jotline/review_ui.py +190 -0
  84. jotline-0.9.6/src/jotline/screens.py +229 -0
  85. jotline-0.9.6/src/jotline/search.py +65 -0
  86. jotline-0.9.6/src/jotline/settings.py +367 -0
  87. jotline-0.9.6/src/jotline/store.py +794 -0
  88. jotline-0.9.6/src/jotline/tasks.py +157 -0
  89. jotline-0.9.6/src/jotline/templates.py +242 -0
  90. jotline-0.9.6/src/jotline/workflows.py +347 -0
  91. jotline-0.9.6/tests/conftest.py +80 -0
  92. jotline-0.9.6/tests/test_action_experience.py +273 -0
  93. jotline-0.9.6/tests/test_app.py +181 -0
  94. jotline-0.9.6/tests/test_cli_append_errors.py +103 -0
  95. jotline-0.9.6/tests/test_cli_redteam.py +218 -0
  96. jotline-0.9.6/tests/test_cli_scripting.py +362 -0
  97. jotline-0.9.6/tests/test_connections.py +229 -0
  98. jotline-0.9.6/tests/test_desktop.py +370 -0
  99. jotline-0.9.6/tests/test_drafts_workflows.py +334 -0
  100. jotline-0.9.6/tests/test_editing_hardening.py +76 -0
  101. jotline-0.9.6/tests/test_encryption.py +237 -0
  102. jotline-0.9.6/tests/test_export.py +218 -0
  103. jotline-0.9.6/tests/test_history.py +472 -0
  104. jotline-0.9.6/tests/test_hotkeys.py +138 -0
  105. jotline-0.9.6/tests/test_import_integration_review.py +108 -0
  106. jotline-0.9.6/tests/test_import_recovery.py +203 -0
  107. jotline-0.9.6/tests/test_install.py +192 -0
  108. jotline-0.9.6/tests/test_integration_redteam.py +36 -0
  109. jotline-0.9.6/tests/test_knowledge_worker.py +168 -0
  110. jotline-0.9.6/tests/test_markdown.py +113 -0
  111. jotline-0.9.6/tests/test_markdown_editor.py +443 -0
  112. jotline-0.9.6/tests/test_markdown_hotkeys.py +84 -0
  113. jotline-0.9.6/tests/test_markdown_toolbar.py +106 -0
  114. jotline-0.9.6/tests/test_navigation.py +109 -0
  115. jotline-0.9.6/tests/test_newcomer_flow.py +73 -0
  116. jotline-0.9.6/tests/test_note_menu.py +181 -0
  117. jotline-0.9.6/tests/test_omarchy.py +131 -0
  118. jotline-0.9.6/tests/test_packaging.py +101 -0
  119. jotline-0.9.6/tests/test_platforms.py +181 -0
  120. jotline-0.9.6/tests/test_quick_capture.py +73 -0
  121. jotline-0.9.6/tests/test_redteam_2026_09_12.py +592 -0
  122. jotline-0.9.6/tests/test_settings.py +94 -0
  123. jotline-0.9.6/tests/test_shutdown.py +28 -0
  124. jotline-0.9.6/tests/test_storage_cache.py +165 -0
  125. jotline-0.9.6/tests/test_storage_redteam.py +422 -0
  126. jotline-0.9.6/tests/test_store.py +184 -0
  127. jotline-0.9.6/tests/test_tasks.py +122 -0
  128. jotline-0.9.6/tests/test_templates.py +145 -0
  129. jotline-0.9.6/tests/test_ui_redteam.py +228 -0
  130. jotline-0.9.6/tests/test_usability_integration.py +248 -0
  131. jotline-0.9.6/tests/test_windows_console.py +46 -0
  132. jotline-0.9.6/tests/test_workflow_additions.py +116 -0
  133. jotline-0.9.6/tests/test_workspaces_tags.py +142 -0
  134. jotline-0.9.6/uv.lock +360 -0
@@ -0,0 +1,32 @@
1
+ name: Bug report
2
+ description: Report unexpected behavior with reproducible steps.
3
+ labels: [bug]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: Please use synthetic notes. For security vulnerabilities, follow SECURITY.md instead of posting publicly.
8
+ - type: textarea
9
+ id: environment
10
+ attributes:
11
+ label: Environment
12
+ description: Jotline version, Python version, OS, terminal and terminal version.
13
+ validations:
14
+ required: true
15
+ - type: textarea
16
+ id: reproduce
17
+ attributes:
18
+ label: Steps to reproduce
19
+ description: Include the smallest example that shows the problem.
20
+ validations:
21
+ required: true
22
+ - type: textarea
23
+ id: behavior
24
+ attributes:
25
+ label: Expected and actual behavior
26
+ validations:
27
+ required: true
28
+ - type: textarea
29
+ id: diagnostics
30
+ attributes:
31
+ label: Diagnostics or screenshots
32
+ description: Optional jotline doctor --json output. Review local paths before sharing; remove personal information.
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: true
2
+ contact_links:
3
+ - name: Report a security vulnerability privately
4
+ url: https://github.com/CaulShiver/jotline/security/advisories/new
5
+ about: Please do not disclose exploitable issues or private notes in a public issue.
@@ -0,0 +1,20 @@
1
+ name: Workflow improvement
2
+ description: Explain a task Jotline could make easier.
3
+ body:
4
+ - type: textarea
5
+ id: task
6
+ attributes:
7
+ label: What are you trying to do?
8
+ description: Describe the writing or review task and where you get stuck.
9
+ validations:
10
+ required: true
11
+ - type: textarea
12
+ id: suggestion
13
+ attributes:
14
+ label: Suggested behavior
15
+ description: Include an example and any workaround you use today.
16
+ - type: textarea
17
+ id: fit
18
+ attributes:
19
+ label: Terminal and offline considerations
20
+ description: Optional keyboard, platform, accessibility or external-service requirements.
@@ -0,0 +1,11 @@
1
+ Describe the problem and the resulting user behavior.
2
+
3
+ ## Validation
4
+
5
+ Include relevant test results and any manual terminal checks. For UI changes,
6
+ show the affected workflow with synthetic notes. State platforms not tested.
7
+
8
+ ## Compatibility
9
+
10
+ Mention changes to note files, settings, shortcuts, imports, or install behavior,
11
+ and update user-facing documentation where needed.
@@ -0,0 +1,92 @@
1
+ name: Release
2
+ on:
3
+ push:
4
+ tags: ['v*']
5
+ permissions:
6
+ contents: read
7
+ jobs:
8
+ verify:
9
+ uses: ./.github/workflows/test.yml
10
+ package:
11
+ needs: verify
12
+ runs-on: ubuntu-latest
13
+ timeout-minutes: 15
14
+ steps:
15
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
16
+ with:
17
+ persist-credentials: false
18
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
19
+ with:
20
+ python-version: '3.12'
21
+ - name: Check release identity
22
+ env:
23
+ RELEASE_TAG: ${{ github.ref_name }}
24
+ run: python scripts/release_metadata.py
25
+ - name: Build and checksum packages
26
+ run: |
27
+ python -m pip install uv==0.12.10
28
+ uv build --clear
29
+ python scripts/release_metadata.py --checksums
30
+ uvx twine==7.0.0 check dist/*.whl dist/*.tar.gz
31
+ - name: Smoke-test the exact release wheel through the public installer
32
+ run: |
33
+ uv venv /tmp/jotline-release-smoke
34
+ python scripts/install.py --from-dir dist --python /tmp/jotline-release-smoke/bin/python --installer pip
35
+ /tmp/jotline-release-smoke/bin/python -I scripts/smoke_install.py
36
+ /tmp/jotline-release-smoke/bin/python -I scripts/smoke_pty.py
37
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
38
+ with:
39
+ name: release-dist
40
+ path: |
41
+ dist/*.whl
42
+ dist/*.tar.gz
43
+ dist/SHA256SUMS
44
+ dist/install.py
45
+ dist/install.ps1
46
+ if-no-files-found: error
47
+ github-release:
48
+ needs: package
49
+ runs-on: ubuntu-latest
50
+ timeout-minutes: 10
51
+ permissions:
52
+ contents: write
53
+ steps:
54
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
55
+ with:
56
+ persist-credentials: false
57
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
58
+ with:
59
+ name: release-dist
60
+ path: dist
61
+ - name: Publish GitHub Release assets
62
+ env:
63
+ GH_TOKEN: ${{ github.token }}
64
+ RELEASE_TAG: ${{ github.ref_name }}
65
+ run: |
66
+ assets=(dist/*.whl dist/*.tar.gz dist/SHA256SUMS dist/install.py dist/install.ps1)
67
+ if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
68
+ gh release upload "$RELEASE_TAG" "${assets[@]}" --clobber
69
+ else
70
+ gh release create "$RELEASE_TAG" "${assets[@]}" --verify-tag --title "Jotline $RELEASE_TAG" --notes-file docs/release-notes.md
71
+ fi
72
+ pypi:
73
+ needs: package
74
+ runs-on: ubuntu-latest
75
+ timeout-minutes: 10
76
+ environment:
77
+ name: pypi
78
+ url: https://pypi.org/project/jotline/
79
+ permissions:
80
+ id-token: write
81
+ steps:
82
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
83
+ with:
84
+ name: release-dist
85
+ path: dist
86
+ - name: Stage PyPI packages only
87
+ run: |
88
+ mkdir pypi-dist
89
+ cp dist/*.whl dist/*.tar.gz pypi-dist/
90
+ - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
91
+ with:
92
+ packages-dir: pypi-dist
@@ -0,0 +1,69 @@
1
+ name: Tests
2
+ on:
3
+ push:
4
+ branches: ['**']
5
+ pull_request:
6
+ workflow_call:
7
+ permissions:
8
+ contents: read
9
+ jobs:
10
+ test:
11
+ runs-on: ${{ matrix.os }}
12
+ timeout-minutes: 15
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ os: [ubuntu-latest, macos-latest, windows-latest]
17
+ python: ['3.11', '3.12', '3.13']
18
+ defaults:
19
+ run:
20
+ shell: bash
21
+ env:
22
+ PYTHONUTF8: '1'
23
+ steps:
24
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
25
+ with:
26
+ persist-credentials: false
27
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
28
+ with:
29
+ python-version: ${{ matrix.python }}
30
+ - name: Install uv
31
+ timeout-minutes: 2
32
+ run: python -m pip install uv==0.12.10
33
+ - name: Check locked project resolve
34
+ timeout-minutes: 2
35
+ run: uv lock --check --python '${{ matrix.python }}'
36
+ - name: Check latest dependency resolve
37
+ if: matrix.python == '3.13'
38
+ timeout-minutes: 4
39
+ run: uv lock --upgrade --dry-run --python '${{ matrix.python }}'
40
+ - name: Check direct lower bounds
41
+ if: matrix.python == '3.11' && matrix.os == 'ubuntu-latest'
42
+ timeout-minutes: 5
43
+ run: |
44
+ uv venv /tmp/jotline-lower-bound --python '${{ matrix.python }}'
45
+ uv pip install --python /tmp/jotline-lower-bound/bin/python --strict -e . 'textual==8.2.8' 'pytest==8.2.0' 'pytest-asyncio==0.24.0'
46
+ /tmp/jotline-lower-bound/bin/python -m pytest -q tests/test_cli_redteam.py tests/test_packaging.py
47
+ - name: Sync locked test environment
48
+ timeout-minutes: 4
49
+ run: uv sync --locked --extra dev --extra encryption --python '${{ matrix.python }}'
50
+ - name: Run tests
51
+ timeout-minutes: 8
52
+ run: uv run --locked pytest -q -o faulthandler_timeout=60
53
+ - name: Build distributions
54
+ timeout-minutes: 3
55
+ run: uv build --clear
56
+ - name: Checksum packages and copy installers
57
+ timeout-minutes: 2
58
+ run: python scripts/release_metadata.py --checksums
59
+ - name: Install and exercise the built wheel through the public installer
60
+ timeout-minutes: 4
61
+ run: |
62
+ uv venv .smoke-venv --python '${{ matrix.python }}'
63
+ if [ "$RUNNER_OS" = "Windows" ]; then
64
+ smoke_python=.smoke-venv/Scripts/python.exe
65
+ else
66
+ smoke_python=.smoke-venv/bin/python
67
+ fi
68
+ python scripts/install.py --from-dir dist --python "$smoke_python" --installer pip
69
+ "$smoke_python" -I scripts/smoke_install.py
@@ -0,0 +1,15 @@
1
+ .venv/
2
+ __pycache__/
3
+ .pytest_cache/
4
+ *.egg-info/
5
+ dist/
6
+ notes/
7
+ *.log
8
+ audit/
9
+
10
+ .jotline-history/
11
+ .jotline-backups/
12
+ .jotline-templates/
13
+ .jotline-settings.json
14
+ .jotline.lock
15
+ .jotline-action-history.json
@@ -0,0 +1,262 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## 0.9.6 — 2026-09-15
6
+
7
+ - The `v0.9.5` tag never uploaded GitHub Release assets or PyPI files.
8
+ Hatchling now emits Metadata-Version 2.5; the release job still ran
9
+ `twine==6.1.0`, which rejects that version. The check now uses Twine 7.
10
+ The rest of 0.9.5 is unchanged.
11
+
12
+ ## 0.9.5 — 2026-09-15
13
+
14
+ - Daily logs can move through days: Previous daily log, Next daily log, and Open
15
+ daily log by date (`YYYY-MM-DD`, `today`, or `yesterday`) in the command
16
+ palette. Missing days use the daily template, as today already did. Optional
17
+ shortcuts start unassigned. `jotline daily` opens today's log in the app;
18
+ `jotline daily --date yesterday` opens another day. `jotline capture --daily --date`
19
+ appends to that log.
20
+ - **Extract selection to new note** saves the selection as an inbox note and
21
+ replaces it with a `[[id|title]]` link, as one undo step.
22
+ - **Process next inbox note** opens the oldest inbox capture (daily logs are
23
+ skipped). Filing that note with Move to collection opens the next. The status
24
+ line shows how many captures remain. `jotline stats` (and `--json`) prints
25
+ workspace counts without note bodies.
26
+ - Connections are a first-class loop: Alt+K (or Ctrl+P → Show connections)
27
+ lists incoming and outgoing notes with the line that contains each link.
28
+ Follow opens the `[[link]]` under the cursor; a missing target can create a
29
+ note and rewrite the typed `[[title]]` to a stable `[[id|title]]`. Click a
30
+ link in preview, or Ctrl+click one in the editor. Compact terminals keep
31
+ `←N →N` on the status line when the connections bar is hidden.
32
+ `jotline backlinks NOTE [--json]` prints the same graph. Wiki links inside
33
+ fenced code or inline code spans no longer count as connections. Typing `[[`
34
+ to complete a note link no longer offers the note you are already in.
35
+ - Linux desktop capture is a shipped feature: `jotline desktop install` writes
36
+ an XDG `jotline capture` desktop entry, `jotline desktop launch` opens the
37
+ capture editor in a terminal, and `jotline desktop recipe` prints Omarchy,
38
+ Hyprland, GNOME, KDE, and clipboard-pipe snippets with this install's
39
+ `jotline` path. No dictation, share sheet, or cloud. Windows and macOS keep
40
+ `jotline capture` and pipe-in.
41
+ - Install no longer requires hunting a wheel filename. A tagged GitHub Release
42
+ attaches the wheel, source archive, `SHA256SUMS`, `install.py`, and
43
+ `install.ps1`. Linux and macOS use
44
+ `curl …/install.py | python3`; Windows PowerShell uses
45
+ `irm …/install.ps1 | iex`. The installer verifies SHA-256 before installing
46
+ with uv, pipx, or pip.
47
+ - `uv tool install jotline` / `pipx install jotline` are the PyPI commands. The
48
+ tag workflow publishes to PyPI with Trusted Publishing after the GitHub
49
+ assets exist. Linux, macOS, and Windows remain the supported-OS contract;
50
+ Windows is not dropped to make a tag publishable.
51
+ - CI installs the built wheel through `scripts/install.py` on Linux, macOS, and
52
+ Windows before a tag can publish.
53
+
54
+ ## 0.9.4 — 2026-09-15
55
+
56
+ - GitHub Release assets for the `v0.9.3` tag were never uploaded: Windows
57
+ Python 3.11 failed `test_builder_keyboard_only_preview_close_save` on a 60×20
58
+ terminal because Preview sat one row below the screen. The action builder now
59
+ pins Preview, Save, and Cancel below the form, matching Settings.
60
+ - The test job allows eight minutes for pytest. A slow PDF converter on
61
+ Ubuntu/Python 3.12 previously finished the suite in 299s and still failed the
62
+ five-minute step timeout.
63
+ - Settings opens with Ctrl+, so it works on Mac keyboards that do not send
64
+ F-keys without Fn. F1 still opens Settings where function keys work.
65
+ - On macOS, import and recipe files under `/tmp` or `$TMPDIR` (`/var/folders`)
66
+ work. Those prefixes are OS compatibility links to `/private`; user-created
67
+ aliases later in the path are still refused.
68
+ - Optional Omarchy desktop theme synchronization, including live palette,
69
+ cursor and selection updates in the editor and quick-capture window.
70
+
71
+ - Markdown has an editor toolbar for bold, italic, headings, lists, tasks, links,
72
+ inline code, all other formats, and preview. Mouse selections retain their
73
+ Markdown colours on a theme-tinted background, and the cursor uses the theme
74
+ accent. Theme changes update both immediately.
75
+ - PDF export no longer hangs or crashes on common setups. Every installed
76
+ Chromium-based browser is tried in turn, each with its own profile. On Ubuntu
77
+ 23.10 and later, where Chromium's sandbox cannot start, a browser is retried
78
+ without it (the page loads nothing and its CSP blocks scripts). Chrome on
79
+ macOS no longer waits on the keychain or on helper processes after printing,
80
+ Windows' `chrome.exe` launcher no longer counts as finished before the PDF is
81
+ written, and a stuck browser gives up after 30 seconds instead of 180.
82
+ - On Windows, a command run with input from `NUL` (a scheduled task or script)
83
+ is no longer mistaken for a terminal: a missing passphrase fails with the
84
+ `JOTLINE_PASSPHRASE` hint instead of waiting forever, and `capture` reads the
85
+ empty input instead of opening the editor.
86
+ - Markdown editing fixes from a code review. Format link keeps a multi-line
87
+ selection on one line in CRLF notes and accepts a selected `<autolink>`.
88
+ Insert or tidy table no longer pulls a paragraph above the table containing
89
+ a pipe into the table, and dash-only body rows no longer truncate the table. Toggling a code block off works when the selection ends at the start
90
+ of the closing fence. Numbered lists keep task checkboxes. Jump to heading
91
+ keeps a `#` that is part of a title (such as `C#`), lists setext headings,
92
+ and is one command again. Enter after a `- - -` rule no longer starts a
93
+ list. A horizontal rule gets exactly one blank line on each side. The
94
+ side-by-side preview follows the cursor as well as edits, waits for its
95
+ content before scrolling, and stops rendering while the terminal is too
96
+ small to show it. It can be switched off while compact, responds to terminal
97
+ resizes immediately, and picks up externally renamed link titles on refresh. Highlighting rescans only the edited rows, so typing in
98
+ large notes no longer lags. Exports, tasks and highlighting share one rule
99
+ for fenced code, and `[[links]]` inside code spans are left alone.
100
+ - Storage fixes from the same review. A revision removed by another process
101
+ between listing and stat no longer makes a note's history read as empty;
102
+ permission and I/O errors still surface. Concurrent backup pruning no longer
103
+ reports a failed daily backup when an archive disappears before stat.
104
+ Exporting a note snapshots its text first, so typing during a slow PDF
105
+ export cannot change what is written. A folder import skips an unreadable
106
+ entry instead of abandoning the rest of that folder.
107
+ - Tags are highlighted with the rule the vault uses to index them, so `#123`
108
+ now counts. Tags inside URL destinations and fragments are not highlighted.
109
+ - Moving a note now reports `Moved to X`, prefixes failures with `Note was not
110
+ moved:`, refreshes connections, and shows any backup warning.
111
+ - Workspace mismatch errors now consistently name the `--workspace NAME` option.
112
+ CLI export uses the same terminal-control refusal message as other commands.
113
+ - Applying an empty note selection now shows `Select at least one note first`.
114
+ - Internal cleanup with no behaviour change: the CLI dispatches commands
115
+ through one handler per command, repeated messages and limits are named
116
+ constants, temporary-file removal and modal cancel share one helper each,
117
+ and dead code was removed.
118
+ - Full Markdown editing in the app. The editor highlights Markdown syntax in the
119
+ current theme's colours, with no new dependency. Enter continues bullet,
120
+ numbered, task and quote lines, and Enter on an empty item ends the list.
121
+ Formatting commands now toggle off. New commands: strikethrough, heading
122
+ levels 1–6, numbered and task lists, code blocks, links, images, horizontal
123
+ rules, indent and outdent, and insert or tidy table. Ctrl+P → Toggle
124
+ side-by-side Markdown preview renders while you type, and Jump to heading
125
+ lists a note's headings. Previews show checkboxes and note-link titles as
126
+ exports do. Every new command can take an optional shortcut, and F1 → Editor
127
+ turns highlighting or list continuation off.
128
+ - Commands that take a note (`append`, `prepend`, `open`, `run`, `export`,
129
+ `tag`) accept a unique ID prefix of four or more characters, an exact title
130
+ (any letter case), or `last`. Ambiguous references are refused with the
131
+ matching IDs. The missing-note error now reads "No note with ID or title …".
132
+ - `capture`, `append`, `prepend` and `import` accept `--encoding NAME` and
133
+ `--replace-invalid`. Decoding errors suggest both, and folder imports report
134
+ a bad file in plain language instead of a codec error. Undecodable bytes in
135
+ command-line text are reported the same way.
136
+ - `tags`, `workspaces` and `actions` accept `--json`, joining `list` and `doctor`.
137
+ - `jotline completion bash|zsh|fish` prints a completion script for commands,
138
+ options, note IDs, tags, workspaces and actions.
139
+ - `jotline tasks` lists open `- [ ]` tasks across the workspace, with optional
140
+ due dates (`due:2026-09-20` or `📅 2026-09-20`), a search filter, `--due`,
141
+ `--done` and `--json`. `jotline done NOTE:LINE` checks one off (`--undo`
142
+ reopens it). In the app, Ctrl+P → Open tasks across notes jumps to a task.
143
+ - `jotline capture` with no text in a terminal opens a small capture editor
144
+ (Ctrl+S saves, Esc cancels). [docs/quick-capture.md](docs/quick-capture.md)
145
+ binds it to a global key on Omarchy/Hyprland, GNOME and KDE.
146
+ - `jotline export` saves HTML, Word (`.docx`) and PDF with `--format` or an
147
+ `--output` file extension; `--force` replaces an existing file. HTML is built
148
+ in; Word uses pandoc or LibreOffice and PDF a Chromium-based browser,
149
+ LibreOffice or pandoc. Ctrl+P → Export note as… does the same in the app.
150
+ - Opt-in encryption for sensitive notes: `jotline encryption setup`, then
151
+ `jotline encrypt NOTE` or Ctrl+P → Encrypt this note. Note text is sealed with
152
+ AES-256-GCM under a passphrase-wrapped key; unencrypted saved versions of the
153
+ note are removed, and locked notes show as "Encrypted note (locked)". Needs
154
+ the `cryptography` package (`jotline[encryption]`). There is no passphrase
155
+ recovery. Versions before this release show encrypted notes as unreadable text.
156
+
157
+ ## 0.9.3 — 2026-09-12
158
+
159
+ - `jotline append` and `prepend` put the text on its own line. They add one
160
+ line break in the note's newline style when the text would otherwise run into
161
+ the note, which merged words and created false tags such as `#ideaappended`.
162
+ Pass `--no-newline` for the previous exact join. Actions are unchanged.
163
+ - CLI errors are plain language: a missing note reads "No note with ID …", a
164
+ missing file no longer shows `[Errno 2]`, and non-UTF-8 input names its source
165
+ instead of printing a Python codec error.
166
+ - Tagged as `v0.9.3`; the release workflow did not publish wheels. Install 0.9.4.
167
+
168
+ ## 0.9.2 — 2026-09-12
169
+
170
+ Fixes from the 2026-09-12 multi-agent red team (storage, CLI, parsing, UI).
171
+ See [docs/redteam-2026-09-12.md](docs/redteam-2026-09-12.md).
172
+
173
+ - Saves fall back to rename on filesystems that refuse hard links (FAT/exFAT
174
+ media, SMB shares, shared folders). A failed publish now puts the original
175
+ note straight back under its own name, and any warning that names a retained
176
+ file survives sidebar refreshes.
177
+ - A daily backup that cannot be written (full disk, unsafe backup folder) no
178
+ longer blocks note saves or recovery copies; it becomes a warning. The daily
179
+ archive is validated once per session instead of on every save, and stale
180
+ temporary files from interrupted writes are removed after an hour and listed
181
+ by `jotline doctor`.
182
+ - One invalid settings value no longer resets every other preference: valid
183
+ fields are kept, the bad field is named, and the next save preserves actions,
184
+ views, hotkeys and unknown keys. Unreadable settings files are set aside as
185
+ `.jotline-settings.json.invalid-*.json` rather than overwritten.
186
+ - Opening a note never rewrites it: notes with Unicode line separators, form
187
+ feeds, lone CR or mixed newlines stay clean until you actually edit them, and
188
+ no longer trigger false external-change dialogs.
189
+ - Task toggle, heading/list/quote formatting, find context and arrange now use
190
+ the editor's own line model, fixing a crash on lone-CR notes and inserted
191
+ blank lines on CRLF notes.
192
+ - Modal dialogs ignore a second dismissal (key repeat, Enter then Escape, or a
193
+ mouse double-click), which previously ended the app or silently closed the
194
+ action builder.
195
+ - Ctrl+Q, Ctrl+N, Ctrl+S, opening a note and switching workspace re-show the
196
+ external-change dialog after it was dismissed; re-selecting the open note
197
+ keeps its undo history.
198
+ - A byte-order mark added by an external editor no longer strips a note's
199
+ collection, star, workspace and created date; folder imports of Jotline's own
200
+ note files keep that metadata too.
201
+ - Markdown preview refuses notes with more than 600 content lines or very wide
202
+ tables, which stalled the interface for ten seconds or more.
203
+ - Jump to heading used a quadratic regular expression; a 20 KB heading line
204
+ took seconds and a long one minutes.
205
+ - Text search no longer matches one or two characters against random digits of
206
+ every note ID; ID matching needs an 8-character prefix. Links and `title:`
207
+ filters match the full first line, not only its first 100 characters.
208
+ - Terminal-safety checks accept ordinary text such as CRLF, joined emoji,
209
+ soft hyphens and byte-order marks; `jotline run` checks exported output
210
+ before any step applies and accepts `--raw`. Closed stdin and a closed pipe
211
+ reader are handled quietly; `--vault ""` is rejected and a relative
212
+ `XDG_DATA_HOME` is ignored. Shell commands wait up to ten seconds for the
213
+ vault lock instead of one.
214
+ - Revision history orders versions by write time, so a clock step backwards
215
+ cannot offer stale content or prune the newest version.
216
+ - A corrupt action-history file is set aside and logging resumes. One stray
217
+ entry in the templates folder no longer hides every template. Symlinked
218
+ ancestors are reported as such instead of "Not a directory".
219
+ - Read-only commands fail with "Vault does not exist" instead of creating an
220
+ empty vault at a mistyped path; the preview labels unrendered HTML blocks.
221
+
222
+ ## 0.9.1 — 2026-09-12
223
+
224
+ - Bound cached search results to one second before the next scan rereads them.
225
+ External edits that preserve all tracked timestamps no longer remain cached
226
+ indefinitely. Refresh vault still forces an immediate reread.
227
+ - Add deterministic coverage for timestamp collisions and cache expiry.
228
+
229
+ ## 0.9.0 — 2026-09-12
230
+
231
+ - Added an action builder, starter recipes, result previews, action editing and
232
+ duplication, recipe sharing, and bounded action run history.
233
+ - Added visible navigation controls, contextual empty states, and an optional
234
+ quick-start guide that preserves the current note.
235
+ - Added saved-view editing, renaming, duplication and updates, filter controls,
236
+ and an active-view indicator.
237
+ - Added recovery comparison with explicit preservation of the full local draft
238
+ before reviewing an external version.
239
+ - Added folder and Drafts JSON export import with preview, metadata mapping,
240
+ duplicate handling and partial-result summaries.
241
+ - Added versioned release packages with checksums and a cross-platform test gate,
242
+ installation/update/uninstall instructions, and contributor templates.
243
+ - Added private vulnerability reporting, a security policy, a public roadmap,
244
+ and a terminal/accessibility testing checklist.
245
+ - Corrected replacement failure feedback, backward selection search navigation,
246
+ and canonical date-filter validation.
247
+ - Restored Tab/Shift+Tab navigation inside modals and removed a redundant
248
+ Markdown preview render.
249
+
250
+ Existing notes and settings remain readable. Imports create new notes and do not
251
+ overwrite existing notes. Compact date filters must use `YYYY-MM-DD`. Local
252
+ action history is stored separately from note revision history.
253
+ Older releases do not recognize the new `quote` and `restore` recipe steps;
254
+ back up settings before downgrading, or remove those recipes using 0.9.0 first.
255
+
256
+ ## 0.8.1 and earlier
257
+
258
+ The pre-release source history introduced Markdown capture, collections,
259
+ workspaces, tags, templates, history/backups, saved views, local JSON actions,
260
+ native Windows/macOS support and sidebar context menus. See the Git history and
261
+ [earlier review](docs/redteam-review.md) for the historical fixes. Version 0.9.0
262
+ is the first packaged GitHub release.
@@ -0,0 +1,71 @@
1
+ # Contributing
2
+
3
+ Jotline values fast capture, readable files, and a small keyboard-first interface.
4
+
5
+ Start with [ROADMAP.md](ROADMAP.md) for priorities and scoped starter tasks.
6
+ Use the workflow-improvement issue template to describe user needs before a
7
+ large change. Recipes and terminal compatibility reports are useful contributions
8
+ alongside code. Security issues should follow [SECURITY.md](SECURITY.md).
9
+
10
+ Install with `uv sync --extra dev`. Before opening a pull request, run the locked
11
+ suite with `uv run --locked pytest -q`. CI also checks an unlocked latest resolve
12
+ with `uv lock --upgrade --dry-run`, a direct lower-bound environment, and a clean
13
+ installed-wheel smoke run. For local release checks, build with `uv build --clear`
14
+ and run `python scripts/install.py --from-dir dist --installer pip` into a fresh
15
+ venv, then `python -I scripts/smoke_install.py` from that environment.
16
+
17
+ CI runs the complete suite and installed-wheel CLI/TUI smoke checks on Linux,
18
+ macOS, and Windows with Python 3.11–3.13. POSIX-only filesystem cases are marked
19
+ explicitly; Windows has separate native handle, junction, and locking coverage.
20
+ Storage code uses `jotline.filesystem.fs`: native `os` on Unix and a pinned-handle
21
+ backend on Windows. Keep file I/O UTF-8 with explicit newlines; do not substitute
22
+ unprotected path operations for descriptor-relative storage calls.
23
+
24
+ Storage changes should cover round trips, external edits, failed saves, and doctor
25
+ diagnostics. UI changes should exercise the relevant keyboard workflow with Textual's
26
+ Pilot. Use temporary vaults for testing; never include personal notes in commits or
27
+ screenshots.
28
+
29
+ Follow [the terminal and accessibility checklist](docs/terminal-testing.md) for
30
+ native UI verification. Headless tests cannot certify clipboard, screen-reader,
31
+ or input-method compatibility. On POSIX, the fresh wheel environment can also
32
+ run `python -I scripts/smoke_pty.py` to exercise actual terminal input and saves.
33
+
34
+ The package version is single-sourced in `src/jotline/__init__.py`; `pyproject.toml`
35
+ reads it dynamically. Release pull requests should update that value and any
36
+ user-facing status text together.
37
+
38
+ For bugs, include the Jotline/Python version, terminal, steps to reproduce, and the
39
+ error message. `jotline doctor --json` reports counts, paths, versions, limits,
40
+ and local state without note bodies. Review local paths before attaching it. Do not
41
+ include secrets or private notes. New integrations should be explicitly
42
+ user-triggered and preserve the offline core.
43
+
44
+ ## Releases
45
+
46
+ Update the package version, main README, [CHANGELOG.md](CHANGELOG.md), and
47
+ `docs/release-notes.md` together. Build and exercise the installed wheel locally.
48
+ `python scripts/release_metadata.py --checksums` checks package names and writes
49
+ SHA-256 checksums after `uv build --clear`.
50
+
51
+ Push an annotated matching `vX.Y.Z` tag to start the release workflow. It runs
52
+ the complete Linux/macOS/Windows test and installer-smoke matrix, then publishes
53
+ the wheel, source archive, checksums, and `install.py` / `install.ps1` to GitHub
54
+ Releases. A later job uploads the wheel and sdist to PyPI with Trusted
55
+ Publishing. The tag must match the single-sourced package version. A failed
56
+ verification job prevents publication. Never move an already-published tag; fix
57
+ the issue and release a new patch version. Do not drop Windows from the matrix
58
+ to make a tag publishable.
59
+
60
+ Before the first PyPI upload, add a pending publisher at
61
+ https://pypi.org/manage/account/publishing/ :
62
+
63
+ - PyPI project name: `jotline`
64
+ - Owner: `CaulShiver`
65
+ - Repository: `jotline`
66
+ - Workflow name: `release.yml`
67
+ - Environment name: `pypi`
68
+
69
+ The GitHub Release with assets is the install path that does not wait on that
70
+ one-time PyPI click. After it succeeds, `uv tool install jotline` works on
71
+ Linux, macOS, and Windows.
jotline-0.9.6/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CaulShiver
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.