Update projektu
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
---
|
||||
name: bookmark
|
||||
description: Manage a personal reading list. Use when the user wants to save, list, mark as read, or remove article URLs for later reading. Triggers on "bookmark", "save URL", "read later", "reading list", "bookmarks".
|
||||
description: >
|
||||
Use when the user wants to save a URL (with or without additional content)
|
||||
to read later or search in. Triggers on "bookmark", "save URL".
|
||||
---
|
||||
|
||||
# Bookmark
|
||||
@@ -10,6 +12,7 @@ Manage a personal reading list stored in SQLite (`db/bookmark.sqlite`).
|
||||
## Commands
|
||||
|
||||
All commands run via:
|
||||
|
||||
```bash
|
||||
/home/nanobot/.local/bin/uv run /home/nanobot/.nanobot/workspace/skills/bookmark/scripts/bookmark.py <command> [args]
|
||||
```
|
||||
@@ -21,14 +24,47 @@ bookmark.py add <url> "<description>" [--tags tag1,tag2]
|
||||
```
|
||||
|
||||
- `url` — the article URL
|
||||
- `description` — short human-readable description (required)
|
||||
- `description` — short human-readable description (required). If the user did not give one, generate a short (~1 sentence) description yourself — from the article text if you have it, otherwise from the URL.
|
||||
- `--tags` — optional comma-separated tags
|
||||
- `--content-file <path>` — optional; path to the cleaned article markdown to archive. `-` reads it from stdin. See "Saving an article's full text" below.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
bookmark.py add "https://example.com/rust-async" "Async Rust patterns" --tags rust,async
|
||||
```
|
||||
|
||||
### Saving an article's full text
|
||||
|
||||
When the user pastes a **large block of text** together with a URL (typically a whole page selected with Ctrl+A/Ctrl+C), treat that text as the **full article to archive**, not as the description. Pick the path by what the pasted content looks like:
|
||||
|
||||
**If the pasted content is raw HTML** (you see `<html>`, `<div>`, `<p>` tags, etc.), do **not** convert it yourself — pipe it through the `html_to_markdown.py` helper (it uses trafilatura to strip boilerplate and emit clean markdown) straight into `add`, so the converted text never passes through your context:
|
||||
|
||||
```bash
|
||||
/home/nanobot/.local/bin/uv run /home/nanobot/.nanobot/workspace/skills/bookmark/scripts/html_to_markdown.py <<'HTML' \
|
||||
| /home/nanobot/.local/bin/uv run /home/nanobot/.nanobot/workspace/skills/bookmark/scripts/bookmark.py add "<url>" "<description>" [--tags a,b] --content-file -
|
||||
<raw html here>
|
||||
HTML
|
||||
```
|
||||
|
||||
If `add` does **not** report "article content stored" (trafilatura extracted nothing → empty content), fall back to cleaning the text yourself and storing it as below.
|
||||
|
||||
**If the pasted content is plain text or already markdown**, store it directly with `--content-file -` via a heredoc (one call, no shell-escaping of the body). Only clean it yourself **if you see obvious boilerplate** (copied menus, "Share"/"Tweet", cookie banners, footers) — otherwise store it as-is:
|
||||
|
||||
```bash
|
||||
/home/nanobot/.local/bin/uv run /home/nanobot/.nanobot/workspace/skills/bookmark/scripts/bookmark.py \
|
||||
add "<url>" "<description>" [--tags a,b] --content-file - <<'ARTICLE'
|
||||
<article text / markdown here>
|
||||
ARTICLE
|
||||
```
|
||||
|
||||
In both cases:
|
||||
|
||||
- **Generate a description** (~1 sentence) from the article, unless the user gave one.
|
||||
- **Confirm and echo.** After saving, tell the user it was stored and quote a short **verbatim** slice of what was archived (the title and first line or two, exactly as written) — not a re-summary — so they can see it worked.
|
||||
|
||||
**URL without pasted text:** try to fetch the article yourself via the `web` tool (Jina Reader returns clean markdown), then store it the same way. If the page is behind a **paywall** or the fetched text is **garbage/incomplete**, do **not** store that text (never fabricate the article body) — instead **ask the user to copy the whole article (Ctrl+A/Ctrl+C) and paste it**, briefly saying why (paywall / the fetched text looks incomplete). If they paste it, follow the paths above. If they decline or don't reply, save the bookmark without content and mark it `⚠ paywall/incomplete`.
|
||||
|
||||
### List unread bookmarks
|
||||
|
||||
```bash
|
||||
@@ -41,7 +77,7 @@ Shows display ID, URL, tags, description, and date added for each unread bookmar
|
||||
|
||||
The `#1`, `#2`, … shown by `list` and `history` are **display IDs** — sequential positions, computed on the fly, never the internal DB id. They renumber whenever the set changes, so run `list`/`history` first if unsure.
|
||||
|
||||
- `read <n>` and `show <n>` take the display ID from **`list`** (the unread set).
|
||||
- `read <n>`, `show <n>`, `content <n>`, and `delete <n>` take the display ID from **`list`** (the unread set).
|
||||
- `unread <n>` takes the display ID from **`history`** (the read set).
|
||||
|
||||
A freshly added bookmark is always display `#1` in `list` (newest first).
|
||||
@@ -68,7 +104,25 @@ bookmark.py unread <display-id>
|
||||
bookmark.py show <display-id>
|
||||
```
|
||||
|
||||
`<display-id>` is the number from `list`. Shows full URL, description, tags, status, and dates. Does **not** change any state.
|
||||
`<display-id>` is the number from `list`. Shows full URL, description, tags, status, and dates. A `📄` marker means an archived article body is stored (read it with `content`). Does **not** change any state.
|
||||
|
||||
### Read stored article content
|
||||
|
||||
```bash
|
||||
bookmark.py content <display-id>
|
||||
```
|
||||
|
||||
`<display-id>` is the number from `list`. Prints the archived article markdown to stdout — render it for the user. If no full text was stored for that bookmark, it says so. Does **not** change any state.
|
||||
|
||||
### Delete a bookmark
|
||||
|
||||
```bash
|
||||
bookmark.py delete <display-id>
|
||||
```
|
||||
|
||||
`<display-id>` is the number from `list` (the unread set). Soft delete: the bookmark drops out of `list`/`history` but the row stays in the DB (recoverable by hand if ever needed). There is no `restore` command.
|
||||
|
||||
**Always confirm before deleting.** Display IDs renumber whenever the set changes, so a stale number can point at the wrong bookmark. First run `list`/`show`, tell the user exactly which bookmark you are about to delete (URL + description), and **wait for their explicit confirmation** — only then run `delete`. To delete a bookmark that is already read, `unread` it first (delete works on the unread set only).
|
||||
|
||||
### List read bookmarks (history)
|
||||
|
||||
@@ -86,17 +140,27 @@ When presenting bookmark lists or details to the user, **always use markdown lin
|
||||
#3 [hackaday.com](https://hackaday.com/2026/06/02/linux-fu-taming-strace/) [linux, strace] — lepší strace
|
||||
```
|
||||
|
||||
Format: `#<display-id> [<domain>](<url>) [<tags>] — <description>`
|
||||
Format: `#<display-id> [<domain>](<url>) — <description> [<tags>]`
|
||||
|
||||
- Domain is clickable, pointing to the full URL
|
||||
- Tags in brackets, comma-separated
|
||||
- Description after em-dash
|
||||
- Description after em-dash (most important, always shown)
|
||||
- Tags in brackets, comma-separated (secondary, after description)
|
||||
- A `📄` in `list`/`history`/`show` marks a bookmark with an archived article body — offer to open it with `content <display-id>`
|
||||
- **Never** strip URLs from the output or replace them with plain-text summaries
|
||||
|
||||
## Workflow
|
||||
|
||||
1. User shares a URL → `add` with description and optional tags
|
||||
2. User wants to see what to read → `list`
|
||||
3. User wants to see details of a bookmark → `show <display-id>` (from `list`)
|
||||
4. User finishes an article → `read <display-id>` (from `list`)
|
||||
5. User wants to revisit → `unread <display-id>` (from `history`) or `history`
|
||||
2. User pastes a URL **and the full article text** → clean it to markdown and `add … --content-file -` (see "Saving an article's full text")
|
||||
3. User wants to see what to read → `list`
|
||||
4. User wants to see details of a bookmark → `show <display-id>` (from `list`)
|
||||
5. User wants to read an archived article → `content <display-id>` (from `list`)
|
||||
6. User finishes an article → `read <display-id>` (from `list`)
|
||||
7. User wants to revisit → `unread <display-id>` (from `history`) or `history`
|
||||
8. User wants to remove one (e.g. accidental duplicate) → confirm, then `delete <display-id>` (from `list`)
|
||||
|
||||
## Known limitations
|
||||
|
||||
- No `edit`/`update` command — to change a description or tags, delete and re-add
|
||||
- `delete` is soft-delete only (row stays in DB); no `restore` command
|
||||
- Sites behind Cloudflare bot protection (PCTuning.cz, vtm.zive.cz, zive.cz) cannot be auto-fetched; ask user to paste full HTML manually
|
||||
|
||||
Reference in New Issue
Block a user